pygeoinf package¶
Subpackages¶
- pygeoinf.checks package
- pygeoinf.data_assimilation package
- Subpackages
- Submodules
- pygeoinf.data_assimilation.core module
AssimilationEngineBayesianAssimilationProblemEnsembleKalmanFilterGaussianLikelihoodLinearGaussianLikelihoodLinearKalmanFilterProbabilityGriddisplay_animation_html()get_gaussian_pdf()get_independent_gaussian_pdf()plot_1d_slice()plot_ensemble_scatter()plot_gaussian_ellipsoid()plot_grid_marginal()plot_kf_step()plot_tracker_1d()solve_ensemble()solve_trajectory()wrap_angle()
- Module contents
AssimilationEngineBayesianAssimilationProblemEnsembleKalmanFilterGaussianLikelihoodLinearGaussianLikelihoodLinearKalmanFilterProbabilityGriddisplay_animation_html()get_gaussian_pdf()get_independent_gaussian_pdf()plot_1d_slice()plot_ensemble_scatter()plot_gaussian_ellipsoid()plot_grid_marginal()plot_kf_step()plot_tracker_1d()solve_ensemble()solve_trajectory()wrap_angle()
- pygeoinf.symmetric_space package
- Submodules
- pygeoinf.symmetric_space.circle module
LebesgueLebesgue.degree_multiplicity()Lebesgue.degree_transfer_operator()Lebesgue.fft_factorLebesgue.from_coefficients()Lebesgue.from_components()Lebesgue.from_covariance()Lebesgue.from_heat_kernel_prior()Lebesgue.from_sobolev_kernel_prior()Lebesgue.gaussian_curvatureLebesgue.geodesic_distance()Lebesgue.geodesic_quadrature()Lebesgue.index_to_integer()Lebesgue.integer_to_index()Lebesgue.invariant_covariance_function()Lebesgue.inverse_fft_factorLebesgue.is_element()Lebesgue.kmaxLebesgue.laplacian_eigenvalue()Lebesgue.laplacian_eigenvector_squared_norm()Lebesgue.laplacian_eigenvectors_at_point()Lebesgue.point_spacingLebesgue.points()Lebesgue.project_function()Lebesgue.radiusLebesgue.random_point()Lebesgue.representative_index()Lebesgue.to_coefficients()Lebesgue.to_components()Lebesgue.vector_multiply()Lebesgue.vector_sqrt()Lebesgue.with_degree()
SobolevSobolev.angles()Sobolev.derivative_operatorSobolev.fft_factorSobolev.from_coefficients()Sobolev.from_covariance()Sobolev.from_heat_kernel_prior()Sobolev.from_sobolev_kernel_prior()Sobolev.from_sobolev_parameters()Sobolev.inverse_fft_factorSobolev.kmaxSobolev.point_spacingSobolev.points()Sobolev.project_function()Sobolev.radiusSobolev.to_coefficients()Sobolev.with_degree()Sobolev.with_order()
plot()plot_error_bounds()
- pygeoinf.symmetric_space.line module
LebesgueLebesgue.aLebesgue.angle_to_point()Lebesgue.bLebesgue.cLebesgue.circle_spaceLebesgue.degree_multiplicity()Lebesgue.degree_transfer_operator()Lebesgue.from_coefficients()Lebesgue.from_components()Lebesgue.from_covariance()Lebesgue.from_heat_kernel_prior()Lebesgue.from_sobolev_kernel_prior()Lebesgue.gaussian_curvatureLebesgue.geodesic_distance()Lebesgue.geodesic_quadrature()Lebesgue.index_to_integer()Lebesgue.integer_to_index()Lebesgue.invariant_covariance_function()Lebesgue.is_element()Lebesgue.kmaxLebesgue.laplacian_eigenvalue()Lebesgue.laplacian_eigenvector_squared_norm()Lebesgue.laplacian_eigenvectors_at_point()Lebesgue.point_to_angle()Lebesgue.points()Lebesgue.project_function()Lebesgue.random_point()Lebesgue.representative_index()Lebesgue.to_coefficients()Lebesgue.to_components()Lebesgue.vector_multiply()Lebesgue.vector_sqrt()Lebesgue.with_degree()
SobolevSobolev.aSobolev.angle_to_point()Sobolev.bSobolev.cSobolev.circle_spaceSobolev.derivative_operatorSobolev.from_coefficients()Sobolev.from_covariance()Sobolev.from_heat_kernel_prior()Sobolev.from_sobolev_kernel_prior()Sobolev.from_sobolev_parameters()Sobolev.kmaxSobolev.point_to_angle()Sobolev.points()Sobolev.project_function()Sobolev.to_coefficients()Sobolev.with_degree()Sobolev.with_order()
plot()plot_error_bounds()
- pygeoinf.symmetric_space.plane module
LebesgueLebesgue.angle_to_point()Lebesgue.angle_to_point_x()Lebesgue.angle_to_point_y()Lebesgue.bounds_xLebesgue.bounds_yLebesgue.degree_multiplicity()Lebesgue.degree_transfer_operator()Lebesgue.estimate_truncation_degree()Lebesgue.from_coefficient_operator()Lebesgue.from_coefficients()Lebesgue.from_components()Lebesgue.from_covariance()Lebesgue.from_heat_kernel_prior()Lebesgue.from_sobolev_kernel_prior()Lebesgue.gaussian_curvatureLebesgue.geodesic_distance()Lebesgue.geodesic_quadrature()Lebesgue.index_to_integer()Lebesgue.integer_to_index()Lebesgue.invariant_covariance_function()Lebesgue.is_element()Lebesgue.kmaxLebesgue.laplacian_eigenvalue()Lebesgue.laplacian_eigenvector_squared_norm()Lebesgue.laplacian_eigenvectors_at_point()Lebesgue.point_to_angle()Lebesgue.points()Lebesgue.project_function()Lebesgue.random_point()Lebesgue.representative_index()Lebesgue.spectral_projection_operator()Lebesgue.to_coefficient_operator()Lebesgue.to_coefficients()Lebesgue.to_components()Lebesgue.torus_spaceLebesgue.vector_multiply()Lebesgue.vector_sqrt()Lebesgue.wavevector_indices()Lebesgue.with_degree()
SobolevSobolev.bounds_xSobolev.bounds_ySobolev.estimate_truncation_degree()Sobolev.from_coefficient_operator()Sobolev.from_covariance()Sobolev.from_heat_kernel_prior()Sobolev.from_sobolev_kernel_prior()Sobolev.from_sobolev_parameters()Sobolev.kmaxSobolev.points()Sobolev.project_function()Sobolev.spectral_projection_operator()Sobolev.to_coefficient_operator()Sobolev.torus_spaceSobolev.with_degree()Sobolev.with_order()
plot()plot_geodesic()plot_geodesic_network()plot_points()
- pygeoinf.symmetric_space.sphere module
LebesgueLebesgue.ax()Lebesgue.axpy()Lebesgue.csphaseLebesgue.degree_multiplicity()Lebesgue.degree_transfer_operator()Lebesgue.domain_mask()Lebesgue.extendLebesgue.from_coefficient_operator()Lebesgue.from_coefficients()Lebesgue.from_components()Lebesgue.from_covariance()Lebesgue.from_heat_kernel_prior()Lebesgue.from_sobolev_kernel_prior()Lebesgue.gaussian_curvatureLebesgue.geodesic_ball_integral()Lebesgue.geodesic_ball_quadrature()Lebesgue.geodesic_distance()Lebesgue.geodesic_quadrature()Lebesgue.gridLebesgue.grid_typeLebesgue.index_to_integer()Lebesgue.integer_to_index()Lebesgue.invariant_covariance_function()Lebesgue.iris_stations()Lebesgue.is_element()Lebesgue.laplacian_eigenvalue()Lebesgue.laplacian_eigenvector_squared_norm()Lebesgue.laplacian_eigenvectors_at_point()Lebesgue.lmaxLebesgue.normalizationLebesgue.pairs_within_distance()Lebesgue.project_function()Lebesgue.radiusLebesgue.random_domain_points()Lebesgue.random_earthquakes()Lebesgue.random_point()Lebesgue.representative_index()Lebesgue.sample_power_measure()Lebesgue.samplingLebesgue.spherical_cap_average()Lebesgue.spherical_cap_integral()Lebesgue.to_coefficient_operator()Lebesgue.to_coefficients()Lebesgue.to_components()Lebesgue.vector_multiply()Lebesgue.vector_sqrt()Lebesgue.with_degree()
SobolevSobolev.ax()Sobolev.axpy()Sobolev.csphaseSobolev.domain_mask()Sobolev.extendSobolev.from_coefficient_operator()Sobolev.from_coefficients()Sobolev.from_covariance()Sobolev.from_heat_kernel_prior()Sobolev.from_sobolev_kernel_prior()Sobolev.from_sobolev_parameters()Sobolev.gridSobolev.grid_typeSobolev.iris_stations()Sobolev.lmaxSobolev.normalizationSobolev.path_average_operator()Sobolev.point_evaluation_operator()Sobolev.project_function()Sobolev.radiusSobolev.random_domain_points()Sobolev.random_earthquakes()Sobolev.sample_power_measure()Sobolev.samplingSobolev.to_coefficient_operator()Sobolev.to_coefficients()Sobolev.with_degree()Sobolev.with_order()
create_map_figure()plot()plot_geodesic()plot_geodesic_network()plot_points()
- pygeoinf.symmetric_space.symmetric_space module
AbstractSymmetricLebesgueSpaceInvariantGaussianMeasureInvariantGaussianMeasure.affine_mapping()InvariantGaussianMeasure.from_function()InvariantGaussianMeasure.from_index_function()InvariantGaussianMeasure.kl_divergence()InvariantGaussianMeasure.rescale_norm_variance()InvariantGaussianMeasure.spectral_variancesInvariantGaussianMeasure.zero_expectation()
InvariantLinearAutomorphismSymmetricHilbertSpaceSymmetricHilbertSpace.cluster_points()SymmetricHilbertSpace.degreeSymmetricHilbertSpace.degree_multiplicity()SymmetricHilbertSpace.degree_transfer_operator()SymmetricHilbertSpace.dimSymmetricHilbertSpace.estimate_truncation_degree()SymmetricHilbertSpace.from_dual()SymmetricHilbertSpace.gaussian_curvatureSymmetricHilbertSpace.geodesic_ball_average()SymmetricHilbertSpace.geodesic_ball_integral()SymmetricHilbertSpace.geodesic_ball_quadrature()SymmetricHilbertSpace.geodesic_distance()SymmetricHilbertSpace.geodesic_quadrature()SymmetricHilbertSpace.heat_kernel()SymmetricHilbertSpace.heat_kernel_gaussian_measure()SymmetricHilbertSpace.identity_operator()SymmetricHilbertSpace.index_to_integer()SymmetricHilbertSpace.indicesSymmetricHilbertSpace.integer_to_index()SymmetricHilbertSpace.invariant_automorphism()SymmetricHilbertSpace.invariant_covariance_function()SymmetricHilbertSpace.invariant_gaussian_measure()SymmetricHilbertSpace.l2_products_operator()SymmetricHilbertSpace.laplacianSymmetricHilbertSpace.laplacian_eigenvalue()SymmetricHilbertSpace.laplacian_eigenvector_squared_norm()SymmetricHilbertSpace.laplacian_eigenvectors_at_point()SymmetricHilbertSpace.norm_scaled_heat_kernel_gaussian_measure()SymmetricHilbertSpace.norm_scaled_invariant_gaussian_measure()SymmetricHilbertSpace.norm_scaled_sobolev_kernel_gaussian_measure()SymmetricHilbertSpace.orthonormalSymmetricHilbertSpace.pairs_within_distance()SymmetricHilbertSpace.project_function()SymmetricHilbertSpace.random_point()SymmetricHilbertSpace.random_points()SymmetricHilbertSpace.representative_index()SymmetricHilbertSpace.sobolev_kernel()SymmetricHilbertSpace.sobolev_kernel_gaussian_measure()SymmetricHilbertSpace.spatial_dimensionSymmetricHilbertSpace.squared_normsSymmetricHilbertSpace.to_dual()SymmetricHilbertSpace.with_degree()SymmetricHilbertSpace.zero_operator()
SymmetricSobolevSpaceSymmetricSobolevSpace.cluster_points()SymmetricSobolevSpace.degree_multiplicity()SymmetricSobolevSpace.degree_transfer_operator()SymmetricSobolevSpace.dirac()SymmetricSobolevSpace.dirac_representation()SymmetricSobolevSpace.distance_localized_preconditioner()SymmetricSobolevSpace.flexural_operator()SymmetricSobolevSpace.gaussian_curvatureSymmetricSobolevSpace.geodesic_ball_integral()SymmetricSobolevSpace.geodesic_ball_quadrature()SymmetricSobolevSpace.geodesic_distance()SymmetricSobolevSpace.geodesic_integral()SymmetricSobolevSpace.geodesic_integral_representation()SymmetricSobolevSpace.geodesic_quadrature()SymmetricSobolevSpace.index_to_integer()SymmetricSobolevSpace.integer_to_index()SymmetricSobolevSpace.invariant_covariance_function()SymmetricSobolevSpace.inverse_flexural_operator()SymmetricSobolevSpace.l2_products_operator()SymmetricSobolevSpace.laplacian_eigenvalue()SymmetricSobolevSpace.laplacian_eigenvector_squared_norm()SymmetricSobolevSpace.laplacian_eigenvectors_at_point()SymmetricSobolevSpace.orderSymmetricSobolevSpace.order_inclusion_operator()SymmetricSobolevSpace.pairs_within_distance()SymmetricSobolevSpace.path_average_operator()SymmetricSobolevSpace.point_evaluation_operator()SymmetricSobolevSpace.point_value_scaled_heat_kernel_gaussian_measure()SymmetricSobolevSpace.point_value_scaled_invariant_gaussian_measure()SymmetricSobolevSpace.point_value_scaled_sobolev_kernel_gaussian_measure()SymmetricSobolevSpace.random_point()SymmetricSobolevSpace.random_source_receiver_paths()SymmetricSobolevSpace.representative_index()SymmetricSobolevSpace.safeSymmetricSobolevSpace.scaleSymmetricSobolevSpace.sobolev_function()SymmetricSobolevSpace.with_order()
- pygeoinf.symmetric_space.torus module
LebesgueLebesgue.degree_multiplicity()Lebesgue.degree_transfer_operator()Lebesgue.estimate_truncation_degree()Lebesgue.fft_factorLebesgue.from_coefficient_operator()Lebesgue.from_coefficients()Lebesgue.from_components()Lebesgue.from_covariance()Lebesgue.from_heat_kernel_prior()Lebesgue.from_sobolev_kernel_prior()Lebesgue.gaussian_curvatureLebesgue.geodesic_distance()Lebesgue.geodesic_quadrature()Lebesgue.index_to_integer()Lebesgue.inner_product()Lebesgue.integer_to_index()Lebesgue.invariant_covariance_function()Lebesgue.inverse_fft_factorLebesgue.is_element()Lebesgue.kmaxLebesgue.laplacian_eigenvalue()Lebesgue.laplacian_eigenvector_squared_norm()Lebesgue.laplacian_eigenvectors_at_point()Lebesgue.norm()Lebesgue.points()Lebesgue.project_function()Lebesgue.radius_xLebesgue.radius_yLebesgue.random_point()Lebesgue.representative_index()Lebesgue.spectral_projection_operator()Lebesgue.to_coefficient_operator()Lebesgue.to_coefficients()Lebesgue.to_components()Lebesgue.vector_multiply()Lebesgue.vector_sqrt()Lebesgue.wavevector_indices()Lebesgue.with_degree()Lebesgue.zero
SobolevSobolev.estimate_truncation_degree()Sobolev.fft_factorSobolev.from_coefficient_operator()Sobolev.from_coefficients()Sobolev.from_components()Sobolev.from_covariance()Sobolev.from_heat_kernel_prior()Sobolev.from_sobolev_kernel_prior()Sobolev.from_sobolev_parameters()Sobolev.inner_product()Sobolev.inverse_fft_factorSobolev.is_element()Sobolev.kmaxSobolev.norm()Sobolev.points()Sobolev.project_function()Sobolev.radius_xSobolev.radius_ySobolev.spectral_projection_operator()Sobolev.to_coefficient_operator()Sobolev.to_coefficients()Sobolev.to_components()Sobolev.wavevector_indices()Sobolev.with_degree()Sobolev.with_order()
plot()plot_geodesic()plot_geodesic_network()plot_points()
- Module contents
AbstractSymmetricLebesgueSpaceInvariantGaussianMeasureInvariantGaussianMeasure.affine_mapping()InvariantGaussianMeasure.from_function()InvariantGaussianMeasure.from_index_function()InvariantGaussianMeasure.kl_divergence()InvariantGaussianMeasure.rescale_norm_variance()InvariantGaussianMeasure.spectral_variancesInvariantGaussianMeasure.zero_expectation()
InvariantLinearAutomorphismSymmetricHilbertSpaceSymmetricHilbertSpace.cluster_points()SymmetricHilbertSpace.degreeSymmetricHilbertSpace.degree_multiplicity()SymmetricHilbertSpace.degree_transfer_operator()SymmetricHilbertSpace.dimSymmetricHilbertSpace.estimate_truncation_degree()SymmetricHilbertSpace.from_dual()SymmetricHilbertSpace.gaussian_curvatureSymmetricHilbertSpace.geodesic_ball_average()SymmetricHilbertSpace.geodesic_ball_integral()SymmetricHilbertSpace.geodesic_ball_quadrature()SymmetricHilbertSpace.geodesic_distance()SymmetricHilbertSpace.geodesic_quadrature()SymmetricHilbertSpace.heat_kernel()SymmetricHilbertSpace.heat_kernel_gaussian_measure()SymmetricHilbertSpace.identity_operator()SymmetricHilbertSpace.index_to_integer()SymmetricHilbertSpace.indicesSymmetricHilbertSpace.integer_to_index()SymmetricHilbertSpace.invariant_automorphism()SymmetricHilbertSpace.invariant_covariance_function()SymmetricHilbertSpace.invariant_gaussian_measure()SymmetricHilbertSpace.l2_products_operator()SymmetricHilbertSpace.laplacianSymmetricHilbertSpace.laplacian_eigenvalue()SymmetricHilbertSpace.laplacian_eigenvector_squared_norm()SymmetricHilbertSpace.laplacian_eigenvectors_at_point()SymmetricHilbertSpace.norm_scaled_heat_kernel_gaussian_measure()SymmetricHilbertSpace.norm_scaled_invariant_gaussian_measure()SymmetricHilbertSpace.norm_scaled_sobolev_kernel_gaussian_measure()SymmetricHilbertSpace.orthonormalSymmetricHilbertSpace.pairs_within_distance()SymmetricHilbertSpace.project_function()SymmetricHilbertSpace.random_point()SymmetricHilbertSpace.random_points()SymmetricHilbertSpace.representative_index()SymmetricHilbertSpace.sobolev_kernel()SymmetricHilbertSpace.sobolev_kernel_gaussian_measure()SymmetricHilbertSpace.spatial_dimensionSymmetricHilbertSpace.squared_normsSymmetricHilbertSpace.to_dual()SymmetricHilbertSpace.with_degree()SymmetricHilbertSpace.zero_operator()
SymmetricSobolevSpaceSymmetricSobolevSpace.cluster_points()SymmetricSobolevSpace.degree_multiplicity()SymmetricSobolevSpace.degree_transfer_operator()SymmetricSobolevSpace.dirac()SymmetricSobolevSpace.dirac_representation()SymmetricSobolevSpace.distance_localized_preconditioner()SymmetricSobolevSpace.flexural_operator()SymmetricSobolevSpace.gaussian_curvatureSymmetricSobolevSpace.geodesic_ball_integral()SymmetricSobolevSpace.geodesic_ball_quadrature()SymmetricSobolevSpace.geodesic_distance()SymmetricSobolevSpace.geodesic_integral()SymmetricSobolevSpace.geodesic_integral_representation()SymmetricSobolevSpace.geodesic_quadrature()SymmetricSobolevSpace.index_to_integer()SymmetricSobolevSpace.integer_to_index()SymmetricSobolevSpace.invariant_covariance_function()SymmetricSobolevSpace.inverse_flexural_operator()SymmetricSobolevSpace.l2_products_operator()SymmetricSobolevSpace.laplacian_eigenvalue()SymmetricSobolevSpace.laplacian_eigenvector_squared_norm()SymmetricSobolevSpace.laplacian_eigenvectors_at_point()SymmetricSobolevSpace.orderSymmetricSobolevSpace.order_inclusion_operator()SymmetricSobolevSpace.pairs_within_distance()SymmetricSobolevSpace.path_average_operator()SymmetricSobolevSpace.point_evaluation_operator()SymmetricSobolevSpace.point_value_scaled_heat_kernel_gaussian_measure()SymmetricSobolevSpace.point_value_scaled_invariant_gaussian_measure()SymmetricSobolevSpace.point_value_scaled_sobolev_kernel_gaussian_measure()SymmetricSobolevSpace.random_point()SymmetricSobolevSpace.random_source_receiver_paths()SymmetricSobolevSpace.representative_index()SymmetricSobolevSpace.safeSymmetricSobolevSpace.scaleSymmetricSobolevSpace.sobolev_function()SymmetricSobolevSpace.with_order()
Submodules¶
pygeoinf.affine_operators module¶
Provides the AffineOperator class for affine mappings between Hilbert spaces.
- class pygeoinf.affine_operators.AffineOperator(linear_part: LinearOperator, translation: Any)[source]¶
Bases:
AffineOperatorAxiomChecks,NonLinearOperatorRepresents an affine transformation between two Hilbert spaces.
An affine operator is a mapping F(x) = A(x) + b, where ‘A’ is a bounded linear operator and ‘b’ is a fixed translation vector in the codomain.
- property linear_part: LinearOperator¶
The underlying linear mapping ‘A’.
- property translation_part: Any¶
The translation vector ‘b’.
pygeoinf.auxiliary module¶
- pygeoinf.auxiliary.empirical_data_error_measure(model_measure, forward_operator, n_samples=10, scale_factor=1.0)[source]¶
Generate an empirical data error measure based on samples from a measure on the model space. Useful for when you need to define a reasonable data error measure for synthetic testing, and need the covariance matrix to be easily accessible.
- Parameters:
model_measure – The measure on the model space used as a basis for the error measure (e.g., the model prior measure)
forward_operator – Linear operator mapping from model space to data space (e.g., operator B)
n_samples – Number of samples to generate for computing statistics (default: 10)
scale_factor – Scaling factor for the standard deviations (default: 1.0)
- Returns:
Data error measure with empirically determined covariance
- Return type:
inf.GaussianMeasure
pygeoinf.backus_gilbert module¶
Backus-Gilbert style dual master cost function.
Provides DualMasterCostFunction — the oracle $varphi(lambda; q)$
minimised over $lambda$ in convex Backus-Gilbert / dual-level-set inversion.
- class pygeoinf.backus_gilbert.BackusInference(forward_problem: LinearForwardProblem, property_operator: LinearOperator, prior_norm_bound: float, significance_level: float, /, *, constraint_solver=None, constraint_preconditioner=None)[source]¶
Bases:
LinearInferenceSolves a linear inference problem using Backus’ method.
- property critical_chi_squared: float¶
Returns the critical Chi squared.
- property prior_norm_bound: float¶
Returns the prior norm bound.
- property significance_level: float¶
Returns the significance level.
- test_data_compatibility(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) bool[source]¶
Returns true if there exists a model that is compatible with both the data and the norm bound.
- class pygeoinf.backus_gilbert.DualMasterCostFunction(data_space: HilbertSpace, property_space: HilbertSpace, model_space: HilbertSpace, G: LinearOperator, T: LinearOperator, model_prior_support: SupportFunction, data_error_support: SupportFunction, observed_data: Vector, q_direction: Vector)[source]¶
Bases:
NonLinearFormCost function for the master dual equation (Hilbert form):
h_U(q) = inf_{λ ∈ D}
{ (λ, d̃)_D + σ_B(T* q - G* λ) + σ_V(-λ) }
i.e.
φ(λ; q) = (λ, d̃)_D + σ_B(T* q - G* λ) + σ_V(-λ)
- where:
σ_B is the support function of the model prior convex set B ⊆ M
σ_V is the support function of the data error convex set V ⊆ D
Minimizing φ(λ; q) over λ ∈ D yields h_U(q).
- property direction: Vector¶
Current property direction q ∈ P.
- property observed_data: Vector¶
Observed data vector d̃ ∈ D.
- value_and_subgradient(lam: Vector) tuple[float, Vector][source]¶
Compute the value and a subgradient of $varphi(lambda; q)$ in one pass.
Shares the computation of $G^* lambda$ and the support points $v$, $w$ between the value and subgradient evaluations, avoiding redundant work.
The dual master cost function is
\[\varphi(\lambda; q) = \langle \lambda, \tilde{d} \rangle_D + \sigma_B(T^* q - G^* \lambda) + \sigma_V(-\lambda)\]and a subgradient at $lambda$ is
\[g = \tilde{d} - G v - w,\]where $v in partial sigma_B(T^* q - G^* lambda)$ and $w in partial sigma_V(-lambda)$.
- Parameters:
lam – Dual variable $lambda in D$.
- Returns:
A tuple
(f, g)wheref = φ(λ; q)is the scalar value andg ∈ ∂φ(λ; q)is a subgradient vector in $D$.
pygeoinf.config module¶
pygeoinf/config.py Shared configuration constants for the pygeoinf library.
pygeoinf.convex_analysis module¶
- class pygeoinf.convex_analysis.BallSupportFunction(primal_domain: HilbertSpace, center: Vector, radius: float)[source]¶
Bases:
SupportFunctionSupport function of a closed ball B(c, r) = {x : ||x - c|| ≤ r}:
h(q) = ⟨q, c⟩ + r ||q||
- support_point(q: Vector) 'Vector' | None[source]¶
Return x* = c + r * (q / ||q||) achieving the supremum.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))computing $|q|$ once.Both $h(q) = langle q, c rangle + r|q|$ and $x^*(q) = c + r , q / |q|$ depend on $|q|$, so computing it once halves the number of norm evaluations compared to the default two-call fallback.
- Parameters:
q – A vector in the primal domain $H$.
- Returns:
(value, point)wherevalue$= h(q)$ andpoint$= x^*(q)$, or the center $c$ when $q approx 0$.
- class pygeoinf.convex_analysis.CallableSupportFunction(primal_domain: HilbertSpace, fn: Callable[[Vector], float], support_point_fn: Callable[[Vector], Vector] | None = None)[source]¶
Bases:
SupportFunctionSupport function defined by a user-provided callable.
Wraps an arbitrary callable $q mapsto h(q)$ as a
SupportFunction. Optionally accepts a second callable $q mapsto x^*(q)$ that returns the support point (subgradient of $h$ at $q$).- Parameters:
primal_domain – The Hilbert space $H$ on which $h$ is defined.
fn – A callable
fn(q) -> floatcomputing the support value $h(q)$.support_point_fn – An optional callable
support_point_fn(q) -> Vectorreturning $x^*(q) in argmax_{x in C} langle q, x rangle$. When provided,support_point()delegates to it andsubgradient()returns the result. WhenNone,support_point()returnsNoneandsubgradient()raisesNotImplementedError.
Example:
fn = lambda q: float(np.linalg.norm(q)) # L2-ball support sp = lambda q: q / np.linalg.norm(q) # support point h = CallableSupportFunction(space, fn, support_point_fn=sp)
- class pygeoinf.convex_analysis.EllipsoidSupportFunction(primal_domain: HilbertSpace, center: Vector, radius: float, shape_operator: LinearOperator, inverse_operator: LinearOperator | None = None, inverse_sqrt_operator: LinearOperator | None = None)[source]¶
Bases:
SupportFunctionSupport function of an ellipsoid E(c, r, A) defined by:
E = {x : ⟨A(x-c), (x-c)⟩ ≤ r²} with A SPD
- Then:
h(q) = ⟨q, c⟩ + r ||A^{-1/2} q||
- Parameters:
primal_domain – The Hilbert space H.
center – The center c of the ellipsoid.
radius – The radius r.
shape_operator – The SPD operator A.
inverse_operator – A^{-1}. Required for support_point and sufficient for computing h(q) through $sqrt{langle q, A^{-1}qrangle}$.
inverse_sqrt_operator – A^{-1/2}. Optional direct square-root inverse used for computing h(q).
Note
If neither inverse operator is provided, the support function cannot be evaluated. If
inverse_operatoris omitted, support_point returns None.- support_point(q: Vector) 'Vector' | None[source]¶
Return x* = c + r * (A^{-1} q) / ||A^{-1/2} q|| achieving the supremum.
For an ellipsoid E(c, r, A), the extreme point in direction q is found by transforming q through the inverse metric A^{-1} and normalizing.
Returns None if inverse_operator was not provided.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))computing $A^{-1} q$ once.When $A^{-1}$ is available, both the value
\[h(q) = \langle q, c \rangle + r\,\sqrt{\langle q,\, A^{-1} q \rangle}\]and the support point
\[x^*(q) = c + \frac{r}{\sqrt{\langle q, A^{-1} q \rangle}} A^{-1} q\]share the intermediate $A^{-1} q$ and the norm $|A^{-1/2} q| = sqrt{langle q, A^{-1} q rangle}$, so only one operator application is needed instead of two.
When $A^{-1}$ is not available, falls back to calling
self(q)(which uses $A^{-1/2}$) and returnsNonefor the support point, matching the behaviour ofsupport_point().- Parameters:
q – A vector in the primal domain $H$.
- Returns:
(value, point)wherepointisNonewhen $A^{-1}$ was not supplied at construction.
- class pygeoinf.convex_analysis.HalfSpaceSupportFunction(primal_domain: HilbertSpace, normal_vector: Vector, offset: float, inequality_type: str = '<=', *, parallel_rtol: float = 1e-12, parallel_atol: float = 1e-14, return_min_norm_support_point: bool = True)[source]¶
Bases:
NonLinearFormSupport function of a (closed) half-space in a Hilbert space H.
We support two conventions:
(<=) H = { x ∈ H : ⟨a, x⟩ ≤ b } (>=) H = { x ∈ H : ⟨a, x⟩ ≥ b } which is equivalent to { x : ⟨-a, x⟩ ≤ -b }.
- Mathematical facts (extended-real-valued):
For H = {x : ⟨a, x⟩ ≤ b} with a ≠ 0,
- σ_H(q) = sup_{x∈H} ⟨q, x⟩
- = { α b, if q = α a with α ≥ 0,
+∞, otherwise. }
For H = {x : ⟨a, x⟩ ≥ b},
- σ_H(q) = { α b, if q = α a with α ≤ 0,
+∞, otherwise. }
Notes
Half-spaces are unbounded, so σ_H is typically +∞.
This implementation returns float(‘inf’) for unbounded directions.
A support point is not unique when σ_H(q) is finite; the maximizers form the boundary hyperplane ⟨a, x⟩ = b. We optionally return the minimum-norm boundary point as a canonical representative.
- property inequality_type: str¶
- property normal_vector: Vector¶
- property offset: float¶
- support_point(q: Vector) 'Vector' | None[source]¶
Return a canonical maximizer when σ_H(q) is finite.
When finite, the maximizers are all x with ⟨a,x⟩ = b (boundary hyperplane). If return_min_norm_support_point=True, we return the minimum-norm boundary point:
x_min = (b / ||a||^2) a.
Otherwise return None (non-unique support set).
- class pygeoinf.convex_analysis.LinearImageSupportFunction(base: SupportFunction, operator: LinearOperator)[source]¶
Bases:
SupportFunctionSupport function of the linear image $A(C)$ of a convex set $C$.
For a convex set $C subseteq H$ with support function $h_C$ and a bounded linear operator $A: H to K$, the support function of the image $A(C) subseteq K$ is
\[h_{A(C)}(q) = h_C(A^* q), \quad q \in K,\]where $A^*: K to H$ is the Hilbert-space adjoint of $A$.
- Parameters:
base – The support function $h_C$ of the base set $C subseteq H$. Its
primal_domainmust equaloperator.domain.operator – A bounded linear operator $A: H to K$.
operator.domainmust equalbase.primal_domain.
- Raises:
ValueError – If
operator.domaindoes not equalbase.primal_domain.
Note
The
primal_domainof the returned object isoperator.codomain(the space $K$ where the image $A(C)$ lives).Note
Phase 3:
support_point()propagates support points from the base, returning $x_C^*(A^* q)$ when available, orNoneif the base has no support point available.- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the image set $A(C)$ at direction $q in K$.
For the image support function $h_{A(C)}(q) = h_C(A^* q)$, the support point in direction $q$ is obtained by computing the base support point $x_C^*(A^* q)$ and then applying the operator: $x_{A(C)}^*(q) = A(x_C^*(A^* q))$.
- Parameters:
q – A vector in the codomain $K$.
- Returns:
The support point $A(x_C^*(A^* q)) in K$ if available, or
None.
- class pygeoinf.convex_analysis.MinkowskiSumSupportFunction(left: SupportFunction, right: SupportFunction)[source]¶
Bases:
SupportFunctionSupport function of the Minkowski sum $C oplus D$.
For two convex sets $C, D subseteq H$ with support functions $h_C$ and $h_D$ on the same Hilbert space $H$, the support function of their Minkowski sum $C oplus D = {c + d : c in C,, d in D}$ is
\[h_{C \oplus D}(q) = h_C(q) + h_D(q), \quad q \in H.\]- Parameters:
left – Support function $h_C$.
right – Support function $h_D$.
right.primal_domainmust equalleft.primal_domain.
- Raises:
ValueError – If
left.primal_domainandright.primal_domaindiffer.
Note
Phase 3:
support_point()conservatively returns the sum of support points only when both operands have support points available. If either operand has no support point, returnsNone(unavailable).- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the Minkowski sum $C oplus D$ at direction $q$.
If both the left and right operands have support points $x_L^*(q)$ and $x_R^*(q)$ available, return their sum $x_L^*(q) + x_R^*(q)$ (a support point of the sum set). Otherwise return
None(conservative: neither is available or computing the sum is unsafe).- Parameters:
q – A vector in the shared primal space $H$.
- Returns:
The sum of support points $x_L^*(q) + x_R^*(q)$ if both are available, or
None.
- class pygeoinf.convex_analysis.PointSupportFunction(primal_domain: HilbertSpace, point: Vector)[source]¶
Bases:
SupportFunctionSupport function of the singleton set ${p}$.
For a fixed point $p in H$, the support function of the singleton set ${p}$ is
\[h_{\{p\}}(q) = \langle q, p \rangle, \quad q \in H.\]The support point is always $p$ (the unique element of the set), so
subgradient()is available for all query directions.- Parameters:
primal_domain – The Hilbert space $H$ containing the point $p$.
point – The fixed point $p$.
Example:
p = np.array([1.0, 2.0]) h = PointSupportFunction(space, p) h(np.array([3.0, -1.0])) # returns 3*1 + (-1)*2 = 1.0
- class pygeoinf.convex_analysis.ScaledSupportFunction(base: SupportFunction, alpha: float)[source]¶
Bases:
SupportFunctionSupport function of a nonnegatively scaled convex set $alpha C$.
For a convex set $C subseteq H$ with support function $h_C$ and a scalar $alpha geq 0$, the support function of the scaled set is
\[h_{\alpha C}(q) = \alpha\, h_C(q), \quad q \in H.\]When $alpha = 0$ the set $0 cdot C = {0}$ and $h(q) = 0$ for all $q$.
- Parameters:
base – The support function $h_C$.
alpha – A nonnegative scalar.
- Raises:
ValueError – If
alpha < 0.
Note
Phase 3:
support_point()propagates support points by scaling them. For $alpha > 0$: returns $alpha cdot x_C^*(q)$ if available; For $alpha = 0$: returns the zero vector (support point of ${0}$); If base has no support_point, returnsNone.- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the scaled set $alpha C$ at direction $q$.
For $alpha > 0$: Returns $alpha cdot x_C^*(q)$ if the base has a support point. For $alpha = 0$: Returns the zero vector (the unique support point of the singleton ${0}$). If the base has no support point and $alpha > 0$, returns
None.- Parameters:
q – A vector in the primal space $H$.
- Returns:
The scaled support point $alpha cdot x_C^*(q)$, the zero vector for $alpha=0$, or
None.
- class pygeoinf.convex_analysis.SupportFunction(primal_domain: HilbertSpace)[source]¶
Bases:
NonLinearForm,ABCSupport function of a closed convex set S ⊆ H:
h_S(q) = sup_{x ∈ S} ⟨q, x⟩, q ∈ H
In a Hilbert space, we identify H ≅ H* via the Riesz map, so the functional is defined directly on the primal space H.
- The set S is uniquely recovered as:
S = {x : ⟨q, x⟩ ≤ h_S(q) for all q ∈ H}
- classmethod callable(primal_domain: HilbertSpace, mapping: Callable[[Vector], float], support_point: Callable[[Vector], Vector] | None = None) CallableSupportFunction[source]¶
Construct a support function from a user-supplied callable.
- Parameters:
primal_domain – The Hilbert space H.
mapping – A callable
q -> floatthat evaluates $h(q)$.support_point – An optional callable
q -> Vectorreturning $x^*(q) in argmax_{x in C} langle q, x rangle$. When provided,subgradient(q)delegates to it.
- Returns:
A
CallableSupportFunctioninstance.
- image(operator: LinearOperator) LinearImageSupportFunction[source]¶
Return the support function of the linear image $A(C)$.
For a bounded linear operator $A$ with
A.domain == self.primal_domain, returns the support function of the image set $A(C)$, which lives inA.codomain. Its value is $h_{A(C)}(q) = h_C(A^* q)$.- Parameters:
operator – A bounded linear operator $A: H to K$ with
operator.domainequal toself.primal_domain.- Returns:
A
LinearImageSupportFunctiononoperator.codomain.- Raises:
ValueError – If
operator.domain != self.primal_domain.
- classmethod point(primal_domain: HilbertSpace, point: Vector) PointSupportFunction[source]¶
Construct the support function of the singleton set ${p}$.
For a fixed point $p in H$, the support function is $h(q) = langle q, p rangle$.
- Parameters:
primal_domain – The Hilbert space H containing $p$.
point – The fixed point $p$.
- Returns:
A
PointSupportFunctioninstance.
- property primal_domain: HilbertSpace¶
The Hilbert space H in which the underlying convex set lives.
- scale(alpha: float) ScaledSupportFunction[source]¶
Return the support function of the scaled set $alpha C$.
Scaling satisfies $h_{alpha C}(q) = alpha, h_C(q)$ for $alpha geq 0$.
- Parameters:
alpha – A nonnegative scalar.
- Returns:
A
ScaledSupportFunctionon the same space.- Raises:
ValueError – If
alpha < 0.
- support_point(q: Vector) 'Vector' | None[source]¶
Optional: return x*(q) ∈ argmax_{x∈S} ⟨q, x⟩ if available/computable. Default: not provided (returns None). This is the subgradient of h_S at q.
- translate(point: Vector) MinkowskiSumSupportFunction[source]¶
Return the support function of the translated set $C + p$.
Translation by $p in H$ satisfies $h_{C+p}(q) = h_C(q) + langle q, p rangle$.
- Parameters:
point – The translation vector $p in H$ (same space as
primal_domain).- Returns:
A
MinkowskiSumSupportFunctionon the same space.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))sharing intermediate work where possible.For a support function $h_S(q) = sup_{x in S} langle q, x rangle$, the scalar value and the maximiser $x^*(q)$ often share intermediate computations (e.g. a norm or an operator application). This method provides a single entry point so that overriding subclasses can exploit that sharing.
The default implementation simply calls
self(q)andself.support_point(q)separately and is always correct. Concrete subclasses should override this when a fused computation is cheaper.- Parameters:
q – A vector in the primal domain $H$.
- Returns:
A tuple
(value, point)wherevalueis the float $h(q)$, always present;pointis $x^*(q) in argmax_{x in S} langle q, x rangle$ as aVector, orNonewhen a support point is unavailable.
pygeoinf.convex_optimisation module¶
Convex optimisation utilities for non-smooth problems.
This module provides a minimal subgradient descent implementation suitable for learning and experimentation. It assumes the objective is a NonLinearForm that can provide a subgradient oracle via form.subgradient(x).
- class pygeoinf.convex_optimisation.Bundle[source]¶
Bases:
objectCollection of cutting-plane linearisations of a convex function.
A bundle stores a list of
Cutobjects and provides utilities for building the piecewise-linear epigraph model:hat_phi(lambda) = max_j [ f_j + <g_j, lambda - x_j> ]
used by proximal and level bundle methods.
Examples
>>> space = EuclideanSpace(3) >>> bundle = Bundle() >>> bundle.add_cut(Cut(x=np.zeros(3), f=1.0, g=np.ones(3), iteration=0)) >>> len(bundle) 1
- best_point() Vector[source]¶
Return the evaluation point with the lowest recorded function value.
- Returns:
The vector x_j achieving min_j f_j.
- Raises:
ValueError – If the bundle is empty.
- compress(max_size: int) None[source]¶
Discard all but the max_size most recent cuts.
- Parameters:
max_size – Maximum number of cuts to retain. If the bundle already has fewer cuts than max_size, nothing is changed.
- linearization_matrix(stability_center: Vector, domain: HilbertSpace) Tuple[np.ndarray, np.ndarray][source]¶
Build the inequality constraint matrix for the epigraph QP.
- For each cut (x_j, f_j, g_j) the cutting-plane constraint is:
f_j + <g_j, lambda - x_j> <= t
- which is equivalent to:
g_j^T @ lambda - t <= g_j^T @ x_j - f_j
Stacking all cuts gives the system A_ineq @ [lambda; t] <= b where row i is [g_i^T, -1] and b_i = g_i^T @ x_i - f_i.
- Parameters:
stability_center – Current stability/proximal centre (not used to build the constraint data, but kept for API consistency with Phase 2).
domain – The Hilbert space whose
to_componentsconverts vectors to flat numpy arrays.
- Returns:
A tuple
(A_ineq, b_ineq)whereA_ineqhas shape(n_cuts, dim + 1)— columns are [lambda_1, …, lambda_d, t].b_ineqhas shape(n_cuts,).
- Raises:
ValueError – If the bundle is empty.
- lower_bound() float[source]¶
Return a placeholder lower bound (-infinity).
The true lower bound min_lambda hat_phi(lambda) is computed as the master QP/LP objective value by the outer bundle solver (Phase 2–3). This placeholder allows
BundleResultto reportf_lowbefore any master problem has been solved.- Returns:
-np.inf
- class pygeoinf.convex_optimisation.BundleResult(x_best: Vector, f_best: float, f_low: float, gap: float, converged: bool, num_iterations: int, num_serious_steps: int, function_values: List[float], iterates: List['Vector'] | None = None)[source]¶
Bases:
objectResult from a bundle method optimisation run.
- x_best¶
Best primal iterate found (lowest function value).
- Type:
Vector
- f_best¶
Function value at
x_best; upper bound on the optimum.- Type:
float
- f_low¶
Lower bound on the optimum from the cutting-plane model.
- Type:
float
- gap¶
Optimality gap
f_best - f_low(non-negative for a valid lower bound).- Type:
float
- converged¶
Whether the gap tolerance was satisfied.
- Type:
bool
- num_iterations¶
Number of bundle loop iterations (master solves), excluding the initial oracle evaluation before the loop.
- Type:
int
- num_serious_steps¶
Number of serious (descent) steps taken.
- Type:
int
- function_values¶
History of function values at each iteration.
- Type:
List[float]
- iterates¶
Optional history of all iterates (memory intensive).
- Type:
Optional[List[‘Vector’]]
- converged: bool¶
- f_best: float¶
- f_low: float¶
- function_values: List[float]¶
- gap: float¶
- iterates: List['Vector'] | None = None¶
- num_iterations: int¶
- num_serious_steps: int¶
- x_best: Vector¶
- class pygeoinf.convex_optimisation.ChambollePockResult(m: Vector, v: Vector, mu: Vector, primal_dual_gap: float, converged: bool, num_iterations: int)[source]¶
Bases:
objectResult from
ChambollePockSolver.- m¶
Primal variable m* in B (model space).
- Type:
Vector
- v¶
Primal variable v* in V (data space).
- Type:
Vector
- mu¶
Dual variable mu* in D (data space). Approximates the optimal Lagrange multiplier for the equality constraint G @ m + v = d_tilde.
- Type:
Vector
- primal_dual_gap¶
Feasibility residual ||G @ m* + v* - d_tilde|| at termination.
- Type:
float
- converged¶
Trueifprimal_dual_gap < tolerance.- Type:
bool
- num_iterations¶
Number of iterations performed.
- Type:
int
- converged: bool¶
- m: Vector¶
- mu: Vector¶
- num_iterations: int¶
- primal_dual_gap: float¶
- v: Vector¶
- class pygeoinf.convex_optimisation.ChambollePockSolver(B: SupportFunction, V: SupportFunction, G: LinearOperator, d_tilde: Vector, /, *, sigma: float | None = None, tau: float | None = None, theta: float = 1.0, max_iterations: int = 1000, tolerance: float = 1e-06)[source]¶
Bases:
objectSolve the primal feasibility form of the dual master via Chambolle-Pock.
- Solves the constrained maximisation:
- h_U(q) = max_{m in B, v in V} <c, m>
subject to: G @ m + v = d_tilde
where c = T* @ q is the linear objective and the feasible set (B, V, G, d_tilde) is fixed, using the first-order primal-dual algorithm of Chambolle & Pock (2011).
- The saddle-point reformulation (with dual variable mu in D) is:
- min_{m in B, v in V} max_{mu}
<G @ m + v - d_tilde, mu> - <c, m>
with operator K = [G; I_D] : M x D -> D.
Convergence rate: O(1/N) in the primal-dual gap when tau * sigma * ||K||^2 <= 1 (where ||K||^2 <= ||G||^2 + 1).
This is particularly efficient when the objective c = T* @ q changes while the feasible set (B, V, G, d_tilde) remains fixed.
- Parameters:
B – Support function for the model prior (B subset of M).
V – Support function for the data error set (V subset of D).
G – Forward operator G: M -> D.
d_tilde – Observed data vector d_tilde in D.
sigma – Dual step size. If
None, auto-selected from power iteration.tau – Primal step size. If
None, auto-selected from power iteration.theta – Over-relaxation parameter (default 1.0).
max_iterations – Maximum number of iterations.
tolerance – Convergence tolerance on feasibility residual ||G @ m + v - d_tilde||.
References
Chambolle A. & Pock T. (2011). A First-Order Primal-Dual Algorithm for Convex Problems with Applications to Imaging. Journal of Mathematical Imaging and Vision, 40(1), 120–145. https://doi.org/10.1007/s10851-010-0251-1
- solve(c: Vector, m0: Vector | None = None) ChambollePockResult[source]¶
Run the Chambolle-Pock iterations for objective direction $c$.
Solves
\[h_U = \max_{m \in B,\, v \in V}\; \langle c, m \rangle \quad\text{s.t.}\quad Gm + v = \tilde{d}\]Iteration (with $θ = 1$, $K = [G;\ I]$):
$μ^{n+1} = μ^n + σ(G\bar{m}^n + \bar{v}^n - \tilde{d})$
$m^{n+1} = \operatorname{proj}_B\bigl(m^n - τ G^* μ^{n+1} + τ c\bigr)$
$v^{n+1} = \operatorname{proj}_V\bigl(v^n - τ μ^{n+1}\bigr)$
$\bar{m}^{n+1} = m^{n+1} + θ(m^{n+1} - m^n)$, v_bar^{n+1} = v^{n+1} + theta * (v^{n+1} - v^n)
Convergence is declared when the feasibility residual ||G @ m + v - d_tilde|| < tolerance.
- Parameters:
c – Linear objective coefficient in model space (typically c = T* @ q).
m0 – Initial model vector. Defaults to zero.
- Returns:
ChambollePockResultcontaining the primal optimisers $(m^*, v^*)$, dual variable $μ^*$, feasibility gap, and convergence diagnostics.
- class pygeoinf.convex_optimisation.ClarabelQPSolver(*, verbose: bool = False, max_iter: int = 200, eps_abs: float = 1e-08, eps_rel: float = 1e-08)[source]¶
Bases:
objectQP solver using Clarabel (interior-point). Requires
pip install clarabel.Converts the OSQP standard form $l ≤ Ax ≤ u$ to Clarabel’s cone form internally. Equality constraints ($l_i = u_i$) are handled via
clarabel.ZeroConeT; inequality constraints viaclarabel.NonnegativeConeT.- Parameters:
verbose – Whether Clarabel prints solver output (default
False).max_iter – Maximum interior-point iterations (default
200).eps_abs – Absolute convergence tolerance (default
1e-8).eps_rel – Relative convergence tolerance (default
1e-8).
- Raises:
ImportError – If the
clarabelpackage is not installed.
- solve(P: ndarray, q: ndarray, A: ndarray, l: ndarray, u: ndarray, x0: ndarray | None = None) QPResult[source]¶
Solve the QP using Clarabel and return a
QPResult.- Parameters:
P – Symmetric PSD Hessian of shape
(n, n).q – Linear cost vector of shape
(n,).A – Constraint matrix of shape
(m, n).l – Lower-bound vector of shape
(m,);-np.inffor one-sided.u – Upper-bound vector of shape
(m,);+np.inffor one-sided.x0 – Warm-start hint (ignored if API unavailable).
- Returns:
QPResultwithstatus='solved'on success.
Notes
Clarabel’s constraint form is $Ax + s = b$, $s ∈ K$. For
NonnegativeConeTthis means $b - Ax ≥ 0$, i.e. $Ax ≤ b$. Each OSQP row is therefore expanded into at most two Clarabel rows.
- class pygeoinf.convex_optimisation.Cut(x: Vector, f: float, g: Vector, iteration: int)[source]¶
Bases:
objectA linearisation cut for a convex function at a point.
A cut records the function value and a subgradient at an evaluation point, defining the affine lower bound: f_j + <g_j, lambda - x_j> <= f(lambda) for all lambda.
- x¶
Evaluation point (a Hilbert-space vector).
- Type:
Vector
- f¶
Function value f(x).
- Type:
float
- g¶
Subgradient g in partial_f(x).
- Type:
Vector
- iteration¶
Iteration index at which this cut was generated.
- Type:
int
- f: float¶
- g: Vector¶
- iteration: int¶
- x: Vector¶
- class pygeoinf.convex_optimisation.KKTResult(m: Vector, multipliers: tuple[float, float], converged: bool, num_iterations: int)[source]¶
Bases:
objectResult from
PrimalKKTSolver.- m¶
Optimal primal model vector $u^*$ in the model space.
- Type:
Vector
- multipliers¶
KKT multipliers $(lambda^*, mu^*)$. $lambda^*$ enforces the model prior constraint and $mu^*$ enforces the data-fit constraint. Both are non-negative.
- Type:
tuple[float, float]
- converged¶
Trueif the root-finder converged to the required tolerance.- Type:
bool
- num_iterations¶
Number of function evaluations used by the root-finder (or 1 for the closed-form branch).
- Type:
int
- converged: bool¶
- m: Vector¶
- multipliers: tuple[float, float]¶
- num_iterations: int¶
- class pygeoinf.convex_optimisation.LevelBundleMethod(oracle: NonLinearForm, /, *, alpha: float = 0.1, tolerance: float = 1e-06, max_iterations: int = 500, bundle_size: int = 100, store_iterates: bool = False, qp_solver: QPSolver | None = None)[source]¶
Bases:
objectLevel bundle method for minimising a non-smooth convex function.
- Solves:
min_{lambda in D} f(lambda)
where f is a convex function accessible through a value + subgradient oracle (a
NonLinearFormwithsubgradient).- At each iteration the level master QP is:
min_{lambda, t} (1/2) ||lambda - lambda_hat||^2 subject to: f_j + <g_j, lambda - x_j> <= t for all j
t <= f_lev
where the level is: f_lev = alpha * f_low + (1 - alpha) * f_up, alpha in (0,1).
The lower bound f_low is maintained as the LP optimal value of the cutting-plane model:
- f_LP = min_{lambda} hat_phi(lambda)
= min_{lambda, t} t
subject to: f_j + <g_j, lambda - x_j> <= t
Infeasibility handling. If the level QP is infeasible (which can happen when f_lev < f_LP for a tight alpha), alpha is widened by a factor of 1.5 (capped at 0.9) for up to three attempts. If all attempts fail an emergency proximal step is taken (minimize t + (1/2) ||lambda - lambda_hat||^2 over the current bundle) so the stability centre and bundle are always updated.
- Parameters:
oracle – Non-smooth convex functional with subgradient oracle.
alpha – Level parameter alpha in (0, 1) controlling how aggressively the level is set towards the lower bound. Smaller values are more aggressive (risk infeasibility); larger are more conservative. Defaults to
0.1.tolerance – Convergence tolerance; terminates when the duality gap f_up - f_low <= tolerance.
max_iterations – Maximum number of oracle calls.
bundle_size – Maximum number of cuts retained in the bundle.
store_iterates – If
True, all iterates are stored inBundleResult.iterates.qp_solver – QP solver implementing
QPSolver. Defaults toSciPyQPSolverifNone.
Examples
>>> from pygeoinf.hilbert_space import EuclideanSpace >>> from pygeoinf.nonlinear_forms import NonLinearForm >>> import numpy as np >>> domain = EuclideanSpace(1) >>> f = lambda x: float(x[0]**2 + 2*x[0]) >>> g = lambda x: np.array([2*x[0] + 2.0]) >>> oracle = NonLinearForm(domain, f, subgradient=g) >>> solver = LevelBundleMethod(oracle, tolerance=1e-5) >>> result = solver.solve(domain.from_components(np.array([2.0]))) >>> np.testing.assert_allclose(domain.to_components(result.x_best), [-1.0], atol=1e-3)
- solve(x0: Vector) BundleResult[source]¶
Run the level bundle method starting from x0.
- Parameters:
x0 – Initial point in the domain of the oracle.
- Returns:
A
BundleResultsummarising the optimisation run.
- class pygeoinf.convex_optimisation.OSQPQPSolver(*, eps_abs: float = 1e-06, eps_rel: float = 1e-06, verbose: bool = False, polish: bool = True, max_iter: int = 10000)[source]¶
Bases:
objectQP solver using OSQP (ADMM-based). Requires
pip install osqp.Supports warm-starting via the x0 parameter. A fresh OSQP instance is created for every
solve()call to avoid stale state.- Parameters:
eps_abs – Absolute feasibility tolerance (default
1e-6).eps_rel – Relative feasibility tolerance (default
1e-6).verbose – Whether OSQP prints solver output (default
False).polish – Whether to apply polishing step for higher accuracy (default
True).max_iter – Maximum number of ADMM iterations (default
10000).
- Raises:
ImportError – If the
osqppackage is not installed.
- solve(P: ndarray, q: ndarray, A: ndarray, l: ndarray, u: ndarray, x0: ndarray | None = None) QPResult[source]¶
Solve the QP using OSQP and return a
QPResult.- Parameters:
P – Symmetric PSD Hessian of shape
(n, n).q – Linear cost vector of shape
(n,).A – Constraint matrix of shape
(m, n).l – Lower-bound vector of shape
(m,);-np.inffor one-sided.u – Upper-bound vector of shape
(m,);+np.inffor one-sided.x0 – Optional warm-start primal solution of shape
(n,).
- Returns:
QPResultwithstatus='solved'on success.
- class pygeoinf.convex_optimisation.PrimalKKTSolver(B: SupportFunction, V: SupportFunction, G: LinearOperator, d_tilde: Vector, /, *, fsolve_tol: float = 1e-10, fsolve_maxfev: int = 200)[source]¶
Bases:
objectPrimal KKT solver via Woodbury identity in abstract Hilbert spaces.
The solver operates on abstract Hilbert-space vectors throughout: the model space $H$ is never discretised. Only the data space $D$ (which is explicitly finite-dimensional) is discretised — and only inside
_woodbury_solve(), which builds the $M times M$ Woodbury system.The Woodbury reduction:
\[u^*(\lambda,\mu) = \frac{1}{\lambda} A_B^{-1} r_H - \frac{1}{\lambda} A_B^{-1} G^* K^{-1} G A_B^{-1} r_H\]where
\[r_H = c + \lambda A_B u_0 + \mu G^* A_V \tilde{d}, \qquad K = \tfrac{1}{\mu} A_V^{-1} + \tfrac{1}{\lambda} G A_B^{-1} G^*\]The $M times M$ matrix $P = G A_B^{-1} G^*$ is precomputed once via
.matrix(dense=True)which probes the data space only. No model-spaceto_componentsorfrom_componentsis ever called.Ball/ball simplification ($A_B = I_H$, $A_V = I_D$):
\[r_H = c + \lambda u_0 + \mu G^* \tilde{d}, \qquad P = G G^*, \qquad K = \tfrac{1}{\mu} I_D + \tfrac{1}{\lambda} G G^*\]so the only M×M solve is $K z = G w$ and no model-space matrix is ever formed.
Supports
BallSupportFunctionandEllipsoidSupportFunctionfor both $B$ and $V$ (four combinations).- Parameters:
B – Model prior support function.
V – Data error support function (ball or ellipsoid, centered at origin).
G – Forward operator $G : H to D$.
d_tilde – Observed data vector in $D$.
fsolve_tol – Tolerance for
scipy.optimize.fsolve.fsolve_maxfev – Maximum function evaluations for
fsolve.
- solve(c: Vector) KKTResult[source]¶
Solve for $u^*$ maximising $langle c, u rangle$ over the feasible set.
Uses a two-branch strategy:
Compute the support point $u_{rm ball}$ of $B$ in direction $c$. If the data constraint is satisfied, return immediately.
Otherwise both constraints are active; solve the $2 times 2$ root-finding problem in log-space via
scipy.optimize.fsolve, warm-started from $(lambda_{rm prev}, mu_{rm prev})$.
The model space is never discretised during this method.
- Parameters:
c – Linear objective in model space $H$.
- Returns:
KKTResultwith the optimal model vector $u^*$, KKT multipliers, convergence flag, and iteration count.
- class pygeoinf.convex_optimisation.ProximalBundleMethod(oracle: NonLinearForm, /, *, rho0: float = 1.0, rho_factor: float = 2.0, tolerance: float = 1e-06, max_iterations: int = 500, bundle_size: int = 100, store_iterates: bool = False, qp_solver: QPSolver | None = None)[source]¶
Bases:
objectProximal bundle method for minimising a non-smooth convex function.
- Solves:
min_{lambda in D} f(lambda)
where f is a convex function accessible through a value + subgradient oracle (a
NonLinearFormwithsubgradient).- At each iteration the master QP is:
min_{lambda, t} t + (rho / 2) ||lambda - lambda_hat||^2 subject to: f_j + <g_j, lambda - x_j> <= t for all j in bundle
where lambda_hat is the current stability centre and rho > 0 is the proximal weight.
A serious step is taken whenever the new oracle value f(lambda_+) < f(lambda_hat); otherwise a null step occurs and rho is increased to tighten the proximal term.
- Parameters:
oracle – Non-smooth convex functional with subgradient oracle.
rho0 – Initial proximal weight rho > 0.
rho_factor – Multiplicative factor applied to rho on null steps (divide on serious steps).
tolerance – Convergence tolerance; terminates when the duality gap f_up - f_low <= tolerance.
max_iterations – Maximum number of oracle calls.
bundle_size – Maximum number of cuts retained in the bundle.
store_iterates – If
True, all iterates are stored inBundleResult.iterates.qp_solver – QP solver implementing
QPSolver. Defaults toSciPyQPSolverifNone.
Examples
>>> from pygeoinf.hilbert_space import EuclideanSpace >>> from pygeoinf.nonlinear_forms import NonLinearForm >>> import numpy as np >>> domain = EuclideanSpace(1) >>> f = lambda x: float(x[0]**2 + 2*x[0]) >>> g = lambda x: np.array([2*x[0] + 2.0]) >>> oracle = NonLinearForm(domain, f, subgradient=g) >>> solver = ProximalBundleMethod(oracle, tolerance=1e-5) >>> result = solver.solve(domain.from_components(np.array([2.0]))) >>> np.testing.assert_allclose(domain.to_components(result.x_best), [-1.0], atol=1e-3)
- solve(x0: Vector) BundleResult[source]¶
Run the proximal bundle method starting from x0.
- Parameters:
x0 – Initial point in the domain of the oracle.
- Returns:
A
BundleResultsummarising the optimisation run.
- class pygeoinf.convex_optimisation.QPResult(x: ndarray, obj: float, status: str)[source]¶
Bases:
objectResult from a quadratic programme solve.
- x¶
Solution vector (component array).
- Type:
numpy.ndarray
- obj¶
Objective value at
x.- Type:
float
- status¶
'solved'on success; a descriptive failure message otherwise.- Type:
str
- obj: float¶
- status: str¶
- x: ndarray¶
- class pygeoinf.convex_optimisation.QPSolver(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol for QP solvers used by bundle methods.
- Solvers must implement the OSQP standard form:
min_x (1/2) x^T @ P @ x + q^T @ x subject to: l <= A @ x <= u
- Parameters:
P – Symmetric positive-semi-definite Hessian, shape
(n, n).q – Linear cost, shape
(n,).A – Constraint matrix, shape
(m, n).l – Lower bounds, shape
(m,); use-np.inffor one-sided.u – Upper bounds, shape
(m,); use+np.inffor one-sided.x0 – Optional warm-start primal solution.
- Returns:
A
QPResult.
- class pygeoinf.convex_optimisation.SciPyQPSolver[source]¶
Bases:
objectQP solver backed by
scipy.optimize.minimize()withmethod='SLSQP'.Implements the
QPSolverprotocol. Converts the OSQP standard-form bounds $l ≤ Ax ≤ u$ to SLSQP inequality/equality constraints.Notes
SLSQP is a gradient-based method suitable for small to medium problems (up to a few hundred variables). For large-scale bundle QPs use an OSQP- or Clarabel-backed solver (Phase 4).
- solve(P: ndarray, q: ndarray, A: ndarray, l: ndarray, u: ndarray, x0: ndarray | None = None) QPResult[source]¶
Solve the QP and return a
QPResult.- Parameters:
P – Symmetric PSD Hessian of shape
(n, n).q – Linear cost vector of shape
(n,).A – Constraint matrix of shape
(m, n).l – Lower-bound vector of shape
(m,).u – Upper-bound vector of shape
(m,).x0 – Optional warm-start point of shape
(n,).
- Returns:
QPResultwithstatus='solved'on success.
- class pygeoinf.convex_optimisation.SmoothedDualMaster(cost: object, epsilon: float)[source]¶
Bases:
objectSmooth approximation of DualMasterCostFunction using Moreau-Yosida smoothing.
Smooths the norm-type support functions with parameter epsilon, making the objective differentiable. Only supports
BallSupportFunctionandEllipsoidSupportFunction.The smoothed ball support is
\[σ_{B,\varepsilon}(z) = ⟨ z, c ⟩ + r\,\sqrt{‖z‖^2 + \varepsilon^2}\]and its gradient w.r.t. $z$ is
\[\nabla_z σ_{B,\varepsilon}(z) = c + r\,\frac{z}{\sqrt{‖z‖^2 + \varepsilon^2}}\]The smoothed ellipsoid support is
\[σ_{E,\varepsilon}(z) = ⟨ z, c ⟩ + r\,\sqrt{⟨ z,\, A^{-1}z ⟩ + \varepsilon^2}\]and its gradient w.r.t. $z$ is
\[\nabla_z σ_{E,\varepsilon}(z) = c + r\,\frac{A^{-1}z}{\sqrt{⟨ z,\, A^{-1}z ⟩ + \varepsilon^2}}\]The full smoothed objective and its gradient are
\[\varphi_\varepsilon(λ) = ⟨λ, \tilde{d}⟩ + σ_{B,\varepsilon}(T^*q - G^*λ) + σ_{V,\varepsilon}(-λ)\]\[\nabla_λ \varphi_\varepsilon(λ) = \tilde{d} - G\,\nabla_{z_1}σ_{B,\varepsilon}(z_1) - \nabla_{z_2}σ_{V,\varepsilon}(z_2)\]where $z_1 = T^*q - G^*λ$ and $z_2 = -λ$.
- Parameters:
cost –
DualMasterCostFunctioninstance.epsilon – Smoothing parameter ($> 0$). Smaller values give a better approximation but a larger Lipschitz constant $L = r‖G‖^2 / varepsilon$.
- Raises:
NotImplementedError – If either support function is not a
BallSupportFunctionorEllipsoidSupportFunction.
- gradient(lam: Vector) Vector[source]¶
Compute the gradient $nabla_λ varphi_varepsilon(λ)$.
Uses the chain rule through $z_1 = T^*q - G^*λ$ and $z_2 = -λ$:
\[\nabla_λ \varphi_\varepsilon = \tilde{d} - G\,\nabla_{z_1}σ_{B,\varepsilon}(z_1) - \nabla_{z_2}σ_{V,\varepsilon}(z_2)\]- Parameters:
lam – Dual variable $λ ∈ D$.
- Returns:
Gradient vector in $D$.
- Raises:
NotImplementedError – If either support function is unsupported.
- class pygeoinf.convex_optimisation.SmoothedLBFGSSolver(cost: object, /, *, epsilon0: float = 0.01, n_levels: int = 5, tolerance: float = 1e-06, max_iter_per_level: int = 500)[source]¶
Bases:
objectL-BFGS-B optimiser with smoothing continuation for DualMasterCostFunction.
Uses Moreau-Yosida smoothing with a geometric continuation schedule:
epsilon_0 >> epsilon_1 >> … >> epsilon_{L-1} ≈ tol
where epsilon_i = epsilon_0 × 10^{-i}. Each level is solved with L-BFGS-B, warm-starting from the previous solution.
Note
Returns
BundleResultwithgap=np.nanandf_low=np.nan— no gap certificate is available for smoothed methods.- Parameters:
cost –
DualMasterCostFunctioninstance.epsilon0 – Initial smoothing parameter (default
1e-2).n_levels – Number of continuation levels (default
5).tolerance – Target accuracy; last epsilon is $varepsilon_0 × 10^{-(n_levels - 1)}$.
max_iter_per_level – Maximum L-BFGS-B iterations per level (default
500).
- solve(lam0: Vector) BundleResult[source]¶
Run the smoothed L-BFGS-B continuation and return the result.
- Parameters:
lam0 – Starting point $λ_0 ∈ D$.
- Returns:
BundleResultwithgapandf_lowset tonp.nan(no subgradient-based lower bound is maintained).
- class pygeoinf.convex_optimisation.SubgradientDescent(oracle: NonLinearForm, /, *, step_size: float, max_iterations: int = 500, store_iterates: bool = False, stagnation_window: int | None = None)[source]¶
Bases:
objectBasic subgradient descent for minimising non-smooth convex functions.
- Algorithm:
x_{k+1} = x_k - α * g_k
where g_k ∈ ∂f(x_k) is a subgradient (obtained via oracle.subgradient(x_k)).
This implementation uses CONSTANT step size α for all k. Convergence is not guaranteed with constant step size; use for learning/testing only.
- Parameters:
oracle – A NonLinearForm with subgradient() method returning subgradients.
step_size – Constant step size α > 0.
max_iterations – Maximum number of iterations.
store_iterates – Whether to store full history (memory intensive).
stagnation_window – Optional number of iterations without improvement to declare convergence.
- property domain: HilbertSpace¶
- property oracle: NonLinearForm¶
- solve(x0: Vector) SubgradientResult[source]¶
Run subgradient descent from initial point x0.
- class pygeoinf.convex_optimisation.SubgradientResult(x_best: Vector, f_best: float, x_final: Vector, f_final: float, num_iterations: int, converged: bool, function_values: List[float], iterates: List['Vector'] | None = None)[source]¶
Bases:
objectResult from subgradient descent optimisation.
- x_best¶
Best point found (lowest function value).
- Type:
Vector
- f_best¶
Best function value found.
- Type:
float
- x_final¶
Final iterate (may differ from x_best).
- Type:
Vector
- f_final¶
Final function value.
- Type:
float
- num_iterations¶
Number of iterations performed.
- Type:
int
- converged¶
Whether convergence criterion was met.
- Type:
bool
- function_values¶
History of function values at each iteration.
- Type:
List[float]
- iterates¶
Optional history of all iterates (memory intensive).
- Type:
Optional[List[‘Vector’]]
- converged: bool¶
- f_best: float¶
- f_final: float¶
- function_values: List[float]¶
- iterates: List['Vector'] | None = None¶
- num_iterations: int¶
- x_best: Vector¶
- x_final: Vector¶
- pygeoinf.convex_optimisation.best_available_qp_solver() QPSolver[source]¶
Return the best available QP solver (OSQP > Clarabel > SciPy).
Tries solvers in order of preference: OSQP (ADMM, fast for large-scale), then Clarabel (interior-point, high accuracy), then the SciPy SLSQP fallback.
- Returns:
A
QPSolverinstance backed by the best installed package.
- pygeoinf.convex_optimisation.solve_primal_feasibility(cost, qs: list[Vector] | np.ndarray, cp_solver: ChambollePockSolver) np.ndarray[source]¶
Compute support values h_U(q_i) using the primal feasibility form.
Solves one Chambolle-Pock problem for each direction q_i (using c = T* @ q_i), exploiting that the feasible set (B, V, G, d_tilde) is independent of q.
- The support value for direction q is:
- h_U(q) = max_{m in B, v in V} <T* @ q, m>
subject to: G @ m + v = d_tilde
= <T* @ q, m*(q)>
where m*(q) is returned by
ChambollePockSolver.solve().- Parameters:
cost –
DualMasterCostFunctionholding references to T, G, and the model space.qs – Directions to evaluate; a list of Vectors (in the property space) or an
np.ndarrayof shape(p, prop_dim).cp_solver – Pre-configured
ChambollePockSolverfor the problem.
- Returns:
np.ndarrayof shape(p,)with h_U(q_i) for each direction.
- pygeoinf.convex_optimisation.solve_support_values(cost, qs, solver, lambda0, *, warm_start: bool = True, n_jobs: int = 1)[source]¶
Compute support function values for multiple directions.
Solves the dual master minimisation for each direction q_i in qs, optionally warm-starting from the previous direction’s solution.
The support function of a set U evaluated at direction q is:
h_U(q) = min_{lambda} f(q, lambda)
where f(q, ·) is the dual master cost with direction q.
- Parameters:
cost – DualMasterCostFunction instance with a
set_directionmethod.qs – Directions to evaluate; either a list of Vectors or an
np.ndarrayof shape(p, prop_dim).solver – Bundle method solver (ProximalBundleMethod or LevelBundleMethod).
lambda0 – Initial lambda for the first direction (a Vector in the data space).
warm_start – If
True(default), each direction starts from the previous direction’s optimal lambda. IfFalse, always start fromlambda0.n_jobs – Number of parallel jobs.
1= fully sequential (warm starting works).>1= joblib Parallel (warm-starting across workers is disabled; each worker starts fromlambda0).
- Returns:
np.ndarrayof shape(p,), support values$h_U(q_i)$ for each direction.
- lambdas:
listof lengthp, optimal lambda for each direction.
diagnostics:
listofBundleResultfor each direction.- Return type:
values
- Raises:
ImportError – If
n_jobs > 1andjoblibis not installed (falls back to sequential with a warning instead of raising).
pygeoinf.datasets module¶
pygeoinf/datasets.py
Provides access to built-in datasets for testing, benchmarking, and visualization across the pygeoinf package.
- pygeoinf.datasets.download_gsn_stations(force: bool = False) None[source]¶
Fetches the Global Seismograph Network (GSN) stations from the IRIS FDSN API and saves them to a local CSV file in the data/ directory.
- pygeoinf.datasets.download_usgs_earthquakes(min_magnitude: float = 5.0, start_time: str = None, end_time: str = None, min_depth: float = None, max_depth: float = None, bbox: Tuple[float, float, float, float] = None, limit: int = 2000, force: bool = False, filename: str = 'usgs_events_filtered.csv') None[source]¶
Fetches a filtered catalog of earthquakes from the USGS API and saves it to a CSV in the centralized DATADIR.
- pygeoinf.datasets.load_gsn_stations(n_stations: int = None, include_names: bool = False) List[Tuple[float, float]] | List[Tuple[str, float, float]][source]¶
Loads a representative global set of seismic stations from the GSN.
If the internal CSV file is missing, this function will attempt to automatically download it from IRIS into the pygeoinf/data/ directory.
- Parameters:
n_stations – If provided, returns a random subsample of this size. If greater than the total available stations, returns all.
include_names – If True, returns (Name, Latitude, Longitude). If False, returns pure (Latitude, Longitude) tuples.
- Returns:
A list of station tuples in degrees.
- pygeoinf.datasets.sample_earthquakes(n_events: int, min_magnitude: float = 5.0) List[Tuple[float, float, float]][source]¶
Returns a random subsample of real earthquake locations.
If the local cache does not contain enough events to satisfy the request, it automatically fetches a larger catalog from the USGS to rebuild the cache.
- Parameters:
n_events – The exact number of earthquake locations to return.
min_magnitude – The minimum magnitude to use if a new download is required.
- Returns:
(Latitude, Longitude, Depth_in_km).
- Return type:
A list of tuples
pygeoinf.direct_sum module¶
Implements direct sums of Hilbert spaces and corresponding block operators.
This module provides tools for constructing larger, composite Hilbert spaces and operators from smaller ones. This is essential for problems involving multiple coupled fields or joint inversions where a single model is constrained by data from different experiments.
Key Classes¶
HilbertSpaceDirectSum: A HilbertSpace formed by the direct sum of a list of other spaces. Vectors in this space are lists of vectors from the component subspaces.
BlockLinearOperator: A LinearOperator acting between direct sum spaces, represented as a 2D grid (matrix) of sub-operators.
ColumnLinearOperator: A specialized block operator mapping from a single space to a direct sum space.
RowLinearOperator: A specialized block operator mapping from a direct sum space to a single space.
BlockDiagonalLinearOperator: An efficient representation for block operators with zero off-diagonal blocks.
- class pygeoinf.direct_sum.BlockDiagonalLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureA block operator where all off-diagonal blocks are zero operators.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
If i equals j, this is one of the diagonal operators. Otherwise, it is a zero operator.
- class pygeoinf.direct_sum.BlockLinearOperator(blocks: List[List[LinearOperator]])[source]¶
Bases:
LinearOperator,BlockStructureA linear operator between direct sum spaces, defined by a matrix of sub-operators.
This operator acts like a matrix where each entry is itself a LinearOperator. It maps a list of input vectors [x_1, x_2, …] to a list of output vectors [y_1, y_2, …]. The constructor checks for dimensional consistency between the blocks.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
- class pygeoinf.direct_sum.BlockStructure(row_dim: int, col_dim: int)[source]¶
Bases:
ABCAn abstract base class for operators with a block structure.
- abstract block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
- property col_dim: int¶
Returns the number of columns in the block structure.
- property row_dim: int¶
Returns the number of rows in the block structure.
- class pygeoinf.direct_sum.ColumnLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureAn operator that maps from a single space to a direct sum space.
It can be visualized as a column vector of operators, [A_1, A_2, …]^T. It takes a single input vector x and produces a list of output vectors [A_1(x), A_2(x), …]. This is often used to represent a joint forward operator in an inverse problem.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, 0)-th sub-block.
- class pygeoinf.direct_sum.HilbertSpaceDirectSum(spaces: List[HilbertSpace])[source]¶
Bases:
HilbertSpaceA Hilbert space formed from the direct sum of a list of other spaces.
A vector in this space is represented as a list of vectors, where the i-th element of the list is a vector from the i-th component subspace. The inner product is the sum of the inner products of the components.
- add(xs: List[Any], ys: List[Any]) List[Any][source]¶
Computes the sum of two vectors. Defaults to x + y.
- axpy(a: float, xs: List[Any], ys: List[Any]) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- canonical_dual_inverse_isomorphism(xp: LinearForm) List[LinearForm][source]¶
Maps a dual vector on the sum space to a list of dual vectors.
This is the inverse of the canonical isomorphism, projecting the action of a dual vector onto each subspace.
- Parameters:
xp (LinearForm) – A dual vector on the direct sum space.
- canonical_dual_isomorphism(xps: List[LinearForm]) LinearForm[source]¶
Maps a list of dual vectors to a single dual vector on the sum space.
This is the canonical isomorphism from the direct sum of the dual spaces to the dual of the direct sum space.
- Parameters:
xps (List[LinearForm]) – A list of dual vectors, one for each subspace.
- property dim: int¶
Returns the dimension of the direct sum space.
- from_components(c: ndarray) List[Any][source]¶
Maps a NumPy component array back to a vector in the space.
- Parameters:
c – The components of the vector as a NumPy array.
- Returns:
The corresponding vector in the space.
- from_dual(xp: LinearForm) List[Any][source]¶
Maps a dual vector back to its representative in the primal space.
This is the inverse of the Riesz representation map defined by to_dual.
- Parameters:
xp – A vector in the dual space.
- Returns:
The corresponding vector in the primal space.
- is_element(xs: Any) bool[source]¶
Checks if a list of vectors is a valid element of the direct sum space.
- multiply(a: float, xs: List[Any]) List[Any][source]¶
Computes scalar multiplication. Defaults to a * x.
- property number_of_subspaces: int¶
Returns the number of subspaces in the direct sum.
- subspace(i: int) HilbertSpace[source]¶
Returns the i-th subspace.
- Parameters:
i (int) – The index of the subspace to retrieve.
- subspace_inclusion(i: int) LinearOperator[source]¶
Returns the inclusion operator from the i-th subspace into the sum.
- Parameters:
i (int) – The index of the subspace to include from.
- subspace_projection(i: int) LinearOperator[source]¶
Returns the projection operator onto the i-th subspace.
- Parameters:
i (int) – The index of the subspace to project onto.
- property subspaces: List[HilbertSpace]¶
Returns the list of subspaces that form the direct sum.
- subtract(xs: List[Any], ys: List[Any]) List[Any][source]¶
Computes the difference of two vectors. Defaults to x - y.
- to_components(xs: List[Any]) ndarray[source]¶
Maps a vector to its representation as a NumPy component array.
- Parameters:
x – A vector in the space.
- Returns:
The components of the vector as a NumPy array.
- to_dual(xs: List[Any]) LinearForm[source]¶
Maps a vector to its canonical dual vector (a linear functional).
This method, along with from_dual, defines the Riesz representation map and implicitly defines the inner product of the space.
- Parameters:
x – A vector in the primal space.
- Returns:
The corresponding vector in the dual space.
- property zero: List[Any]¶
each subspace contributes its own zero.
- Type:
The zero element
- class pygeoinf.direct_sum.RowLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureAn operator that maps from a direct sum space to a single space.
It can be visualized as a row vector of operators, [A_1, A_2, …]. It takes a list of input vectors [x_1, x_2, …] and produces a single output vector y = A_1(x_1) + A_2(x_2) + …. The adjoint of a ColumnLinearOperator is a RowLinearOperator.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (0, j)-th sub-block.
pygeoinf.dynamical_system module¶
A module defining the base architecture for dynamical systems on Hilbert spaces.
- class pygeoinf.dynamical_system.AutonomousDynamicalSystem(state_space: HilbertSpace, operator: NonLinearOperator)[source]¶
Bases:
DynamicalSystemA concrete implementation of a non-linear, autonomous system. Represents du/dt = F(u), where the operator F does not change with time.
- dynamical_rule(t: float) NonLinearOperator[source]¶
Returns the static non-linear operator.
- Parameters:
t – The current time (ignored, but kept for interface compliance).
- property is_autonomous: bool¶
Indicates if the system’s governing operator is time-independent. Defaults to False for a general dynamical system.
- class pygeoinf.dynamical_system.AutonomousLinearSystem(state_space: HilbertSpace, operator: LinearOperator)[source]¶
Bases:
LinearDynamicalSystemA concrete implementation of a linear, autonomous system. Represents du/dt = Lu, where the linear operator L is constant.
- dynamical_rule(t: float) LinearOperator[source]¶
Returns the static linear operator.
- Parameters:
t – The current time (ignored, but kept for interface compliance).
- property is_autonomous: bool¶
Indicates if the system’s governing operator is time-independent. Defaults to False for a general dynamical system.
- class pygeoinf.dynamical_system.DynamicalSystem(state_space: HilbertSpace)[source]¶
Bases:
ABCBase abstract class for a dynamical system on a Hilbert space. Represents the generally non-linear, non-autonomous system du/dt = F(t, u).
- abstract dynamical_rule(t: float) NonLinearOperator[source]¶
Returns the non-linear operator F(t, .) mapping the state to its derivative.
- Parameters:
t – The current time.
- Returns:
A pygeoinf NonLinearOperator mapping state_space to state_space.
- property is_autonomous: bool¶
Indicates if the system’s governing operator is time-independent. Defaults to False for a general dynamical system.
- class pygeoinf.dynamical_system.LinearDynamicalSystem(state_space: HilbertSpace)[source]¶
Bases:
DynamicalSystemAbstract base class for a linear, non-autonomous dynamical system. Represents du/dt = L(t)u.
This enforces a stricter return type (LinearOperator) so integrators can optimize Jacobian evaluations and matrix operations.
- abstract dynamical_rule(t: float) LinearOperator[source]¶
Returns the linear operator L(t) mapping the state to its derivative.
- Parameters:
t – The current time.
- Returns:
A pygeoinf LinearOperator mapping state_space to state_space.
pygeoinf.forward_problem module¶
Defines the mathematical structure of a forward problem.
This module provides classes that encapsulate the core components of an inverse problem. A forward problem describes the physical or mathematical process that maps a set of unknown model parameters u to a set of observable data d.
The module handles both the deterministic relationship d = A(u) and the more realistic statistical model d = A(u) + e, where e represents random noise.
Key Classes¶
ForwardProblem: A general class representing the link between a model space and a data space via a forward operator, with an optional data error.
LinearForwardProblem: A specialization for linear problems where the forward operator is a LinearOperator.
- class pygeoinf.forward_problem.ForwardProblem(forward_operator: NonLinearOperator, /, *, data_error_measure: GaussianMeasure | None = None)[source]¶
Bases:
objectRepresents a general forward problem.
An instance is defined by a forward operator that maps from a model space to a data space, and an optional Gaussian measure representing the statistical distribution of errors in the data.
- property data_error_measure: GaussianMeasure¶
The measure from which data errors are drawn.
- property data_error_measure_set: bool¶
True if a data error measure has been set.
- property data_space: HilbertSpace¶
The data space (codomain of the forward operator).
- property forward_operator: LinearOperator¶
The forward operator, mapping from model to data space.
- property model_space: HilbertSpace¶
The model space (domain of the forward operator).
- class pygeoinf.forward_problem.LinearForwardProblem(forward_operator: LinearOperator, /, *, data_error_measure: GaussianMeasure | None = None)[source]¶
Bases:
ForwardProblemRepresents a linear forward problem of the form d = A(u) + e.
Here, d is the data, A is the linear forward operator, u is the model, and e is a random error drawn from a Gaussian distribution.
- chi_squared(model: Vector, data: Vector) float[source]¶
Calculates the chi-squared statistic for a given model and data.
This measures the misfit between the predicted and observed data.
If a data error measure with an inverse covariance C_e^-1 is defined, this is the weighted misfit: (d - A(u))^T * C_e^-1 * (d - A(u)).
Otherwise, it is the squared L2 norm of the data residual: ||d - A(u)||^2.
- Parameters:
model – A vector from the model space.
data – An observed data vector from the data space.
- Returns:
The chi-squared statistic.
- chi_squared_from_residual(residual: Vector) float[source]¶
Calculates the chi-squared statistic from a residual vector.
- Parameters:
residual – The residual vector.
- Returns:
The chi-squared statistic.
- chi_squared_test(significance_level: float, model: Vector, data: Vector) bool[source]¶
Performs a chi-squared test for goodness of fit.
- Parameters:
significance_level – The significance level for the test (e.g., 0.95).
model – A vector from the model space.
data – An observed data vector from the data space.
- Returns:
True if the model is statistically compatible with the data at the specified significance level, False otherwise.
- critical_chi_squared(significance_level: float) float[source]¶
Returns the critical value of the chi-squared statistic.
This value serves as the threshold for the chi-squared test at a given significance level.
- Parameters:
significance_level – The desired significance level (e.g., 0.95).
- Returns:
The critical chi-squared value.
- data_measure_from_model(model: Vector) GaussianMeasure[source]¶
Returns the Gaussian measure for the data, given a specific model.
The resulting measure has a mean of A(model) and the covariance of the data error.
- Parameters:
model – A vector from the model space.
- Returns:
The Gaussian measure representing the distribution of possible data.
- data_measure_from_model_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the induced measure on the data space.
- data_reduced_problem(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1) LinearForwardProblem[source]¶
Creates a new forward problem by applying a reduction (or sketching) operator to the data space.
- Parameters:
reduction_operator – A LinearOperator mapping from the current data space to the new reduced data space.
reduced_data_error_measure – An optional data error measure on the reduced data space. If not provided, the original data error measure is pushed forward automatically.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
- Returns:
A new LinearForwardProblem operating in the reduced data space.
- static from_direct_sum(forward_problems: List[LinearForwardProblem]) LinearForwardProblem[source]¶
Forms a joint forward problem from a list of separate problems.
This is a powerful tool for joint inversions, where a single underlying model is observed through multiple, independent measurement systems (e.g., different types of geophysical surveys).
- Parameters:
forward_problems – A list of LinearForwardProblem instances that share a common model space.
- Returns:
A single LinearForwardProblem where the data space is the direct sum of the individual data spaces.
- joint_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the joint measure for the model and data.
- parameterized_problem(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1) LinearForwardProblem[source]¶
Creates a new forward problem based on a model parameterization.
- synthetic_data(model: Vector) Vector[source]¶
Generates a synthetic data vector for a given model.
The data is computed as d = A(model) + e, where e is a random sample from the data error measure.
- Parameters:
model – A vector from the model space.
- Returns:
A synthetic data vector.
- synthetic_model_and_data(prior: GaussianMeasure) Tuple[Vector, Vector][source]¶
Generates a random model and corresponding synthetic data.
- Parameters:
prior – A Gaussian measure on the model space, from which the random model u will be drawn.
- Returns:
A tuple (u, d), where u is the random model and d is the corresponding synthetic data.
pygeoinf.functional_calculus module¶
Functional calculus for abstract linear operators.
This module provides the machinery to evaluate matrix functions of the form f(A)v, where A is a self-adjoint LinearOperator, v is a vector in a Hilbert space, and f is a continuous function defined on the spectrum of A.
The primary mathematical engine is the Lanczos method. Given a self-adjoint LinearOperator C, a vector v in H, and a real-valued analytic function f, it computes the approximation:
f(C)v ~= ||v||_H * V_k * f(T_k) * e_1
where T_k is the k x k symmetric tridiagonal matrix produced by k steps of the Lanczos recurrence, V_k is the orthogonal basis of the Krylov subspace, and e_1 is the first standard basis vector. This approach yields the optimal degree-k polynomial approximation to the true action of the function.
- class pygeoinf.functional_calculus.LanczosOperatorFunction(operator: LinearOperator, func: Callable[[ndarray], ndarray], size_estimate: int, *, method: Literal['variable', 'fixed'] = 'variable', max_k: int | None = None, reorth: str = 'full', rtol: float = 0.001, atol: float = 1e-08, check_interval: int = 5)[source]¶
Bases:
LinearOperatorA matrix-free LinearOperator representing the action of a continuous function applied to a self-adjoint positive operator.
Rather than explicitly computing and storing the dense matrix f(A), this class evaluates the matrix-vector product f(A)x dynamically on the fly using the Lanczos process. This allows for highly efficient evaluations in massive or infinite-dimensional Hilbert spaces.
- property base_operator: LinearOperator¶
Returns the underlying base LinearOperator.
- pygeoinf.functional_calculus.apply_operator_function(operator: LinearOperator, v: Vector, func: Callable[[ndarray], ndarray], size_estimate: int, *, method: Literal['variable', 'fixed'] = 'variable', max_k: int | None = None, reorth: str = 'full', rtol: float = 0.001, atol: float = 1e-08, check_interval: int = 5) Vector[source]¶
Computes the action of a matrix function on a vector, f(A)v, using the Lanczos approximation.
This function builds a Krylov subspace from the starting vector v. It projects the large operator onto this subspace to form a small tridiagonal matrix T. The target function f is evaluated on the eigensystem of T, and the result is lifted back to the original full-dimensional space.
- Parameters:
operator (LinearOperator) – The self-adjoint positive operator A.
v (Vector) – The input vector to be multiplied by f(A).
func (Callable) – A vectorized scalar function.
size_estimate (int) – The initial or fixed number of Krylov basis vectors.
method (str) – ‘variable’ to stop dynamically when the relative change in the approximated vector falls below tolerance. ‘fixed’ to run an exact number of iterations.
max_k (int, optional) – Hard limit on Krylov dimension.
reorth (str) – ‘full’ for complete basis orthogonalization, ‘none’ otherwise.
rtol (float) – Relative tolerance for convergence checking.
atol (float) – Absolute tolerance for convergence checking.
check_interval (int) – Iterations between convergence checks.
- Returns:
The result of f(A)v residing in the same Hilbert space as v.
- Return type:
Vector
- pygeoinf.functional_calculus.iter_lanczos_tridiagonalize(operator: LinearOperator, v: Vector, max_k: int, *, reorth: str = 'full') Iterator[Tuple[List[Vector], ndarray]][source]¶
Generator that lazily yields the Krylov basis and tridiagonal matrix at each step of the Lanczos process.
This engine progressively builds an orthonormal basis for the Krylov subspace K_k(A, v) while simultaneously projecting the operator into that subspace to form a symmetric tridiagonal matrix T.
It includes an early-stopping mechanism: if the starting vector v is fully contained within an invariant subspace of dimension less than max_k, the residual norm will drop to zero, and the generator will terminate cleanly to prevent numerical breakdown.
- Parameters:
operator (LinearOperator) – The self-adjoint operator A.
v (Vector) – The starting vector.
max_k (int) – The maximum number of Krylov subspace dimensions to build.
reorth (str, optional) – Reorthogonalization strategy. ‘full’ employs the “twice is enough” modified Gram-Schmidt algorithm against all previous basis vectors, enforcing strict numerical orthogonality. ‘none’ only orthogonalizes against the immediate two predecessors. Defaults to ‘full’.
- Yields:
Iterator[Tuple[List[Vector], np.ndarray]] –
- At each step k (from 1 to max_k),
yields a tuple containing: - The current list of k orthonormal basis vectors. - The current k x k symmetric tridiagonal numpy array T.
- Raises:
ValueError – If max_k is less than 1, if an invalid reorth strategy is passed, or if the starting vector v is the zero vector.
- pygeoinf.functional_calculus.lanczos_tridiagonalize(operator: LinearOperator, v: Vector, max_k: int, *, reorth: str = 'full') Tuple[List[Vector], ndarray][source]¶
Executes a fixed number of Lanczos iterations to tridiagonalize the operator.
This is a convenience wrapper around the iter_lanczos_tridiagonalize generator. It runs the process to completion and returns only the final state.
- Parameters:
operator (LinearOperator) – The self-adjoint operator to tridiagonalize.
v (Vector) – The starting vector for the Krylov subspace.
max_k (int) – The maximum number of iterations/dimensions to compute.
reorth (str, optional) – The reorthogonalization strategy (‘full’ or ‘none’). Defaults to “full”.
- Returns:
A list of orthonormal basis vectors defining the Krylov subspace.
The final symmetric tridiagonal matrix T of size up to (max_k, max_k).
- Return type:
Tuple[List[Vector], np.ndarray]
- pygeoinf.functional_calculus.operator_function_quadratic_form(operator: LinearOperator, v: Vector, func: Callable[[ndarray], ndarray], size_estimate: int, *, method: Literal['variable', 'fixed'] = 'variable', max_k: int | None = None, reorth: str = 'full', rtol: float = 0.001, atol: float = 1e-08, check_interval: int = 5) float[source]¶
Computes the quadratic form <v, f(A)v> using the Lanczos approximation.
This function evaluates the quadratic form much more efficiently than explicitly computing the full vector f(A)v first. It relies on the spectral theorem: the quadratic form is equivalent to an integral over the spectral measure of A. The Lanczos process naturally generates the nodes (eigenvalues) and weights (squared first components of eigenvectors) for a highly accurate Gaussian quadrature of this integral.
- Parameters:
operator (LinearOperator) – The self-adjoint positive operator A.
v (Vector) – The input vector.
func (Callable) – A vectorized scalar function.
size_estimate (int) – The initial or fixed number of Krylov basis vectors.
method (str) – ‘variable’ to check convergence dynamically, ‘fixed’ otherwise.
max_k (int, optional) – Hard limit on Krylov dimension.
reorth (str) – Reorthogonalization strategy (‘full’ or ‘none’).
rtol (float) – Relative tolerance for convergence checking.
atol (float) – Absolute tolerance for convergence checking.
check_interval (int) – Iterations between convergence checks.
- Returns:
The scalar evaluation of the quadratic form.
- Return type:
float
pygeoinf.gaussian_measure module¶
Provides a class for representing Gaussian measures on Hilbert spaces.
This module generalizes the concept of a multivariate normal distribution to the setting of abstract Hilbert spaces. A GaussianMeasure is defined by its expectation (a vector in the space) and its covariance (a self-adjoint, positive semi-definite LinearOperator).
This abstraction is fundamental for Bayesian inference, Gaussian processes, and data assimilation in function spaces.
Key Features¶
Multiple factory methods for creating measures from various inputs (matrices, samples, standard deviations).
A method for drawing random samples from the measure.
Implementation of the affine transformation rule (y = A(x) + b).
Support for creating low-rank approximations of the measure for efficiency.
Overloaded arithmetic operators for intuitive combination of measures.
- class pygeoinf.gaussian_measure.GaussianMeasure(*, covariance: LinearOperator = None, covariance_factor: LinearOperator = None, expectation: Vector = None, sample: Callable[[], Vector] = None, inverse_covariance: LinearOperator = None, inverse_covariance_factor: LinearOperator = None)[source]¶
Bases:
objectRepresents a Gaussian measure on a Hilbert space.
This class generalizes the multivariate normal distribution to abstract, potentially infinite-dimensional, Hilbert spaces. A measure is defined by its expectation (mean vector) and its covariance, which is a LinearOperator on the space.
- affine_mapping(*, operator: LinearOperator = None, translation: Vector = None, affine_operator: AffineOperator = None, inverse_solver: LinearSolver = None, inverse_preconditioner: LinearOperator = None) GaussianMeasure[source]¶
Transforms the measure under an affine map y = A(x) + b.
This method calculates the push-forward measure. It can also construct the implied inverse covariance (precision) using a saddle-point (KKT) system.
- Parameters:
operator – The linear part of the mapping (A).
translation – The translation vector (b).
affine_operator – An AffineOperator instance (cannot be used with operator or translation).
inverse_solver – A solver used to evaluate the KKT inverse covariance.
inverse_preconditioner – A preconditioner for the inverse_solver.
- Returns:
A new GaussianMeasure representing the push-forward distribution.
- Raises:
ValueError – If mutually exclusive arguments are provided, or if an inverse solve is requested but the prior lacks an inverse covariance.
- ambient_ball(probability: float, /, **kwargs)[source]¶
Shortcut for
credible_set(..., geometry='ambient_ball', ...).
- as_multivariate_normal(*, parallel: bool = False, n_jobs: int = -1) <scipy.stats._multivariate.multivariate_normal_gen object at 0x7d8aa0531940>[source]¶
Returns the measure as a scipy.stats.multivariate_normal object.
- Parameters:
parallel – If True, evaluates the dense covariance matrix concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A frozen scipy.stats.multivariate_normal object.
- Raises:
NotImplementedError – If the measure is not defined on a EuclideanSpace.
- property covariance: LinearOperator¶
The covariance operator of the measure.
- property covariance_factor: LinearOperator¶
The covariance factor L. Raises AttributeError if not set.
- property covariance_factor_set: bool¶
True if a covariance factor L (such that C = L @ L*) is available.
- credible_set(probability: float, /, *, geometry: str = 'ellipsoid', rank: int | None = None, open_set: bool = False, theta: float | None = None, spectrum=None, spectrum_size: int | None = None, radius_method: str = 'auto', quantile_method: str = 'auto', quantile_tol: float = 0.01, fractional_apply: str = 'auto', n_samples: int = 10000, lanczos_size_estimate: int = 50, lanczos_method: Literal['variable', 'fixed'] = 'fixed', lanczos_max_k: int | None = None, lanczos_rtol: float = 0.001, lanczos_atol: float = 1e-08, lanczos_check_interval: int = 5, spectrum_low_rank_kwargs: dict | None = None, rng: Generator | None = None)[source]¶
Return a probability-calibrated Gaussian credible subset.
Five geometries are supported:
"ellipsoid"/"mahalanobis"/"domain"The classical Mahalanobis ellipsoid.
"cameron_martin"/"cm"/"ball"/"norm_ball"The ellipsoid expressed as a unit ball in the Cameron-Martin geometry.
"ambient_ball"/"ambient"The ambient norm ball ${m : |m - m_0|_H le r_p}$.
"weakened_ellipsoid"/"fractional"The weakened-covariance ellipsoid ${m : |C^{-theta/2}(m-m_0)|_H le r_p}$.
- Parameters:
probability – Credible probability $p$, strictly between 0 and 1.
geometry – Selects the ball/ellipsoid family (see above).
rank – Chi-square degrees of freedom (legacy modes only).
open_set – If true, return the open version of the set.
theta – Fractional exponent in $(0, 1)$, required for weakened_ellipsoid.
spectrum – Covariance spectrum specification.
spectrum_size – Truncation length when
spectrumis callable orNone.radius_method –
"auto","spectral", or"sampling".quantile_method – Weighted-chi-square quantile method.
quantile_tol – Desired relative accuracy of the weighted-chi-square quantile.
fractional_apply – How to apply $C^{-theta/2}$ for the weakened ellipsoid.
n_samples – Monte Carlo sample count for sampling radius.
lanczos_size_estimate – Initial or fixed Krylov dimension for Lanczos fractional evaluation.
lanczos_method – ‘fixed’ or ‘variable’ dynamic convergence for Lanczos.
lanczos_max_k – Maximum Krylov dimension if ‘variable’ is used.
lanczos_rtol – Relative tolerance for Lanczos convergence.
lanczos_atol – Absolute tolerance for Lanczos convergence.
lanczos_check_interval – Number of iterations between Lanczos convergence checks.
spectrum_low_rank_kwargs – Extra kwargs forwarded to
LowRankEig.from_randomized.rng – Optional NumPy generator for Monte Carlo paths.
- Returns:
An Ellipsoid or Ball defining the credible subset.
- deflated_pointwise_std(rank: int, /, *, size_estimate: int = 0, method: str = 'variable', max_samples: int = None, rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise standard deviation field using a deflated Hutchinson’s method.
- Parameters:
rank – The rank of the deterministic SVD deflation.
size_estimate – The initial number of stochastic residual samples.
method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on stochastic residual samples.
rtol – Relative tolerance for the stochastic residual phase.
block_size – Number of samples added per check in the ‘variable’ method.
parallel – If True, draws stochastic samples in parallel.
n_jobs – The number of CPU cores to use.
- Returns:
A vector representing the pointwise standard deviation field.
- deflated_pointwise_variance(rank: int, /, *, size_estimate: int = 0, method: str = 'variable', max_samples: int = None, rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise variance field using a deflated Hutchinson’s method.
This combines a deterministic low-rank extraction (via SVD deflation) with a stochastic Hutchinson trace estimator for the residual variance.
- Parameters:
rank – The rank of the deterministic SVD deflation.
size_estimate – The initial number of stochastic residual samples.
method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on stochastic residual samples.
rtol – Relative tolerance for the stochastic residual phase.
block_size – Number of samples added per check in the ‘variable’ method.
parallel – If True, draws stochastic samples in parallel.
n_jobs – The number of CPU cores to use.
- Returns:
A vector representing the pointwise variance field.
- Raises:
NotImplementedError – If the domain is not a HilbertModule.
- directional_covariance(d1: Vector, d2: Vector, /) float[source]¶
Returns the covariance between the scalar projections <x, d1> and <x, d2>.
- Parameters:
d1 – The first test vector.
d2 – The second test vector.
- Returns:
The covariance scalar.
- directional_statistics(direction: Vector, /) Tuple[float, float][source]¶
Returns the expectation and variance of the scalar Gaussian <x, direction>.
- Parameters:
direction – The test vector.
- Returns:
A tuple containing (expectation, variance).
- directional_variance(d: Vector, /) float[source]¶
Returns the variance of the scalar projection <x, d>.
- Parameters:
d – The test vector.
- Returns:
The variance scalar.
- property domain: HilbertSpace¶
The Hilbert space the measure is defined on.
- property expectation: Vector¶
The expectation (mean) vector of the measure.
- static from_covariance_matrix(domain: HilbertSpace, covariance_matrix: np.ndarray, /, *, expectation: Vector = None, rtol: float = 1e-10) GaussianMeasure[source]¶
Creates a Gaussian measure from a dense covariance matrix.
- Parameters:
domain – The Hilbert space on which the measure is defined.
covariance_matrix – A 2D symmetric positive semi-definite NumPy array.
expectation – The mean vector. Defaults to the zero vector.
rtol – Relative tolerance for clipping small negative eigenvalues caused by floating-point inaccuracies.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the matrix has significantly negative eigenvalues.
- static from_direct_sum(measures: List[GaussianMeasure], /) GaussianMeasure[source]¶
Constructs a product measure from a list of other measures.
The resulting measure resides on the direct sum of the input domains, with block-diagonal covariance and concatenated expectations.
- Parameters:
measures – A list of GaussianMeasure instances.
- Returns:
A new GaussianMeasure instance defined on the direct sum space.
- static from_samples(domain: HilbertSpace, samples: List[Vector], /) GaussianMeasure[source]¶
Estimates a Gaussian measure from a collection of sample vectors.
Constructs an empirical mean and an unnormalized sample covariance operator using a tensor product expansion.
- Parameters:
domain – The Hilbert space the samples belong to.
samples – A list of sample vectors.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the list of samples is empty.
- static from_standard_deviation(domain: HilbertSpace, standard_deviation: float, /, *, expectation: Vector = None) GaussianMeasure[source]¶
Creates an isotropic Gaussian measure with a scaled identity covariance.
- Parameters:
domain – The Hilbert space on which the measure is defined.
standard_deviation – The uniform standard deviation for all dimensions.
expectation – The mean vector. Defaults to the zero vector.
- Returns:
A new GaussianMeasure instance.
- static from_standard_deviations(domain: HilbertSpace, standard_deviations: np.ndarray, /, *, expectation: Vector = None) GaussianMeasure[source]¶
Creates a Gaussian measure with a diagonal covariance operator.
- Parameters:
domain – The Hilbert space on which the measure is defined.
standard_deviations – A 1D NumPy array representing the diagonal entries of the covariance factor.
expectation – The mean vector. Defaults to the zero vector.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the size of the array does not match the space dimension.
- property has_zero_expectation: bool¶
True if the measure is internally stored with an exactly zero expectation.
- property inverse_covariance: LinearOperator¶
The inverse covariance (precision) operator. Raises AttributeError if not set.
- property inverse_covariance_factor: LinearOperator¶
The inverse covariance factor. Raises AttributeError if not set.
- property inverse_covariance_factor_set: bool¶
True if an inverse covariance factor is available.
- property inverse_covariance_set: bool¶
True if the inverse covariance (precision) operator is available.
- kl_divergence(other: GaussianMeasure, /, *, method: Literal['dense', 'randomized'] = 'dense', hutchinson_size_estimate: int = 10, hutchinson_method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_size_estimate: int = 40, lanczos_method: Literal['variable', 'fixed'] = 'variable', lanczos_max_k: int | None = None, lanczos_rtol: float = 0.001, lanczos_atol: float = 1e-08, lanczos_check_interval: int = 5, parallel: bool = False, n_jobs: int = -1) float[source]¶
Computes the exact or approximate Kullback-Leibler (KL) divergence D_KL(self || other).
This calculates the divergence of ‘self’ (P) from the prior/reference measure ‘other’ (Q).
- Parameters:
other – The reference GaussianMeasure (Q).
method – ‘dense’ uses exact dense matrix factorizations (O(N^3)). ‘randomized’ uses matrix-free Stochastic Lanczos Quadrature (SLQ).
hutchinson_size_estimate – Initial samples for the randomized trace estimator.
hutchinson_method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on Hutchinson samples.
rtol – Relative tolerance for the Hutchinson estimator.
block_size – Samples added per check in the ‘variable’ Hutchinson method.
lanczos_size_estimate – Initial Krylov dimension for fractional evaluations.
lanczos_method – ‘variable’ or ‘fixed’ convergence for Lanczos.
lanczos_max_k – Maximum Krylov dimension if ‘variable’ is used.
lanczos_rtol – Relative tolerance for Lanczos convergence.
lanczos_atol – Absolute tolerance for Lanczos convergence.
lanczos_check_interval – Iterations between Lanczos convergence checks.
parallel – If True, evaluates the stochastic probes concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The calculated KL divergence.
- Raises:
ValueError – If the measures reside on different domains, or if the ‘randomized’ method is called without an inverse covariance on the reference measure.
- low_rank_approximation(size_estimate: int, /, *, method: str = 'variable', max_rank: int = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Constructs a low-rank approximation of the measure.
Uses randomized matrix-free algorithms to factorize the covariance.
- Parameters:
size_estimate – Target rank or initial sample size for the algorithm.
method – ‘variable’ to sample dynamically, ‘fixed’ otherwise.
max_rank – Upper limit on rank for the ‘variable’ method.
power – Number of power iterations to enhance spectral decay.
rtol – Relative tolerance for the ‘variable’ method.
block_size – Samples drawn per iteration in the ‘variable’ method.
parallel – If True, parallelizes the evaluations.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure backed by a LowRankCholesky covariance factor.
- rescale_directional_variance(direction: Vector, std: float, /) GaussianMeasure[source]¶
Returns a new measure where Var[<x, direction>] is scaled to std^2.
- Parameters:
direction – The test vector to scale against.
std – The target standard deviation for the projection.
- Returns:
A variance-scaled GaussianMeasure.
- Raises:
ValueError – If the current directional variance is zero or negative.
- sample() Vector[source]¶
Returns a single random sample drawn from the measure.
- Returns:
A randomly sampled vector.
- Raises:
NotImplementedError – If a sample method is not set for this measure.
- sample_expectation(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the expectation vector by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use for the estimation.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
The empirical expectation vector.
- sample_pointwise_std(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise standard deviation field by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A vector representing the pointwise standard deviation field.
- sample_pointwise_variance(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise variance field by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A vector representing the pointwise variance field.
- Raises:
NotImplementedError – If the domain is not a HilbertModule (which provides pointwise multiplication).
- property sample_set: bool¶
True if a method for drawing random samples is available.
- samples(n: int, /, *, parallel: bool = False, n_jobs: int = -1) List[Vector][source]¶
Returns a list of n independent random samples from the measure.
- Parameters:
n – The number of samples to draw.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A list of sampled vectors.
- Raises:
ValueError – If n is less than 1.
- two_point_covariance(point: Any, /) Vector[source]¶
Computes the two-point covariance function radiating from a specific point.
- Parameters:
point – The spatial coordinate to evaluate from.
- Returns:
The covariance field evaluated at the chosen point.
- Raises:
NotImplementedError – If the domain lacks a dirac_representation method.
- weakened_ellipsoid(probability: float, /, *, theta: float, **kwargs)[source]¶
Shortcut for the weakened-covariance ellipsoid mode.
- with_dense_covariance(*, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Forms a new Gaussian measure equivalent to the existing one, but with its covariance matrix stored explicitly in dense form.
- Parameters:
parallel – If True, computes the dense matrix concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure instance backed by a dense matrix.
- with_regularized_inverse(solver: LinearSolver, /, *, damping: float = 0.0, preconditioner: LinearOperator | None = None) GaussianMeasure[source]¶
Returns a new GaussianMeasure with a well-defined precision operator (inverse covariance) computed via Tikhonov regularization.
- Parameters:
solver – The linear solver used to invert the covariance.
damping – Tikhonov regularization parameter added to the diagonal.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A new GaussianMeasure instance equipped with an inverse covariance.
- Raises:
ValueError – If the damping parameter is negative.
- with_sparse_approximation(*, threshold: float = 0.001, max_nnz: int | None = None, diag_rank: int = 0, diag_samples: int = 0, regularization_fraction: float = 0.0001, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Creates an approximately equivalent measure with a sparse covariance matrix and an exactly factorized sparse inverse, built entirely matrix-free.
- Parameters:
threshold – Minimum correlation required to keep an off-diagonal element.
max_nnz – Maximum number of non-zero elements allowed per column.
diag_rank – Rank of deterministic SVD used to estimate the diagonal.
diag_samples – Number of stochastic samples used to estimate the diagonal.
regularization_fraction – Tikhonov regularization applied before sparse inversion.
parallel – If True, computes the sparse approximations concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure backed by sparse operators.
- zero_expectation() GaussianMeasure[source]¶
Returns a new measure with the same covariance, but zero expectation.
- Returns:
A mean-shifted GaussianMeasure.
pygeoinf.hilbert_space module¶
Defines the foundational abstractions for working with Hilbert spaces.
This module provides the core HilbertSpace abstract base class (ABC), which serves as a mathematical abstraction for real vector spaces equipped with an inner product. The design separates abstract vector operations from their concrete representations (e.g., as NumPy arrays), allowing for generic and reusable implementations of linear operators and algorithms.
The inner product of a space is defined by its Riesz representation map (to_dual and from_dual methods), which connects the space to its dual. Concrete subclasses must implement the abstract methods to define a specific type of space.
Key Classes¶
HilbertSpace: The primary ABC defining the interface for all Hilbert spaces.
DualHilbertSpace: A wrapper class representing the dual of a Hilbert space.
HilbertModule: An ABC for Hilbert spaces that also support vector multiplication.
EuclideanSpace: A concrete implementation for R^n using NumPy arrays.
MassWeightedHilbertSpace: A space whose inner product is weighted by a mass operator relative to an underlying space.
- class pygeoinf.hilbert_space.DualHilbertSpace(space: HilbertSpace)[source]¶
Bases:
HilbertSpaceA wrapper class representing the dual of a HilbertSpace.
An element of a dual space is a continuous linear functional, represented in this library by the LinearForm class. This wrapper provides a full HilbertSpace interface for these LinearForm objects, allowing them to be treated as vectors in their own right.
- property dim: int¶
The dimension of the dual space.
- property dual: HilbertSpace¶
The dual of the dual space, which is the original primal space.
- final duality_product(xp: LinearForm, x: Vector) float[source]¶
Computes the duality product <x, xp>.
In this context, x is from the primal space and xp is the dual vector (a LinearForm). This is unconventional but maintains the method signature; it evaluates x(xp).
- from_components(c: np.ndarray) LinearForm[source]¶
Creates a LinearForm from a NumPy component array.
- from_dual(xp: Vector) LinearForm[source]¶
Maps a primal vector to its corresponding dual LinearForm.
- to_components(x: LinearForm) np.ndarray[source]¶
Maps a LinearForm to its NumPy component array.
- to_dual(x: LinearForm) Any[source]¶
Maps a dual vector back to its representative in the primal space.
- property underlying_space: HilbertSpace¶
The primal HilbertSpace of which this is the dual.
- class pygeoinf.hilbert_space.EuclideanSpace(dim: int)[source]¶
Bases:
HilbertSpaceAn n-dimensional Euclidean space, R^n.
This is a concrete HilbertSpace where vectors are represented directly by NumPy arrays, and the inner product is the standard dot product.
- property dim: int¶
The dimension of the space.
- from_components(c: ndarray) ndarray[source]¶
Returns the component array itself, as it is the vector.
- from_dual(xp: LinearForm) np.ndarray[source]¶
Maps a LinearForm back to a vector via its components.
- inner_product(x1: ndarray, x2: ndarray) float[source]¶
Computes the inner product of two vectors.
Notes
Default implementation overrident for efficiency.
- subspace_projection(indices: int | List[int]) LinearOperator[source]¶
Returns a projection operator onto specified coordinates.
This creates a linear operator that extracts the components at the given indices, projecting from this space to a lower-dimensional Euclidean space.
- Parameters:
indices – Single index or list of indices to project onto (0-indexed).
- Returns:
LinearOperator from this space to EuclideanSpace(len(indices)).
- Raises:
IndexError – If any index is out of range for this space’s dimension.
- to_components(x: ndarray) ndarray[source]¶
Returns the vector itself, as it is already a component array.
- to_dual(x: np.ndarray) LinearForm[source]¶
Maps a vector x to a LinearForm with the same components.
- class pygeoinf.hilbert_space.HilbertModule[source]¶
Bases:
HilbertSpace,ABCAn ABC for a HilbertSpace where vector multiplication is defined.
This acts as a “mixin” interface, adding the vector_multiply requirement to the HilbertSpace contract.
- class pygeoinf.hilbert_space.HilbertSpace[source]¶
Bases:
ABC,HilbertSpaceAxiomChecksAn abstract base class for real Hilbert spaces.
This class provides a mathematical abstraction for a vector space equipped with an inner product. It defines a formal interface that separates abstract vector operations from their concrete representation (e.g., as NumPy arrays). Subclasses must implement all abstract methods to be instantiable.
- axpy(a: float, x: Vector, y: Vector) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- final basis_vector(i: int) Vector[source]¶
Returns the i-th standard basis vector.
This is the vector whose component array is all zeros except for a one at index i.
- Parameters:
i – The index of the basis vector.
- Returns:
The i-th basis vector.
- property coordinate_inclusion: LinearOperator¶
The linear operator mapping R^n component vectors into this space.
- property coordinate_projection: LinearOperator¶
The linear operator projecting vectors from this space to R^n.
- abstract property dim: int¶
The finite dimension of the space.
- property dual: HilbertSpace¶
The dual of this Hilbert space.
The dual space is the space of all continuous linear functionals (i.e., LinearForm objects) that map vectors from this space to real numbers. This implementation returns a DualHilbertSpace wrapper.
- duality_product(xp: LinearForm, x: Vector) float[source]¶
Computes the duality product <xp, x>.
This evaluates the linear functional xp (an element of the dual space) at the vector x (an element of the primal space).
- Parameters:
xp – The linear functional from the dual space.
x – The vector from the primal space.
- Returns:
The result of the evaluation xp(x).
- abstract from_components(c: ndarray) Vector[source]¶
Maps a NumPy component array back to a vector in the space.
- Parameters:
c – The components of the vector as a NumPy array.
- Returns:
The corresponding vector in the space.
- abstract from_dual(xp: Any) Vector[source]¶
Maps a dual vector back to its representative in the primal space.
This is the inverse of the Riesz representation map defined by to_dual.
- Parameters:
xp – A vector in the dual space.
- Returns:
The corresponding vector in the primal space.
- final gram_schmidt(vectors: List[Vector]) List[Vector][source]¶
Orthonormalizes a list of vectors using the Gram-Schmidt process.
- Parameters:
vectors – A list of linearly independent vectors.
- Returns:
A list of orthonormalized vectors spanning the same subspace.
- Raises:
ValueError – If not all items in the list are elements of the space.
- final identity_operator() LinearOperator[source]¶
Returns the identity operator I on the space.
- inner_product(x1: Vector, x2: Vector) float[source]¶
Computes the inner product of two vectors, (x1, x2).
This is defined via the duality product as <R(x1), x2>, where R is the Riesz map (to_dual).
- Parameters:
x1 – The first vector.
x2 – The second vector.
- Returns:
The inner product as a float.
- property inverse_riesz: LinearOperator¶
The inverse Riesz map (primal to dual) as a LinearOperator.
- is_element(x: Any) bool[source]¶
Checks if an object is a valid element of the space.
Note: The default implementation checks the object’s type against the type of the zero vector. This may not be robust for all vector representations and can be overridden if needed.
- Parameters:
x – The object to check.
- Returns:
True if the object is an element of the space, False otherwise.
- final norm(x: Vector) float[source]¶
Computes the norm of a vector, ||x||.
- Parameters:
x – The vector.
- Returns:
The norm of the vector.
- random() Vector[source]¶
Generates a random vector from the space.
The vector’s components are drawn from a standard normal distribution.
- Returns:
A new random vector.
- property riesz: LinearOperator¶
The Riesz map (dual to primal) as a LinearOperator.
- final sample_expectation(vectors: List[Vector]) Vector[source]¶
Computes the sample mean of a list of vectors.
- Parameters:
vectors – A list of vectors from the space.
- Returns:
The sample mean (average) vector.
- Raises:
TypeError – If not all items in the list are elements of the space.
- final squared_norm(x: Vector) float[source]¶
Computes the squared norm of a vector, ||x||^2.
- Parameters:
x – The vector.
- Returns:
The squared norm of the vector.
- subtract(x: Vector, y: Vector) Vector[source]¶
Computes the difference of two vectors. Defaults to x - y.
- abstract to_components(x: Vector) ndarray[source]¶
Maps a vector to its representation as a NumPy component array.
- Parameters:
x – A vector in the space.
- Returns:
The components of the vector as a NumPy array.
- abstract to_dual(x: Vector) Any[source]¶
Maps a vector to its canonical dual vector (a linear functional).
This method, along with from_dual, defines the Riesz representation map and implicitly defines the inner product of the space.
- Parameters:
x – A vector in the primal space.
- Returns:
The corresponding vector in the dual space.
- property zero: Vector¶
The zero vector (additive identity) of the space.
- final zero_operator(codomain: HilbertSpace | None = None) LinearOperator[source]¶
Returns the zero operator 0 from this space to a codomain.
- Parameters:
codomain – The target space of the operator. If None, the operator maps to this space itself.
- Returns:
The zero linear operator.
- class pygeoinf.hilbert_space.MassWeightedHilbertModule(underlying_space: HilbertModule, mass_operator: LinearOperator, inverse_mass_operator: LinearOperator)[source]¶
Bases:
MassWeightedHilbertSpace,HilbertModuleA mass-weighted Hilbert space that also supports vector multiplication.
This class inherits the mass-weighted inner product structure and mixes in the HilbertModule interface, delegating the multiplication operation to the underlying space.
- class pygeoinf.hilbert_space.MassWeightedHilbertSpace(underlying_space: HilbertSpace, mass_operator: LinearOperator, inverse_mass_operator: LinearOperator)[source]¶
Bases:
HilbertSpaceA Hilbert space with an inner product weighted by a mass operator.
This class wraps an existing HilbertSpace (let’s call it X) and defines a new inner product for a space (Y) as: (u, v)_Y = (M @ u, v)_X, where M is a self-adjoint, positive-definite mass operator defined on X.
This is a common construction in numerical methods like the Finite Element Method, where the basis functions are not orthonormal.
- axpy(a: float, x: Vector, y: Vector) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- property dim: int¶
The dimension of the space.
- from_dual(xp: LinearForm) Vector[source]¶
Computes the inverse dual mapping R_Y^{-1}(xp) = M^{-1} R_X^{-1}(xp).
- inner_product(x1: Vector, x2: Vector) float[source]¶
Computes the inner product of two vectors.
Notes
Default implementation overrident for efficiency.
- property inverse_mass_operator: LinearOperator¶
The inverse of the mass operator.
- property mass_operator: LinearOperator¶
The mass operator (M) defining the weighted inner product.
- subtract(x: Vector, y: Vector) Vector[source]¶
Computes the difference of two vectors. Defaults to x - y.
- to_dual(x: Vector) LinearForm[source]¶
Computes the dual mapping R_Y(x) = R_X(M x).
- property underlying_space: HilbertSpace¶
The underlying Hilbert space (X) without mass weighting.
- property zero: Vector¶
The zero vector (additive identity) of the space.
pygeoinf.inversion module¶
Provides the abstract base class for all inversion algorithms.
This module defines the Inversion class, which serves as a common foundation for various methods that solve an inverse problem. Its primary role is to maintain a reference to the ForwardProblem being solved, providing a consistent interface and convenient access to the problem’s core components like the model space and data space.
It also includes helper methods to assert preconditions required by different inversion techniques, such as the existence of a data error measure.
- class pygeoinf.inversion.Inference(forward_problem: ForwardProblem, property_operator: NonLinearOperator)[source]¶
Bases:
InversionA base class for inference algorithms. These methods inherit common functionality from the inversion base class, but need not themselves derive from a specific inversion scheme.
Within an inference problem, the aim is to estimate some property of the unknown model, and hence a property operator mapping from the model to a property space must be specified.
- property property_operator: NonLinearOperator¶
Returns the property operator.
- property property_space: HilbertSpace¶
Returns the property space.
- class pygeoinf.inversion.Inversion(forward_problem: ForwardProblem, /)[source]¶
Bases:
objectA base class for inversion methods.
This class provides a common structure for different inversion and inference algorithms (e.g., Bayesian, Least Squares). Its main purpose is to hold a reference to the forward problem being solved and provide convenient access to its properties. Subclasses should inherit from this class to implement a specific inversion algorithm.
- assert_data_error_measure() None[source]¶
Checks if a data error measure is set in the forward problem.
This is a precondition for statistical inversion methods.
- Raises:
AttributeError – If no data error measure has been set.
- assert_inverse_data_covariance() None[source]¶
Checks if the data error measure has an inverse covariance.
This is a precondition for methods that require the data precision matrix (the inverse of the data error covariance).
- Raises:
AttributeError – If no data error measure is set, or if the measure does not have an inverse covariance operator defined.
- property data_space: HilbertSpace¶
The data space (codomain) of the forward problem.
- property forward_problem: ForwardProblem¶
The forward problem associated with this inversion.
- property model_space: HilbertSpace¶
The model space (domain) of the forward problem.
- class pygeoinf.inversion.LinearInference(forward_problem: LinearForwardProblem, property_operator: LinearOperator)[source]¶
Bases:
InferenceA base class for linear inference algorithms.
- class pygeoinf.inversion.LinearInversion(forward_problem: LinearForwardProblem, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
InversionAn abstract base class for linear inversion algorithms.
- data_measure_from_model(model: Vector) GaussianMeasure[source]¶
Returns the Gaussian measure for the data, given a specific model.
- data_measure_from_model_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the induced measure on the data space.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearInversion[source]¶
Constructs a surrogate of the linear inversion using a reduced data space.
- Parameters:
reduction_operator – A LinearOperator mapping from the current data space to the new, reduced data space.
reduced_data_error_measure – An optional data error measure defined on the reduced data space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion.
- Returns:
A new instance of the concrete inversion class operating on the reduced data space.
- property formalism: Literal['model_space', 'data_space']¶
The algebraic space in which the normal equations are assembled and solved.
- joint_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the joint measure for the model and data.
- parameterized_inversion(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearInversion[source]¶
Constructs a parameterized surrogate of the linear inversion.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
dense – If True, computes and stores the parameterized forward operator as a dense matrix in memory.
parallel – If True, computes the dense matrix in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new instance of the concrete inversion class operating on the parameter space.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearInversion[source]¶
Returns a new instance of the inversion using the specified formalism.
pygeoinf.linear_bayesian module¶
Implements the Bayesian framework for solving linear inverse problems.
This module treats the inverse problem from a statistical perspective. Rather than seeking a single deterministic “best-fit” solution, it aims to determine the full posterior probability distribution of the unknown model parameters given the observed data, prior knowledge, and noise statistics.
A core feature of this module is its dual algebraic formalism, allowing users to optimize computational efficiency based on the problem geometry:
data_space: Assembles the data-space normal operator (size M x M, where M is the data dimension). Normal Operator: N = A Q A* + R Kalman Gain: K = Q A* N^-1 Best suited for underdetermined problems (M << N).
model_space: Assembles the model-space normal operator (size N x N, where N is the model dimension). Normal Operator: N = Q^-1 + A* R^-1 A Kalman Gain: K = N^-1 A* R^-1 Best suited for overdetermined problems (N << M).
Key Classes¶
LinearBayesianInversion: Computes the posterior Gaussian measure p(u|d) for the model u given observed data d.
- class pygeoinf.linear_bayesian.LinearBayesianInversion(forward_problem: LinearForwardProblem, model_prior_measure: GaussianMeasure, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem using Bayesian methods.
This class applies to problems of the form d = A(u) + e, where u is a Gaussian random variable representing the model prior, and e is a Gaussian random variable representing observation noise.
It computes the exact posterior Gaussian measure p(u|d), providing access to the posterior expectation, the posterior covariance operator, and an efficient exact-sampling mechanism using the randomize-then-optimize technique.
- property data_prior_measure: GaussianMeasure¶
The prior predictive distribution on the data space. This represents the expected distribution of data before observation.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate of the Bayesian inversion using a reduced data space.
- Parameters:
reduction_operator – A LinearOperator mapping from the current data space to the new, reduced data space.
reduced_data_error_measure – An optional data error measure defined on the reduced data space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion.
- Returns:
A new LinearBayesianInversion instance operating on the reduced data space.
- diagonal_normal_preconditioner(*, blocks: List[List[int]] | None = None, parallel: bool = False, n_jobs: int = -1) LinearOperator[source]¶
Constructs a diagonal preconditioner specifically for the data-space Bayesian normal operator (A Q A* + R).
This exploits the identity <v, A Q A* v> = <A* v, Q A* v>. If blocks of data indices are provided, it acts on the averaged basis vector for each block to compute a robust representative regional variance, requiring only one adjoint action of the forward operator per block.
- Parameters:
blocks – An optional list of lists, where each sub-list contains indices of data points grouped together. Must perfectly partition the data space.
parallel – If True, computes the adjoint actions in parallel.
n_jobs – Number of parallel jobs to use. -1 means all available cores.
- Returns:
A DiagonalSparseMatrixLinearOperator representing the inverse of the approximated normal operator.
- Raises:
ValueError – If the inversion was initialized with formalism=’model_space’, as this preconditioner is mathematically invalid for that normal operator.
- estimate_log_determinant(*, operator_type: Literal['data_space', 'model_space'] = 'data_space', size_estimate: int = 10, method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_degree: int = 40, lanczos_rtol: float | None = 0.001, parallel: bool = False, n_jobs: int = -1) float[source]¶
Estimates the log-determinant of the Bayesian normal operator using Stochastic Lanczos Quadrature (SLQ).
This acts as a public interface for computing the log-determinant of either the data-space normal operator (A Q A* + R) or the model-space normal operator (Q^-1 + A* R^-1 A). It securely resolves the correct algebraic space and delegates to the internal matrix-free SLQ engine.
- Parameters:
operator_type – The target normal operator (‘data_space’ or ‘model_space’).
size_estimate – Initial number of Hutchinson samples (probe vectors).
method – ‘variable’ to sample until ‘rtol’ is met, ‘fixed’ otherwise.
max_samples – Hard limit on the number of Hutchinson samples.
rtol – Relative tolerance for the Hutchinson trace estimate.
block_size – Number of new samples per iteration in the ‘variable’ method.
lanczos_degree – Maximum Krylov dimension (k) per probe vector.
lanczos_rtol – Relative tolerance for dynamic Lanczos truncation. If None, uses fixed ‘lanczos_degree’ steps.
parallel – If True, evaluates probe vectors in parallel.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The estimated log-determinant ln(|N|).
- Return type:
float
- get_normal_equations_rhs(data: Vector) Vector[source]¶
Computes the exact right-hand side vector (v) of the normal equations N * w = v for a given observed data vector, automatically accounting for non-zero prior and noise expectations.
- property joint_prior_measure: GaussianMeasure¶
The joint prior distribution of both the model and the data.
- kalman_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) LinearOperator[source]¶
Constructs the Kalman gain operator K.
The Kalman gain maps data residuals to model space updates.
For ‘data_space’: K = Q A* (A Q A* + R)^-1 For ‘model_space’: K = (Q^-1 + A* R^-1 A)^-1 A* R^-1
- Parameters:
solver – The LinearSolver used to invert the normal operator.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A LinearOperator representing the Kalman gain.
- log_evidence(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None, size_estimate: int = 10, method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_degree: int = 40, lanczos_rtol: float | None = 0.001, parallel: bool = False, n_jobs: int = -1) float[source]¶
Computes the approximate log marginal likelihood (evidence) of the data, ln(p(d)).
The log-evidence is a critical metric for Bayesian model selection, allowing users to quantitatively compare different prior assumptions or forward models. It evaluates the likelihood of the observed data marginalized over all possible model states.
- The computation evaluates the Gaussian marginal density equation:
ln p(d) = -0.5 * [ ln|N_d| + <v, N_d^-1 v> + M * ln(2*pi) ]
- Parameters:
data – The observed data vector ‘d’.
solver – The LinearSolver used to invert the normal operator for the Mahalanobis misfit term.
preconditioner – Optional preconditioner for the iterative solver.
size_estimate – Initial number of SLQ Hutchinson samples.
method – ‘variable’ to dynamically bound SLQ error, ‘fixed’ otherwise.
max_samples – Hard limit on SLQ Hutchinson samples.
rtol – Relative tolerance for the SLQ trace estimate.
block_size – Number of new SLQ samples per iteration.
lanczos_degree – Maximum Krylov dimension for SLQ.
lanczos_rtol – Relative tolerance for dynamic Lanczos truncation.
parallel – If True, evaluates SLQ probe vectors in parallel.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The estimated log-evidence ln(p(d)).
- Return type:
float
- Raises:
ValueError – If the ‘model_space’ formalism is used but no data error measure has been set on the forward problem.
- low_rank_surrogate(*, forward_rank: int | None = None, prior_rank: int | None = None, data_error_rank: int | None = None, forward_kwargs: dict | None = None, prior_kwargs: dict | None = None, data_error_kwargs: dict | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate Bayesian inversion problem by replacing the exact physics and statistical measures with their low-rank approximations.
This method generates computationally cheap surrogate models to be used in constructing preconditioners for massive, ill-conditioned inverse problems (e.g., using spectral or banded methods). The low-rank approximations are computed using randomized SVD and eigendecomposition algorithms.
- Parameters:
forward_rank – Target rank for the randomized SVD of the forward operator.
prior_rank – Target rank for the randomized eigendecomposition of the prior.
data_error_rank – Target rank for the randomized eigendecomposition of the noise.
forward_kwargs – Additional kwargs passed directly to LinearOperator.random_svd.
prior_kwargs – Additional kwargs passed directly to GaussianMeasure.low_rank_approximation.
data_error_kwargs – Additional kwargs passed directly to GaussianMeasure.low_rank_approximation.
- Returns:
A LinearBayesianInversion representing the low-rank surrogate problem.
- mahalanobis_evidence_term(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) float[source]¶
Computes the data-dependent Mahalanobis term of the log-evidence.
This value represents the optimal, penalty-balanced data misfit. It is equivalent to the unnormalized log-posterior evaluated at the posterior expectation.
Mathematically, for a shifted data residual vector v = d - A(mu_u) - mu_e, the term evaluates the quadratic form:
Misfit = <v, (A Q A* + R)^-1 v>
In the ‘model_space’ formalism, this is computed far more efficiently using the Woodbury matrix identity to bypass the massive data-space inversion:
Misfit = <v, R^-1 v> - <A* R^-1 v, (Q^-1 + A* R^-1 A)^-1 A* R^-1 v>
- Parameters:
data – The observed data vector ‘d’.
solver – The LinearSolver used to invert the normal operator.
preconditioner – An optional preconditioner to accelerate iterative solvers.
- Returns:
The scalar Mahalanobis distance.
- Return type:
float
- Raises:
ValueError – If the forward problem lacks a defined data error measure.
- model_posterior_measure(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) GaussianMeasure[source]¶
Computes and returns the posterior Gaussian measure p(u|d).
This method applies the Kalman update equations to find the posterior expectation and covariance. If both the prior and data error measures have sampling enabled, it automatically constructs a randomize-then-optimize exact sampling function for the posterior.
- Parameters:
data – The observed data vector.
solver – A linear solver for inverting the normal operator.
preconditioner – An optional preconditioner for iterative solvers.
- Returns:
A GaussianMeasure representing the posterior distribution.
- property model_prior_measure: GaussianMeasure¶
The prior Gaussian measure on the model space.
- property normal_operator: LinearOperator¶
Constructs the Bayesian Normal operator for the chosen formalism.
For ‘data_space’: Returns N = A Q A* + R For ‘model_space’: Returns N = Q^-1 + A* R^-1 A
- Returns:
A LinearOperator representing the normal equations matrix.
- normal_residual_callback(data: Vector, /, *, message: str = 'CG Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True) ResidualTrackingCallback[source]¶
Generates a ResidualTrackingCallback pre-configured to track the convergence of the Bayesian normal equations for the given data vector.
- Parameters:
data – The observed data vector.
message – The formatting string for printing progress.
print_progress – If True, prints the message to stdout at each iteration.
- Returns:
A configured ResidualTrackingCallback ready to be passed to a solver.
- parameterized_inversion(parameterization: LinearOperator, /, *, parameter_prior: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearBayesianInversion[source]¶
Constructs a parameterized surrogate of the Bayesian inversion.
If the target formalism resolves to ‘model_space’ (which is typical for parameterized inversions), the parameter prior’s covariance matrix will be automatically densified to explicitly compute the required precision (inverse covariance) operator.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
parameter_prior – An optional prior measure on the parameter space. If not provided, the original model prior is pulled back to the parameter space automatically.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new LinearBayesianInversion instance operating on the parameter space.
- posterior_expectation_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) LinearOperator | AffineOperator[source]¶
Constructs the operator mapping observed data to the posterior expectation.
The mapping evaluates F(d) = mu_u + K(d - A(mu_u) - mu_e).
If the prior and data error measures both have a zero expectation, this mapping is purely linear and returns the Kalman gain operator directly. Otherwise, it regroups the terms into an AffineOperator: F(d) = K(d) + (mu_u - K(A(mu_u) + mu_e)).
- Parameters:
solver – The LinearSolver used to invert the normal operator.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A LinearOperator (if expectations are zero) or an AffineOperator.
- sparse_localized_preconditioner(interacting_blocks: list[list[int]], rank: int = 10, parallel: bool = False, n_jobs: int = -1) LinearOperator[source]¶
Builds a sparse preconditioner specifically for the data-space Bayesian normal equations using randomized Nystrom approximations on localized, potentially overlapping sub-blocks.
- Parameters:
interacting_blocks – A list of lists, where each sub-list contains the indices of data points that strongly couple to each other.
rank – The rank of the randomized Nystrom approximation to use per block.
parallel – If True, computes the sub-block approximations in parallel.
n_jobs – Number of CPU cores to use if parallel=True (-1 uses all cores).
- Returns:
A LinearOperator representing the inverse of the sparse approximation.
- Raises:
ValueError – If the inversion was initialized with formalism=’model_space’, as this preconditioner is mathematically invalid for that normal operator.
- surrogate_inversion(*, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate Bayesian inversion problem using simplified physics, priors, or data errors.
This is primarily used to construct robust, computationally cheap surrogate models to use as preconditioners for the full, complex inverse problem.
- Parameters:
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A new LinearBayesianInversion instance representing the surrogate problem. The surrogate inherits the formalism of the parent problem.
- Raises:
ValueError – If the alternative operators/measures exist in incompatible domains/codomains.
- surrogate_normal_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a preconditioner by exactly inverting the normal operator of a simplified surrogate inverse problem.
- Parameters:
solver – The LinearSolver to use to exactly invert the surrogate normal operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A LinearOperator representing the inverse of the surrogate normal equations.
- surrogate_woodbury_data_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None, prior_solver: LinearSolver | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Builds a data-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
This method chains the construction of the surrogate model with the extraction of the Woodbury inverse in one step.
Note
Ensure that any alternate measures provided have well-defined inverse covariances, or use .with_regularized_inverse() on them before passing them to this method.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
prior_solver – Optional solver for the prior covariance.
noise_solver – Optional solver for the noise covariance.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- surrogate_woodbury_model_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a model-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearBayesianInversion[source]¶
Returns a new instance of the Bayesian inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearBayesianInversion instance sharing the exact same forward problem and prior measure, but configured to use the specified formalism.
- woodbury_data_preconditioner(solver: LinearSolver, /, *, prior_solver: LinearSolver | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Constructs a data-space preconditioner using the Woodbury matrix identity.
Data Space Normal Operator: N_d = A Q A* + R Woodbury Identity: N_d^-1 = R^-1 - R^-1 A (Q^-1 + A* R^-1 A)^-1 A* R^-1
Note
This method assumes the prior (Q) and noise (R) measures either already have well-defined inverse covariances, or are well-conditioned enough to be inverted by the provided solvers. If your prior is an unbounded operator on a function space, use Q.with_regularized_inverse() before passing it to the inversion.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator (N_m).
prior_solver – An optional solver used to explicitly invert the prior covariance (Q) if its inverse is not already set. Defaults to solver if not provided.
noise_solver – An optional solver used to explicitly invert the data error covariance (R) if its inverse is not already set. Defaults to solver if not provided.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- woodbury_model_preconditioner(solver: LinearSolver, /) LinearOperator[source]¶
Constructs a model-space preconditioner using the Woodbury matrix identity.
Model Space Normal Operator: N_m = Q^-1 + A* R^-1 A Woodbury Identity: N_m^-1 = Q - Q A* (R + A Q A*)^-1 A Q
Note
Unlike the data-space Woodbury identity, this formulation does not require evaluating the explicit inverses of the prior (Q) or noise (R) covariances, making it highly robust for unbounded or complex measures.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator (N_d).
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
pygeoinf.linear_forms module¶
Provides the LinearForm class for representing linear functionals.
A linear form is a linear mapping from a vector in a Hilbert space to a scalar. This class provides a concrete, component-based representation for elements of the dual space of a HilbertSpace. It inherits from NonLinearForm, specializing it for the linear case.
- class pygeoinf.linear_forms.LinearForm(domain: HilbertSpace, /, *, components: np.ndarray | None = None, mapping: Callable[[Vector], float] | None = None, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
NonLinearFormRepresents a linear form as an efficient, component-based functional.
A LinearForm is an element of a dual HilbertSpace and is defined by its action on vectors from its domain. Internally, this action is represented by a component vector. This class provides optimized arithmetic operations and correctly defines the gradient (a constant vector) and the Hessian (the zero operator) for any linear functional.
- property as_linear_operator: LinearOperator¶
Represents the linear form as a LinearOperator.
The resulting operator maps from the form’s original domain to a 1-dimensional EuclideanSpace, where the single component of the output is the scalar result of the form’s action.
- property components: ndarray¶
The component vector of the form.
- copy() LinearForm[source]¶
Creates a deep copy of the linear form.
- property domain: HilbertSpace¶
The Hilbert space on which the form is defined.
- static from_linear_operator(operator: LinearOperator) LinearForm[source]¶
Creates a LinearForm from an operator that maps to a 1D Euclidean space.
pygeoinf.linear_operators module¶
Provides classes for linear operators between Hilbert spaces.
This module is the primary tool for defining and manipulating linear mappings between HilbertSpace objects. It provides a powerful LinearOperator class that supports a rich algebra and includes numerous factory methods for convenient construction from matrices, forms, or tensor products.
Key Classes¶
LinearOperator: The main workhorse for linear algebra. It represents a linear map L(x) = Ax and provides rich functionality, including composition (@), adjoints (.adjoint), duals (.dual), and matrix representations (.matrix).
DiagonalLinearOperator: A specialized, efficient implementation for linear operators that are diagonal in their component representation, notable for supporting functional calculus (e.g., .inverse, .sqrt).
- class pygeoinf.linear_operators.DenseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray, /, *, galerkin=False)[source]¶
Bases:
MatrixLinearOperatorA specialisation of the MatrixLinearOperator class to instances where the matrix representation is always provided as a numpy array.
This is a class provides some additional methods for component-wise access.
- static from_linear_operator(operator: LinearOperator, /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) DenseMatrixLinearOperator[source]¶
Converts a LinearOperator into a DenseMatrixLinearOperator by forming its dense matrix representation.
- Parameters:
operator – The operator to be converted.
galerkin – If True, the Galerkin representation is used. Default is False.
parallel – If True, dense matrix calculation is done in parallel. Default is False.
n_jobs – Number of jobs used for parallel calculations. Default is False.
- class pygeoinf.linear_operators.DiagonalSparseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, diagonals: Tuple[np.ndarray, List[int]], /, *, galerkin: bool = False)[source]¶
Bases:
SparseMatrixLinearOperatorA highly specialized operator for matrices defined purely by a set of non-zero diagonals.
This class internally stores the operator using a scipy.sparse.dia_array for maximum efficiency in storage and matrix-vector products. It provides extremely fast methods for extracting diagonals, as this is its native storage format.
A key feature of this class is its support for functional calculus. It dynamically proxies element-wise mathematical functions (e.g., .sqrt(), .log(), abs(), **) to the underlying sparse array. For reasons of mathematical correctness, these operations are restricted to operators that are strictly diagonal (i.e., have only a non-zero main diagonal) and will raise a NotImplementedError otherwise.
Aggregation methods that do not return a new operator (e.g., .sum()) are not restricted and can be used on any multi-diagonal operator.
Class Methods¶
- from_diagonal_values:
Constructs a strictly diagonal operator from a 1D array of values.
- from_operator:
Creates a diagonal approximation of another LinearOperator.
Properties¶
- offsets:
The array of stored diagonal offsets.
- is_strictly_diagonal:
True if the operator only has a non-zero main diagonal.
- inverse:
The inverse of a strictly diagonal operator.
- sqrt:
The square root of a strictly diagonal operator.
- apply_function(func: str | Callable[[ndarray], ndarray]) DiagonalSparseMatrixLinearOperator[source]¶
Applies a function to the diagonal values (eigenvalues) of the operator.
This supports functional calculus for strictly diagonal operators. For maximum performance, pass a NumPy ufunc (e.g., np.sqrt, np.exp).
- Parameters:
func – A callable function, or the string name of a SciPy sparse method.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = True, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for extreme efficiency.
This operation is nearly free, as it involves selecting the requested diagonals from the data already stored in the native format.
- classmethod from_diagonal_values(domain: HilbertSpace, codomain: HilbertSpace, diagonal_values: np.ndarray, /, *, galerkin: bool = False) DiagonalSparseMatrixLinearOperator[source]¶
Constructs a purely diagonal operator from a 1D array of values.
This provides a convenient way to create an operator with non-zero entries only on its main diagonal (offset k=0).
- Parameters:
domain – The domain of the operator.
codomain – The codomain of the operator. Must have the same dimension.
diagonal_values – A 1D NumPy array of the values for the main diagonal.
galerkin – If True, the operator is in Galerkin form.
- Returns:
A new DiagonalSparseMatrixLinearOperator.
- classmethod from_operator(operator: LinearOperator, offsets: List[int], /, *, galerkin: bool = True) DiagonalSparseMatrixLinearOperator[source]¶
Creates a diagonal approximation of another LinearOperator.
This factory method works by calling the source operator’s .extract_diagonals() method and using the result to construct a new, highly efficient DiagonalSparseMatrixLinearOperator.
- Parameters:
operator – The source operator to approximate.
offsets – The list of diagonal offsets to extract and keep.
galerkin – Specifies which matrix representation to use.
- Returns:
A new DiagonalSparseMatrixLinearOperator.
- property inverse: DiagonalSparseMatrixLinearOperator¶
The inverse of the operator, computed via functional calculus. Requires the operator to be strictly diagonal with no zero entries.
- property is_strictly_diagonal: bool¶
True if the operator only has a non-zero main diagonal (offset=0).
- property offsets: ndarray¶
Returns the array of stored diagonal offsets.
- property sqrt: DiagonalSparseMatrixLinearOperator¶
The square root of the operator, computed via functional calculus. Requires the operator to be strictly diagonal with non-negative entries.
- class pygeoinf.linear_operators.LinearOperator(domain: HilbertSpace, codomain: HilbertSpace, mapping: Callable[[Any], Any], /, *, dual_mapping: Callable[[Any], Any] | None = None, adjoint_mapping: Callable[[Any], Any] | None = None, dual_base: LinearOperator | None = None, adjoint_base: LinearOperator | None = None)[source]¶
Bases:
NonLinearOperator,LinearOperatorAxiomChecksA linear operator between two Hilbert spaces.
This class represents a linear map L(x) = Ax and provides rich functionality for linear algebraic operations. It specializes NonLinearOperator, with the derivative mapping taking the required form (i.e., the derivative is just the operator itself).
Key features include operator algebra (@, +, *), automatic derivation of adjoint (.adjoint) and dual (.dual) operators, and multiple matrix representations (.matrix()) for use with numerical solvers.
- property adjoint: LinearOperator¶
The adjoint of the operator.
- property dual: LinearOperator¶
The dual of the operator.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Computes the main diagonal of the operator’s matrix representation.
This method is highly parallelizable and memory-efficient, as it avoids forming the full dense matrix.
- Parameters:
galerkin – If True, computes the diagonal of the Galerkin matrix.
parallel – If True, computes the entries in parallel.
n_jobs – Number of parallel jobs to use.
- Returns:
A NumPy array containing the diagonal entries.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Computes specified diagonals of the operator’s matrix representation.
This is a memory-efficient and parallelizable method that computes the matrix one column at a time.
- Parameters:
offsets – A list of diagonal offsets to extract (e.g., [0] for the main diagonal, [-1, 0, 1] for a tridiagonal matrix).
galerkin – If True, computes the diagonals of the Galerkin matrix.
parallel – If True, computes columns in parallel.
n_jobs – Number of parallel jobs to use.
- Returns:
A NumPy array where each row is a diagonal.
The list of offsets.
This format is compatible with scipy.sparse.spdiags.
- Return type:
A tuple containing
- static from_formal_adjoint(domain: HilbertSpace, codomain: HilbertSpace, operator: LinearOperator) LinearOperator[source]¶
Constructs an operator on weighted spaces from one on the underlying spaces.
This is a key method for working with MassWeightedHilbertSpace. It takes an operator A that is defined on the simple, unweighted underlying spaces and “lifts” it to be a proper operator on the mass-weighted spaces. It correctly defines the new operator’s adjoint with respect to the weighted inner products.
This method automatically handles cases where the domain and/or codomain are a HilbertSpaceDirectSum, recursively building the necessary block-structured mass operators.
- Parameters:
domain – The (potentially) mass-weighted domain of the new operator.
codomain – The (potentially) mass-weighted codomain of the new operator.
operator – The original operator defined on the underlying, unweighted spaces.
- Returns:
A new LinearOperator that acts between the mass-weighted spaces.
- static from_formally_self_adjoint(domain: HilbertSpace, operator: LinearOperator) LinearOperator[source]¶
Constructs a self-adjoint operator on a weighted space.
This method takes an operator that is formally self-adjoint on an underlying (unweighted) space and promotes it to a truly self-adjoint operator on the MassWeightedHilbertSpace. It automatically handles HilbertSpaceDirectSum domains.
- Parameters:
domain (HilbertSpace) – The domain of the operator, which can be a MassWeightedHilbertSpace or a HilbertSpaceDirectSum.
operator (LinearOperator) – The operator to be converted.
- static from_linear_form(form: LinearForm) LinearOperator[source]¶
Creates a rank-1 LinearOperator from a single LinearForm.
The resulting operator maps from the form’s domain to a 1-dimensional Euclidean space.
The forward mapping evaluates the form: A(x) = [form(x)]. The dual mapping scales the form: A’(y’) = y’_0 * form. The adjoint mapping is handled automatically by the base class.
- Parameters:
form – A LinearForm representing a continuous linear functional.
- Returns:
A LinearOperator mapping from ‘form.domain’ to EuclideanSpace(1).
- static from_linear_forms(forms: List[LinearForm]) LinearOperator[source]¶
Creates an operator from a list of linear forms.
The resulting operator maps from the forms’ domain to an N-dimensional Euclidean space, where N is the number of forms.
- static from_matrix(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray | sp.sparray | ScipyLinOp, /, *, galerkin: bool = False) MatrixLinearOperator[source]¶
Creates the most appropriate LinearOperator from a matrix representation.
This factory method acts as a dispatcher, inspecting the type of the input matrix and returning the most specialized and optimized operator subclass (e.g., Dense, Sparse, or DiagonalSparse). It also handles matrix-free scipy.sparse.linalg.LinearOperator objects.
- Parameters:
domain – The operator’s domain space.
codomain – The operator’s codomain space.
matrix – The matrix representation (NumPy ndarray, SciPy sparray, or SciPy LinearOperator).
galerkin – If True, the matrix is interpreted in Galerkin form.
- Returns:
An instance of the most appropriate MatrixLinearOperator subclass.
- static from_tensor_product(domain: HilbertSpace, codomain: HilbertSpace, vector_pairs: List[Tuple[Any, Any]], /, *, weights: List[float] | None = None) LinearOperator[source]¶
Creates an operator from a weighted sum of tensor products.
The operator represents A(x) = sum_i( w_i * <x, v_i> * u_i ), where vector_pairs are (u_i, v_i).
- static from_vector(domain: HilbertSpace, vector: Vector) LinearOperator[source]¶
Creates a rank-1 LinearOperator from a single domain vector.
The resulting operator maps from the given domain to a 1-dimensional Euclidean space.
The forward mapping evaluates the inner product: A(x) = [<vector, x>]. The adjoint mapping scales the vector: A*(y) = y[0] * vector.
- Parameters:
domain – The Hilbert space the vector belongs to.
vector – A single vector in the domain space.
- Returns:
A LinearOperator mapping from ‘domain’ to EuclideanSpace(1).
- static from_vectors(domain: HilbertSpace, vectors: List[Vector]) LinearOperator[source]¶
Creates a LinearOperator from a list of domain vectors.
The resulting operator maps from the given domain to a Euclidean space of dimension n (where n is the number of vectors).
The forward mapping is given by A(x)_i = <vectors[i], x>. The adjoint mapping is given by A*(y) = sum(y_i * vectors[i]).
- Parameters:
domain – The Hilbert space the vectors belong to.
vectors – A list of vectors in the domain space.
- Returns:
A LinearOperator mapping from ‘domain’ to EuclideanSpace(len(vectors)).
- Raises:
ValueError – If the list of vectors is empty.
- property linear: bool¶
True, as this is a LinearOperator.
- matrix(*, dense: bool = False, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) LinearOperator | ndarray[source]¶
Returns a matrix representation of the operator.
This provides a concrete matrix that represents the operator’s action on the underlying component vectors.
- Parameters:
dense – If True, returns a dense numpy.ndarray. If False (default), returns a memory-efficient, matrix-free scipy.sparse.linalg.LinearOperator.
galerkin – If True, the returned matrix is the Galerkin representation, whose rmatvec corresponds to the adjoint operator. If False (default), the rmatvec corresponds to the dual operator. The Galerkin form is essential for algorithms that rely on symmetry/self-adjointness.
parallel – If True and dense=True, computes the matrix columns in parallel.
n_jobs – Number of parallel jobs to use. -1 uses all available cores.
- Returns:
The matrix representation, either dense or matrix-free.
- static self_adjoint(domain: HilbertSpace, mapping: Callable[[Any], Any]) LinearOperator[source]¶
Creates a self-adjoint operator.
- static self_adjoint_from_matrix(domain: HilbertSpace, matrix: np.ndarray | sp.sparray | ScipyLinOp) MatrixLinearOperator[source]¶
Creates the most appropriate self-adjoint LinearOperator from a matrix.
This factory acts as a dispatcher, returning the most specialized subclass for the given matrix type (e.g., Dense, Sparse).
It ALWAYS assumes the provided matrix is the Galerkin representation of the operator. The user is responsible for ensuring the input matrix is symmetric (or self-adjoint for ScipyLinOp).
- Parameters:
domain – The operator’s domain and codomain space.
matrix – The symmetric matrix representation.
- Returns:
An instance of the most appropriate MatrixLinearOperator subclass.
- static self_adjoint_from_tensor_product(domain: HilbertSpace, vectors: List[Any], /, *, weights: List[float] | None = None) LinearOperator[source]¶
Creates a self-adjoint operator from a tensor product sum.
- static self_dual(domain: HilbertSpace, mapping: Callable[[Any], Any]) LinearOperator[source]¶
Creates a self-dual operator.
- with_dense_matrix(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) DenseMatrixLinearOperator[source]¶
Returns a new operator equivalent to the existing one, but with its matrix representation computed and stored internally in dense form.
- Parameters:
galerkin – If True, the Galerkin representation is used. Default is False.
parallel – If True, computes the dense matrix in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
- Returns:
A DenseMatrixLinearOperator instance.
- class pygeoinf.linear_operators.MatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray | ScipyLinOp, /, *, galerkin=False)[source]¶
Bases:
LinearOperatorA sub-class of LinearOperator for which the operator’s action is defined internally through its matrix representation.
This matrix can be either a dense numpy matrix or a scipy LinearOperator.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Overload for efficiency.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for efficiency by extracting diagonals directly from the stored dense matrix when possible.
- property is_dense: bool¶
Returns True if the matrix representation is stored internally in dense form.
- property is_galerkin: bool¶
Returns True if the matrix representation is stored in Galerkin form.
- class pygeoinf.linear_operators.SparseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: sp.sparray, /, *, galerkin: bool = False)[source]¶
Bases:
MatrixLinearOperatorA specialization for operators represented by a modern SciPy sparse array.
This class requires a scipy.sparse.sparray object (e.g., csr_array) and provides optimized methods that delegate to efficient SciPy routines.
Upon initialization, the internal array is converted to the CSR (Compressed Sparse Row) format to ensure consistently fast matrix-vector products and row-slicing operations.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Overrides the base method to efficiently extract the main diagonal.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for efficiency by extracting diagonals directly from the stored sparse array.
- property sparse_array: sparray¶
Provides public read-only access to the underlying SciPy sparse array.
pygeoinf.linear_optimisation module¶
Provides deterministic, optimization-based methods for solving linear inverse problems.
This module implements classical inversion techniques that seek a single “best-fit” model by minimizing a specific cost functional. It leverages the abstract operator algebra of the library, allowing inversions to be rigorously formulated in Hilbert spaces and seamlessly applied to discrete representations.
A core feature of this module is its dual algebraic formalism, allowing users to optimize computational efficiency based on the problem geometry: - Model Space Formulation: Assembles and solves the standard normal equations
(size N x N, where N is the model dimension). Best suited for overdetermined problems.
Data Space Formulation: Assembles and solves the dual formulation (size M x M, where M is the data dimension) using the representer method. Highly efficient for underdetermined problems where data measurements are sparse compared to the model.
Key Classes¶
LinearLeastSquaresInversion: Solves the inverse problem by minimizing a Tikhonov-regularized least-squares functional.
ConstrainedLinearLeastSquaresInversion: Solves the regularized least-squares problem strictly within an affine subspace (e.g., enforcing exact boundary conditions or mean property values).
LinearMinimumNormInversion: Finds the model with the smallest norm that fits the data to a statistically acceptable degree using the discrepancy principle. Provides exact analytical Fréchet derivatives of the discrepancy search.
ConstrainedLinearMinimumNormInversion: Applies the discrepancy principle subject to an exact affine subspace constraint, resolving the non-linear mapping between constraint values and the resulting model.
- class pygeoinf.linear_optimisation.ConstrainedLinearLeastSquaresInversion(forward_problem: LinearForwardProblem, constraint: AffineSubspace, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem subject to an affine subspace constraint.
This method finds the model u that minimizes the Tikhonov-regularized least-squares functional while strictly confining the solution to an affine subspace (e.g., enforcing a specific average property value or boundary condition).
Supports both ‘model_space’ and ‘data_space’ formalisms for the underlying unconstrained inversion.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearLeastSquaresInversion[source]¶
Constructs a surrogate of the constrained linear inversion using a reduced data space.
- least_squares_operator(damping: float, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None) AffineOperator[source]¶
Returns an operator that maps data to the constrained least-squares solution.
- normal_residual_callback(damping: float, data: Vector, /, *, message: str = 'Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True)[source]¶
Generates a ResidualTrackingCallback for the reduced, unconstrained normal equations.
- parameterized_inversion(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearLeastSquaresInversion[source]¶
Constructs a parameterized surrogate of the constrained least-squares inversion.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new ConstrainedLinearLeastSquaresInversion instance operating on the parameter space.
- with_formalism(formalism: Literal['model_space', 'data_space']) ConstrainedLinearLeastSquaresInversion[source]¶
Returns a new instance of the constrained inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new ConstrainedLinearLeastSquaresInversion instance with the updated formalism.
- class pygeoinf.linear_optimisation.ConstrainedLinearMinimumNormInversion(forward_problem: LinearForwardProblem, constraint: AffineSubspace, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionFinds the minimum-norm solution subject to an affine subspace constraint.
This class solves the regularized inverse problem using the discrepancy principle while strictly confining the solution to an affine subspace.
- constraint_value_mapping(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator[source]¶
Returns an operator mapping a constraint value ‘w’ to the corresponding constrained minimum norm solution ‘u’ for a strictly fixed dataset. The operator has its derivative set.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearMinimumNormInversion[source]¶
Constructs a surrogate of the constrained linear inversion using a reduced data space.
- minimum_norm_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator[source]¶
Returns an operator that maps data to the constrained minimum-norm solution. The operator has its derivative set.
- parameterized_inversion(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearMinimumNormInversion[source]¶
Constructs a parameterized surrogate of the constrained minimum norm inversion.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new ConstrainedLinearMinimumNormInversion instance operating on the parameter space.
- with_formalism(formalism: Literal['model_space', 'data_space']) ConstrainedLinearMinimumNormInversion[source]¶
Returns a new instance of the constrained inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new ConstrainedLinearMinimumNormInversion instance with the updated formalism.
- class pygeoinf.linear_optimisation.LinearLeastSquaresInversion(forward_problem: LinearForwardProblem, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem using Tikhonov-regularized least-squares.
- This method finds the model u that minimizes the cost functional:
J(u) = ||A(u) - d||^2_R + damping * ||u||^2
where A is the forward operator, d is the observed data, R is the data covariance (if a data error measure is set), and damping is the Tikhonov regularization parameter.
This class supports two formalisms for constructing the linear system: 1. ‘model_space’: Solves the standard normal equations of size (N x N),
where N is the model dimension. Best for overdetermined problems.
‘data_space’: Solves the dual formulation of size (M x M), where M is the data dimension. Best for highly underdetermined problems.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearLeastSquaresInversion[source]¶
Constructs a surrogate of the least-squares inversion using a reduced data space.
- least_squares_operator(damping: float, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None) LinearOperator | AffineOperator[source]¶
Constructs the full operator that maps observed data directly to the least-squares model solution.
This method solves the internal normal equations and applies the necessary algebraic transformations (and affine shifts) to recover the model parameters from the data, seamlessly handling whichever formalism was selected during initialization.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver instance used to invert the normal operator.
preconditioner – An optional LinearOperator, or a LinearSolver factory, used to precondition the normal equations. Only utilized if the provided solver is an IterativeLinearSolver.
- Returns:
A LinearOperator (or AffineOperator, if a non-zero data expectation exists) that maps a vector from the data space to the optimal vector in the model space.
- Raises:
TypeError – If the provided preconditioner is neither a LinearOperator nor a LinearSolver.
- normal_operator(damping: float) LinearOperator[source]¶
Constructs the regularized normal operator for the chosen formalism.
For ‘model_space’, this returns: A* R^{-1} A + damping * I For ‘data_space’, this returns: A A* + damping * R
- Parameters:
damping – The non-negative Tikhonov regularization parameter.
- Returns:
A LinearOperator representing the left-hand side of the normal equations.
- Raises:
ValueError – If the damping parameter is negative.
- normal_residual_callback(damping: float, data: Vector, /, *, message: str = 'Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True)[source]¶
Generates a ResidualTrackingCallback pre-configured to track the convergence of the least-squares normal equations for the given data vector.
- normal_rhs(data: Vector) Vector[source]¶
Computes the right-hand side vector for the normal equations.
Prior to construction, the data is shifted by the expected value of the data error measure (i.e., v - z_bar), if applicable.
For ‘model_space’, this returns: A* R^{-1} (v - z_bar) For ‘data_space’, this returns: (v - z_bar)
- Parameters:
data – The observed data vector in the data space.
- Returns:
The right-hand side Vector for the chosen linear system.
- surrogate_inversion(*, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearLeastSquaresInversion[source]¶
Constructs a surrogate least-squares inversion problem using simplified physics or data errors.
- surrogate_woodbury_data_preconditioner(damping: float, solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Builds a data-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
Note
Ensure that any alternate measures provided have well-defined inverse covariances, or use .with_regularized_inverse() on them before passing them to this method.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_data_error_measure – An optional simplified data error measure.
noise_solver – Optional solver for the noise covariance.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- surrogate_woodbury_model_preconditioner(damping: float, solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a model-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearLeastSquaresInversion[source]¶
Returns a new instance of the inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearLeastSquaresInversion instance with the updated formalism.
- woodbury_data_preconditioner(damping: float, solver: LinearSolver, /, *, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Constructs a data-space preconditioner using the Woodbury matrix identity.
Data Space Normal Operator: N_d = A A* + damping * R Woodbury Identity: N_d^-1 = (1/damping) * [R^-1 - R^-1 A (A* R^-1 A + damping * I)^-1 A* R^-1]
Note
This method assumes the noise measure (R) either already has a well-defined inverse covariance, or is well-conditioned enough to be inverted by the provided solver. If it is an unbounded operator on a function space, use R.with_regularized_inverse() before passing it to the inversion.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator (N_m).
noise_solver – An optional solver used to explicitly invert the data error covariance (R) if its inverse is not already set. Defaults to solver if not provided.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- woodbury_model_preconditioner(damping: float, solver: LinearSolver, /) LinearOperator[source]¶
Constructs a model-space preconditioner using the Woodbury matrix identity.
Model Space Normal Operator: N_m = A* R^-1 A + damping * I Woodbury Identity: N_m^-1 = (1/damping) * [I - A* (damping * R + A A*)^-1 A]
Note
This formulation does not require evaluating the explicit inverse of the noise covariance (R).
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator (N_d).
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- class pygeoinf.linear_optimisation.LinearMinimumNormInversion(forward_problem: LinearForwardProblem, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionFinds a regularized solution using the discrepancy principle.
This method finds the model u with the smallest norm that fits the data to a statistically acceptable degree (determined by a target chi-squared value and significance level).
This class supports two formalisms for constructing the linear systems: 1. ‘model_space’: Solves the normal equations of size (N x N). 2. ‘data_space’: Solves the dual formulation of size (M x M).
- minimum_norm_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator | LinearOperator[source]¶
Maps data to the minimum-norm solution matching target chi-squared.
The returned NonLinearOperator includes the exact analytical Fréchet derivative of the discrepancy search, complete with its adjoint mapping.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearMinimumNormInversion[source]¶
Returns a new instance of the inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearMinimumNormInversion instance with the updated formalism.
pygeoinf.linear_solvers module¶
Provides a collection of solvers for linear systems of equations.
This module offers a unified interface for solving linear systems A(x) = y, where A is a LinearOperator. It includes both direct methods based on matrix factorization and iterative, matrix-free methods suitable for large-scale problems.
The solvers are implemented as callable classes. An instance of a solver can be called with an operator to produce a new operator representing its inverse.
Key Classes¶
LUSolver, CholeskySolver: Direct solvers based on matrix factorization.
ScipyIterativeSolver: A general wrapper for SciPy’s iterative algorithms (CG, GMRES, etc.) that operate on matrix representations.
CGSolver: A pure, matrix-free implementation of the Conjugate Gradient algorithm that operates directly on abstract Hilbert space vectors.
- pygeoinf.linear_solvers.BICGMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- pygeoinf.linear_solvers.BICGStabMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.linear_solvers.BICGStabSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the BiCGStab algorithm.
Suitable for non-symmetric linear systems Ax = y. It operates directly on Hilbert space vectors using native inner products and arithmetic.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- pygeoinf.linear_solvers.CGMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.linear_solvers.CGSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 0.0, maxiter: int | None = None, callback: Callable[[Vector], None] | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the Conjugate Gradient (CG) algorithm.
This solver operates directly on Hilbert space vectors and operator actions without explicitly forming a matrix. It is suitable for self-adjoint, positive-definite operators on a general Hilbert space.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.linear_solvers.CholeskySolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on Cholesky decomposition.
- class pygeoinf.linear_solvers.DirectLinearSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverAn abstract base class for direct linear solvers that rely on matrix factorization.
- class pygeoinf.linear_solvers.EigenSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1, rtol: float = 1e-12)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on the eigendecomposition of a symmetric operator.
- class pygeoinf.linear_solvers.FCGSolver(*, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None, preconditioning_method: LinearSolver | None = None)[source]¶
Bases:
IterativeLinearSolverFlexible Conjugate Gradient (FCG) solver.
FCG is designed to handle variable preconditioning, such as using an inner iterative solver to approximate the action of M^-1.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- pygeoinf.linear_solvers.GMRESMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.linear_solvers.IterativeLinearSolver(*, preconditioning_method: LinearSolver = None)[source]¶
Bases:
LinearSolverAn abstract base class for iterative linear solvers.
- property iterations: int¶
Returns the number of iterations within the last solve. The value is zero if the solver has yet to be called.
- solve_adjoint_linear_system(operator: LinearOperator, adjoint_preconditioner: LinearOperator | None, x: Vector, y0: Vector | None) Vector[source]¶
Solves the adjoint linear system A*y = x for y.
- abstract solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.linear_solvers.LSQRSolver(*, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the LSQR algorithm with damping support.
This solver is designed to solve the problem: minimize ||Ax - y||_2^2 + damping^2 * ||x||_2^2.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None, damping: float = 0.0) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.linear_solvers.LUSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on the LU decomposition of an operator’s dense matrix representation.
- class pygeoinf.linear_solvers.LinearSolver[source]¶
Bases:
ABCAn abstract base class for linear solvers.
- class pygeoinf.linear_solvers.MinResSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the MINRES algorithm.
Suitable for symmetric, possibly indefinite or singular linear systems. It minimizes the norm of the residual ||r|| in each step using the Hilbert space’s native inner product.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.linear_solvers.ProgressCallback(message: str = 'Iteration: ')[source]¶
Bases:
objectA simple callback that prints the solver’s iteration count.
- class pygeoinf.linear_solvers.ResidualTrackingCallback(operator: LinearOperator, y: Vector, print_progress: bool = True, message: str = 'Iteration: {iter} | Residual: {res:.3e}')[source]¶
Bases:
ProgressCallbackA callback that computes and tracks the exact residual norm ||y - A(x)||.
Warning: This evaluates the forward operator once per iteration. For very large problems, this may introduce computational overhead.
- class pygeoinf.linear_solvers.ScipyIterativeSolver(method: str, /, *, preconditioning_method: LinearSolver = None, galerkin: bool = False, **kwargs)[source]¶
Bases:
IterativeLinearSolverA general iterative solver that wraps SciPy’s iterative algorithms.
This class provides a unified interface to SciPy’s sparse iterative solvers like cg, gmres, bicgstab, etc. The specific algorithm is chosen during instantiation, and keyword arguments are passed directly to the chosen SciPy function.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.linear_solvers.SolutionTrackingCallback(domain: HilbertSpace, message: str = 'Iteration: ', print_progress: bool = True)[source]¶
Bases:
ProgressCallbackA callback that tracks the solution vector at each iteration.
Useful for visualizing the convergence path of the solver or calculating diagnostics post-hoc without slowing down the inversion.
pygeoinf.low_rank module¶
Implements randomized matrix-free algorithms for operators on Hilbert spaces.
This module provides fully abstract, matrix-free implementations of randomized factorizations (SVD, Cholesky, Eigendecomposition). These algorithms operate entirely via operator composition, adjoint mappings, and the intrinsic geometry of the underlying HilbertSpace objects.
If a GaussianMeasure is provided, the algorithms draw structured samples to respect mass matrices and continuous function space geometries. If no measure is provided, they fall back to highly optimized, component-based matrix-free algorithms.
- class pygeoinf.low_rank.LowRankCholesky(l_op: LinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the Cholesky-like factorization: A ≈ L @ L*.
This class provides a memory-efficient low-rank Cholesky decomposition of a positive semi-definite operator, highly useful for drawing samples from Gaussian measures.
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = True, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankCholesky[source]¶
Computes a robust approximate Cholesky factorization via randomized range finding.
Attempts a direct dense Cholesky factorization on the projected core matrix. If it fails (due to numerical precision issues), it safely falls back to an Eigendecomposition-based square root.
- Parameters:
operator (LinearOperator) – Positive semi-definite operator to factorize.
size_estimate (int) – Target rank or initial block size.
measure (GaussianMeasure, optional) – Prior measure for drawing test vectors.
galerkin (bool) – Default True. Computes Galerkin representation on fallback.
method (str) – {‘variable’, ‘fixed’}.
max_rank (int, optional) – Upper limit on rank for ‘variable’ method.
power (int) – Number of power iterations.
rtol (float) – Relative tolerance for ‘variable’ method.
block_size (int) – Samples per iteration.
parallel (bool) – Parallelize the sampling/multiplication.
n_jobs (int) – CPU cores to utilize.
- Returns:
An instantiated operator containing the L factor.
- Return type:
- Raises:
ValueError – If the operator is not an automorphism.
- property l_factor: LinearOperator¶
The Cholesky factor (L).
- Type:
- property rank: int¶
The rank of the approximation.
- Type:
int
- class pygeoinf.low_rank.LowRankEig(u_op: LinearOperator, d_op: DiagonalSparseMatrixLinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the eigendecomposition: A ≈ U @ D @ U*.
This class encapsulates the components of an Eigendecomposition for a self-adjoint operator, allowing it to act as a LinearOperator while exposing the eigenvectors and eigenvalues.
- apply_function(func: Callable[[ndarray], ndarray], *, regularization: float = 0.0) LowRankEig[source]¶
Applies a function to the spectrum of the operator. Returns a new LowRankEig representing f(A).
- property d_factor: DiagonalSparseMatrixLinearOperator¶
The diagonal matrix of eigenvalues (D).
- property eigenvalues: ndarray¶
A 1D array of the computed eigenvalues.
- Type:
np.ndarray
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = True, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankEig[source]¶
Computes the Eigendecomposition using a unified randomized range finder.
- Parameters:
operator (LinearOperator) – The self-adjoint operator to approximate.
size_estimate (int) – Target rank or initial block size.
measure (GaussianMeasure, optional) – Prior measure for drawing test vectors.
galerkin (bool) – Default True for Eig. Computes Galerkin representation on fallback.
method (str) – {‘variable’, ‘fixed’}.
max_rank (int, optional) – Upper limit on rank for ‘variable’ method.
power (int) – Number of power iterations.
rtol (float) – Relative tolerance for ‘variable’ method.
block_size (int) – Samples per iteration.
parallel (bool) – Parallelize the sampling/multiplication.
n_jobs (int) – CPU cores to utilize.
- Returns:
An instantiated operator containing the U and D factors.
- Return type:
- Raises:
ValueError – If the operator is not an automorphism (domain != codomain).
- property rank: int¶
The rank of the approximation.
- Type:
int
- property u_factor: LinearOperator¶
The eigenvectors (U).
- Type:
- class pygeoinf.low_rank.LowRankSVD(u_op: LinearOperator, sigma_op: DiagonalSparseMatrixLinearOperator, v_op: LinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the low-rank SVD: A ≈ U @ Sigma @ V*.
This class encapsulates the components of a Singular Value Decomposition, allowing it to be used directly as a LinearOperator while providing access to the individual low-rank factors.
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = False, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankSVD[source]¶
Computes the SVD using a unified randomized range finder.
- Parameters:
operator (LinearOperator) – The operator to approximate.
size_estimate (int) – For ‘fixed’ method, the exact target rank. For ‘variable’ method, this is the initial rank to sample.
measure (GaussianMeasure, optional) – A prior measure used to draw test vectors. If provided, respects the domain’s geometry. If None, falls back to a component-based SciPy LinearOperator representation.
galerkin (bool) – If True, computes the Galerkin representation when falling back to components.
method (str) – {‘variable’, ‘fixed’}. The rank-determination algorithm to use.
max_rank (int, optional) – Hard limit on the rank for the ‘variable’ method.
power (int) – Number of power iterations to improve accuracy.
rtol (float) – Relative tolerance for the ‘variable’ method.
block_size (int) – Number of new vectors to sample per iteration in ‘variable’ method.
parallel (bool) – Whether to parallelize the matrix/operator evaluations.
n_jobs (int) – Number of cores to use if parallel=True (-1 for all).
- Returns:
An instantiated operator containing the U, Sigma, and V factors.
- Return type:
- property rank: int¶
The rank of the approximation.
- Type:
int
- property sigma_factor: DiagonalSparseMatrixLinearOperator¶
The diagonal matrix of singular values (Sigma).
- property singular_values: ndarray¶
A 1D array of the computed singular values.
- Type:
np.ndarray
- property u_factor: LinearOperator¶
The left singular vectors (U).
- Type:
- property v_factor: LinearOperator¶
The right singular vectors (V).
- Type:
- pygeoinf.low_rank.deflated_diagonal(operator: LinearOperator, rank: int, size_estimate: int, /, *, method: str = 'variable', use_rademacher: bool = True, max_samples: int | None = None, rtol: float = 0.01, block_size: int = 10, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Estimates the diagonal of a square operator’s component matrix using SVD deflation.
This combines a deterministic low-rank diagonal approximation (via SVD) with a stochastic estimate of the residual diagonal (via Hutchinson’s).
- Parameters:
operator – The square LinearOperator to analyze.
rank – The rank of the deterministic SVD deflation.
size_estimate – Initial number of samples for the stochastic residual.
method – ‘variable’ or ‘fixed’ for the stochastic residual phase.
use_rademacher – If True, uses [-1, 1] Rademacher noise for Hutchinson’s.
max_samples – Hard limit on residual samples.
rtol – Relative tolerance for the stochastic residual phase.
block_size – Samples added per iteration in the stochastic phase.
galerkin – If True, computes the diagonal of the Galerkin matrix.
parallel – Whether to compute operations in parallel.
n_jobs – Number of CPU cores to utilize.
- Returns:
A 1D array representing the diagonal of the operator.
- Return type:
np.ndarray
- pygeoinf.low_rank.random_diagonal(matrix: ndarray | LinearOperator, size_estimate: int, /, *, method: str = 'variable', use_rademacher: bool = False, max_samples: int | None = None, rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Computes an approximate diagonal of a square matrix using Hutchinson’s method.
This algorithm uses a progressive, iterative approach to estimate the diagonal. It starts with an initial number of samples and adds new blocks of random vectors until the estimate of the diagonal converges to a specified tolerance.
Note: This is a specialized, component-based implementation relying on element-wise array multiplication.
- Parameters:
matrix – The (n, n) matrix or LinearOperator to analyze.
size_estimate – For ‘fixed’ method, the exact target rank. For ‘variable’ method, this is the initial rank to sample.
method ({'variable', 'fixed'}) – The algorithm to use. - ‘variable’: Progressively samples to meet tolerance rtol. - ‘fixed’: Returns an estimate based on exactly size_estimate samples.
use_rademacher – If true, draw components from [-1,1]. Default method draws normally distributed components.
max_samples – For ‘variable’ method, a hard limit on the number of samples. Ignored if method=’fixed’. Defaults to dimension of matrix.
rtol – Relative tolerance for the ‘variable’ method.
block_size – Number of new vectors to sample per iteration in ‘variable’ method.
parallel – Whether to use parallel matrix multiplication.
n_jobs – Number of jobs for parallelism.
- Returns:
A 1D numpy array of size n containing the approximate diagonal.
- Return type:
np.ndarray
- pygeoinf.low_rank.random_range(operator: LinearOperator, size_estimate: int, /, *, measure: GaussianMeasure | None = None, galerkin: bool = False, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LinearOperator[source]¶
Unified random range finder acting as an architectural bridge.
If a GaussianMeasure is provided, it draws abstract structured samples to respect Hilbert space geometries and mass matrices. If no measure is provided, it routes to high-performance component-based representations via SciPy `LinearOperator`s.
- Parameters:
operator (LinearOperator) – The linear operator whose range is to be approximated.
size_estimate (int) – Target rank (‘fixed’) or initial sample size (‘variable’).
measure (GaussianMeasure, optional) – Measure to draw test samples from.
galerkin (bool) – If True, uses the Galerkin representation for the component fallback.
method (str) – {‘variable’, ‘fixed’}. Algorithm choice.
max_rank (int, optional) – Hard limit on rank for variable sampling.
power (int) – Number of power iterations to enhance singular value decay.
rtol (float) – Relative tolerance for convergence checking.
block_size (int) – Size of new sample batches.
parallel (bool) – Parallelize computations where applicable.
n_jobs (int) – CPU cores to use.
- Returns:
The isometry Q mapping from Euclidean(k) into the codomain.
- Return type:
- pygeoinf.low_rank.white_noise_measure(domain: HilbertSpace) GaussianMeasure[source]¶
Creates a formal N(0, I) “white noise” measure on the given domain.
WARNING: Mathematically, the identity operator is not trace-class in infinite dimensions, meaning this does not define a valid Radon measure on the Hilbert space. It is a cylinder measure.
In this library, it is used strictly as a numerical tool to generate isotropic test vectors for randomized algorithms, ensuring that the sampling perfectly respects the domain’s inner product (e.g., mass matrices) without biasing the range approximation.
pygeoinf.nonlinear_forms module¶
Provides the NonLinearForm base class to represent non-linear functionals.
A non-linear form, or functional, is a mapping from a vector in a Hilbert space to a scalar. This class provides a foundational structure for these functionals, equipping them with algebraic operations and an interface for derivatives like gradients and Hessians.
For non-smooth convex functions, the class also supports subgradients, which generalize gradients to non-differentiable points.
- class pygeoinf.nonlinear_forms.NonLinearForm(domain: HilbertSpace, mapping: Callable[[Vector], float], /, *, gradient: Callable[[Vector], Vector] | None = None, subgradient: Callable[[Vector], Vector] | None = None, hessian: Callable[[Vector], LinearOperator] | None = None)[source]¶
Bases:
objectRepresents a general non-linear functional that maps vectors to scalars.
This class serves as the foundation for all forms. It defines the basic callable interface form(x) and overloads arithmetic operators (+, -, *) to create new forms. It also provides an optional framework for specifying a form’s gradient, Hessian, and subgradient.
For smooth functions, use gradient and hessian. For non-smooth convex functions, use subgradient.
- derivative(x: Vector) LinearForm[source]¶
Computes the derivative of the form at a given point.
- Parameters:
x – The vector at which to evaluate the derivative.
- Returns:
The derivative of the form as a LinearForm.
- Raises:
NotImplementedError – If a gradient function was not provided during initialization.
- property domain: HilbertSpace¶
The Hilbert space on which the form is defined.
- gradient(x: Any) Vector[source]¶
Computes the gradient of the form at a given point.
- Parameters:
x – The vector at which to evaluate the gradient.
- Returns:
The gradient of the form as a vector in the domain space.
- Raises:
NotImplementedError – If a gradient function was not provided during initialization.
- property has_gradient: bool¶
True if the form has a gradient.
- property has_hessian: bool¶
True if the form has a Hessian.
- property has_subgradient: bool¶
True if the form has a subgradient.
- hessian(x: Any) LinearOperator[source]¶
Computes the Hessian of the form at a given point.
- Parameters:
x – The vector at which to evaluate the Hessian.
- Returns:
The Hessian of the form as a LinearOperator mapping the domain to itself.
- Raises:
NotImplementedError – If a Hessian function was not provided during initialization.
- subgradient(x: Any) Vector[source]¶
Computes a subgradient of the form at a given point.
- For convex functions, a subgradient g ∈ ∂f(x) satisfies:
f(y) ≥ f(x) + ⟨g, y - x⟩ for all y
At points where the function is differentiable, the subgradient equals the gradient. At non-smooth points, there may be multiple subgradients; this method returns one of them.
- Parameters:
x – The vector at which to evaluate the subgradient.
- Returns:
A subgradient of the form as a vector in the domain space.
- Raises:
NotImplementedError – If a subgradient function was not provided during initialization.
pygeoinf.nonlinear_operators module¶
Provides the NonLinearOperator base class for mappings between Hilbert spaces.
A non-linear operator is a general mapping F(x) from a vector x in a domain Hilbert space to a vector y in a codomain Hilbert space. This class provides a foundational structure for these mappings, equipping them with algebraic operations and an interface for the Frécher derivative.
- class pygeoinf.nonlinear_operators.NonLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, mapping: Callable[[Vector], Any], /, *, derivative: Callable[[Vector], LinearOperator] = None)[source]¶
Bases:
NonLinearOperatorAxiomChecksRepresents a general non-linear operator that maps vectors to vectors.
This class provides a functional representation for an operator F(x), and includes an interface for its Fréchet derivative, F’(x), which is the linear operator that best approximates F at a given point x. It serves as the base class for the more specialized LinearOperator.
- property codomain: HilbertSpace¶
The codomain of the operator.
- derivative(x: Vector) LinearOperator[source]¶
Computes the Fréchet derivative of the operator at a given point.
The Fréchet derivative is the linear operator that best approximates the non-linear operator in the neighborhood of the point x.
- Parameters:
x – The point at which to compute the derivative.
- Returns:
The derivative as a LinearOperator.
- Raises:
NotImplementedError – If a derivative function was not provided.
- property domain: HilbertSpace¶
The domain of the operator.
- property has_derivative: bool¶
Returns true if the operators derivative is implemented.
- property is_automorphism: bool¶
True if the operator maps a space into itself.
- property is_square: bool¶
True if the operator’s domain and codomain have the same dimension.
pygeoinf.nonlinear_optimisation module¶
Module for solution of non-linear inverse and inference problems based on optimisation methods.
- class pygeoinf.nonlinear_optimisation.ScipyUnconstrainedOptimiser(method: str, /, **kwargs: Any)[source]¶
Bases:
objectA wrapper for scipy.optimize.minimize that adapts a NonLinearForm.
Note on derivative-free methods: Internal testing has shown that the ‘Nelder-Mead’ solver can be unreliable for some problems, failing to converge to the correct minimum while still reporting success. The ‘Powell’ method appears to be more robust. Users should exercise caution and verify results when using derivative-free methods.
- minimize(form: NonLinearForm, x0: Vector) Vector[source]¶
Finds the minimum of a NonLinearForm starting from an initial guess.
- Parameters:
form (NonLinearForm) – The non-linear functional to minimize.
x0 (Vector) – The initial guess in the Hilbert space.
- Returns:
The vector that minimizes the form.
- Return type:
Vector
- pygeoinf.nonlinear_optimisation.line_search(form: NonLinearForm, xk: Vector, pk: Vector, gfk: Vector = None, old_fval: float = None, old_old_fval: float = None, c1: float = 0.0001, c2: float = 0.9, amax: float = None, extra_condition: Callable[[float, Vector, float, Vector], bool] = None, maxiter: int = 10)[source]¶
Wrapper for the scipy line_search method for application to a non-linear form.
- Parameters:
form (NonLinearForm) – The non-linear functional to minimize.
xk (Vector) – The current point.
pk (Vector) – The search direction.
gfk (Vector, optional) – The gradient at x=xk. If not provided will be recalculated.
old_fval (float, optional) – The function value at x=xk. If not provided will be recalculated.
old_old_fval (float, optional) – The valur at the point proceeding x=xk.
c1 (float, optional) – Parameter for Armijo condition rule.
c2 (float, optional) – Parameter for curvature condition rule.
amax (float, optional) – Maximum step size.
extra_condition (callable, optional) – A callable of the form extra_condition(alpha, x, f, g) returning a boolean. Arguments are the proposed step alpha and the corresponding x, f and g values. The line search accepts the value of alpha only if this callable returns True. If the callable returns False for the step length, the algorithm will continue with new iterates. The callable is only called for iterates satisfying the strong Wolfe conditions.
maxiter (int, optional) – Maximum number of iterations to perform.
- Returns:
- Alpha for which x_new = x0 + alpha * pk, or None if the
line search algorithm did not converge.
fc (int): Number of function evaluations made. gc (int): Numner of gradient evaluations mades. new_fval (float | None): New function value f(x_new)=f(x0+alpha*pk), or
None if the line search algorithm did not converge.
old_fval (float): Old function value f(x0). new_slope (float | None): The local slope along the search direction at
the new value <myfprime(x_new), pk>, or None if the line search algorithm did not converge.
- Return type:
alpha (float | None)
- Raises:
ValueError – If the non-linear form does not have a gradient set.
pygeoinf.parallel module¶
A collection of helper functions for parallel computation using Joblib.
These functions are designed to be top-level to ensure they can be “pickled” (serialized) and sent to worker processes by libraries like multiprocessing or its wrapper, Joblib.
- pygeoinf.parallel.parallel_compute_dense_matrix_from_scipy_op(scipy_op: ScipyLinOp, n_jobs: int = -1) np.ndarray[source]¶
Computes the dense matrix representation of a scipy.LinearOperator in parallel.
It builds the matrix column by column by applying the operator to each basis vector.
- Parameters:
scipy_op – The SciPy LinearOperator wrapper for the matrix action.
n_jobs – The number of CPU cores to use. -1 means all available.
- Returns:
The dense matrix as a NumPy array.
- pygeoinf.parallel.parallel_mat_mat(A: MatrixLike, B: np.ndarray, n_jobs: int = -1) np.ndarray[source]¶
Computes the matrix product A @ B in parallel by applying A to each column of B.
This is particularly useful when A is a LinearOperator whose action is computationally expensive.
- Parameters:
A – The matrix or LinearOperator to apply.
B – The matrix whose columns will be operated on.
n_jobs – The number of CPU cores to use. -1 means all available.
- Returns:
The result of the matrix product A @ B as a dense NumPy array.
pygeoinf.plot module¶
Plotting module for pygeoinf measures and distributions.
- class pygeoinf.plot.SubspaceSlicePlotter(subset: Subset, on_subspace: AffineSubspace, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, bar_pixel_height: int = 6)[source]¶
Bases:
objectPlotter for visualizing subsets sliced along 1D, 2D, or 3D affine subspaces.
Fully implemented for 1D, 2D, and 3D subspaces via three rendering paths:
PolyhedralSet→ exact affine slice viascipy.spatial.HalfspaceIntersection+ convex hull; payload is vertex array(n_vertices, n_dims).Ball/Ellipsoid→ exact quadratic slice via Cholesky-factored pullback metric; no grid sampling is performed:1D slice:
payloadisnp.array([lo, hi])— the two interval endpoints.2D slice:
payloadis boundary points, shape(N, 2)(N ≈ 360).3D slice:
payloadis surface points, shape(N_pts, 3).
An empty or degenerate slice raises
ValueErrorexplicitly.All other sets → raster oracle sampling on a
grid_size^ngrid; payload is boolean membership mask. For 3D, the mask is rendered as filled voxels using Matplotlib’smpl_toolkits.mplot3dbackend (Axes3D.voxels()).
Architecture:
Common methods (
parse_bounds,embed_point,sample_membership) work for 1D, 2D, and 3D.Dimension-specific
_render_*()methods handle visualization.
- embed_point(params: float | Tuple[float, ...] | List[float]) object[source]¶
Map parameter(s) to ambient point using tangent basis.
Universal formula (works for any dimension): x = translation + sum(params[i] * tangent_basis[i])
- Parameters:
params
1D (-) – Single float
2D (-) – 2-tuple (u, v)
3D (-) – 3-tuple (u, v, w)
- Returns:
Ambient point as Vector
- parse_bounds(bounds: tuple | List | None) tuple[source]¶
Parse and validate bounds for current dimension.
Flexible input format handling: - None: Use default [-1, 1] per dimension - 1D: (u_min, u_max) - 2D: (u_min, u_max, v_min, v_max) OR ((u_min, u_max), (v_min, v_max)) - 3D: (u_min, u_max, v_min, v_max, w_min, w_max) OR
((u_min, u_max), (v_min, v_max), (w_min, w_max))
- Parameters:
bounds – User-provided bounds or None
- Returns:
1D: (u_min, u_max)
2D: (u_min, u_max, v_min, v_max)
3D: (u_min, u_max, v_min, v_max, w_min, w_max)
- Return type:
Normalized tuple
- Raises:
ValueError – If bounds format doesn’t match dimension
- plot(bounds: tuple | List | None = None, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax: Axes | None = None, backend: str = 'auto') tuple[source]¶
Main plotting method. Orchestrates bounds parsing, grid generation, membership sampling, and dimension-specific rendering.
- Parameters:
bounds – Plot bounds (format depends on dimension)
cmap – Colormap for 2D/3D (ignored for 1D)
color – Color for 1D (ignored for 2D/3D)
show_plot – Whether to display the plot
ax – Optional existing Matplotlib Axes (must be
Nonewhenbackend='plotly').backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"."auto"selects Plotly for 3D when it is installed and falls back to Matplotlib otherwise. 1D/2D always use Matplotlib regardless of the backend value.
- Returns:
(fig, ax, payload)tuple.When the Matplotlib backend is used fig is a
matplotlib.figure.Figureand ax is a Matplotlib Axes. When the Plotly backend is used fig is aplotly.graph_objects.Figureand ax isNone.payload semantics depend on the rendering path:
PolyhedralSet(exact affine path): vertex array in parameter coords, shape(n_vertices, n_dims).Ball/Ellipsoid(exact quadratic path): interval endpoints[lo, hi]for 1D; boundary points(N, 2)for 2D; surface points(N_pts, 3)for 3D. Empty slices raiseValueError.All other sets (sampled path): boolean membership mask, shape
(grid_size,)in 1D,(grid_size, grid_size)in 2D, or(grid_size, grid_size, grid_size)in 3D.
- Raises:
ValueError – If
axis notNonewhenbackend='plotly'.
- sample_membership(param_grid: ndarray | Tuple[ndarray, ...]) ndarray[source]¶
Evaluate subset membership on parameter grid.
For each grid point, converts parameter coordinates to ambient space via embed_point(), then tests membership using subset.is_element().
- Parameters:
param_grid – Parameter grid from _generate_param_grid()
- Returns:
1D: shape (grid_size,)
2D: shape (grid_size, grid_size)
3D: shape (grid_size, grid_size, grid_size)
- Return type:
Boolean mask array
- pygeoinf.plot.plot_1d_distributions(posterior_measures: GaussianMeasure | Any | List[GaussianMeasure | Any], /, *, prior_measures: GaussianMeasure | Any | List[GaussianMeasure | Any] | None = None, true_value: float | None = None, show_true_value_in_legend: bool = False, ax: Axes | None = None, xlabel: str = 'Property Value', title: str = 'Prior and Posterior Probability Distributions', prior_labels: str | List[str] | None = None, posterior_labels: str | List[str] | None = None, width_scaling: float = 6.0, legend_position: tuple = (0.95, 0.95), fill_density: bool = False, **kwargs) Axes | Tuple[Axes, Axes][source]¶
Plot 1D probability distributions for prior and posterior measures using dual y-axes.
- Parameters:
posterior_measures – Single measure or list of measures for posterior distributions
prior_measures – Single measure or list of measures for prior distributions (optional)
true_value – True value to mark with a vertical line (optional)
ax – An existing Matplotlib Axes object. If None, plots to the current active axes.
xlabel – Label for x-axis
title – Title for the plot
prior_labels – Manual labels for prior distributions (optional)
posterior_labels – Manual labels for posterior distributions (optional)
width_scaling – Width scaling factor in standard deviations (default: 6.0)
legend_position – Position of legend as (x, y) tuple (default: (0.95, 0.95))
fill_density – Whether to fill the area under the PDF curves (default: False)
**kwargs – Additional kwargs (e.g., figsize) safely ignored or forwarded.
- Returns:
ax1 (if no priors) or (ax1, ax2) if dual axes are used.
- pygeoinf.plot.plot_corner_distributions(posterior_measure: GaussianMeasure, /, *, prior_measure: GaussianMeasure | None = None, true_values: List[float] | ndarray | None = None, show_true_value_in_legend: bool = False, labels: List[str] | None = None, title: str = 'Joint Posterior Distribution', figsize: tuple | None = None, colormap: str = 'Blues', contour_color: str = 'darkblue', parallel: bool = False, n_jobs: int = -1, width_scaling: float = 3.75, legend_position: tuple = (0.9, 0.95), fill_density: bool = False, num_sigmas: int = 3) ndarray[source]¶
Create a professional corner plot for multi-dimensional posterior distributions.
- Parameters:
posterior_measure – Multi-dimensional posterior measure (pygeoinf GaussianMeasure)
prior_measure – Optional prior measure to plot secondary axes showing prior standard deviations.
true_values – True values for each dimension (optional)
labels – Labels for each dimension (optional)
title – Title for the plot
figsize – Figure size tuple (if None, calculated based on dimensions)
colormap – Colormap for 2D plots (used when fill_density=True)
contour_color – Uniform color for the 2D contour lines (used when fill_density=False)
parallel – Compute dense covariance matrix in parallel, default False.
n_jobs – Number of cores to use in parallel calculations, default -1.
width_scaling – Width scaling factor in standard deviations for default boundaries (default: 3.75)
legend_position – Position of legend as (x, y) tuple (default: (0.9, 0.95))
fill_density – Whether to fill the 2D contour background with color. False is recommended for sparse truth values.
num_sigmas – Minimum number of standard deviation contours to draw (dynamically scales up to enclose true values).
- Returns:
An N x N NumPy array of Matplotlib Axes objects.
- Return type:
axes
- pygeoinf.plot.plot_slice(subset: Subset, on_subspace: AffineSubspace, bounds=None, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax=None, backend: str = 'auto') Tuple[Any, Axes | None, ndarray][source]¶
Convenience wrapper: slice a subset along a 1D, 2D, or 3D affine subspace and plot.
Thin wrapper over SubspaceSlicePlotter. See that class for full documentation on the
boundsformat and return-value semantics.- Parameters:
subset – The Subset to visualize (domain must be EuclideanSpace).
on_subspace – A 1D, 2D, or 3D AffineSubspace to slice along.
bounds – Plot bounds — passed directly to SubspaceSlicePlotter.plot().
grid_size – Samples per axis (passed to SubspaceSlicePlotter).
rtol – Oracle tolerance (passed to SubspaceSlicePlotter).
alpha – Fill transparency (passed to SubspaceSlicePlotter).
cmap – Colormap for 2D/3D plots.
color – Color string for 1D plots.
show_plot – Whether to call
plt.show().ax – Optional existing
Axes(orAxes3D) to draw into.backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"."auto"prefers Plotly for 3D when it is installed and warns then falls back to Matplotlib otherwise; 1D/2D always use Matplotlib.
- Returns:
(fig, ax, payload)— identical toSubspaceSlicePlotter.plot().payload semantics depend on set type and dimension:
Sampled path (non-
PolyhedralSet): boolean membership mask.1D: shape
(grid_size,)2D: shape
(grid_size, grid_size)3D: shape
(grid_size, grid_size, grid_size)—mask[i, j, k]isTruewhen the point at local parameter coordinates(u[i], v[j], w[k])lies inside the subset.
Exact path (
PolyhedralSet): vertex array in parameter coordinates.1D:
np.array([u_lo, u_hi])— interval endpoints2D: shape
(n_vertices, 2)— polygon vertices3D: shape
(n_vertices, 3)— polytope vertices
For 3D subspaces using
backend='matplotlib'(orbackend='auto'when Plotly is not installed),figis amatplotlib.figure.Figureandaxis anAxes3Dinstance. For 3D subspaces usingbackend='plotly'(orbackend='auto'when Plotly is installed),figis aplotly.graph_objects.FigureandaxisNone.- Raises:
TypeError – If
subset.domainis not anEuclideanSpace.ValueError – If bounds format is incompatible with the subspace dimension, or if
grid_size,rtol, oralphaare out of range.
pygeoinf.preconditioners module¶
- class pygeoinf.preconditioners.BandedPreconditioningMethod(bandwidth: int, /, *, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a symmetrically banded sparse preconditioner.
Extracts a symmetric band of diagonals from the operator’s Galerkin matrix representation, constructs a sparse matrix, and uses a sparse direct solver (exact or incomplete LU) to invert it.
- class pygeoinf.preconditioners.ColumnThresholdedPreconditioningMethod(threshold: float, /, *, max_nnz: int | None = None, galerkin: bool = True, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a sparse preconditioner by evaluating the operator column-by-column, dropping elements that are small relative to the diagonal element, and optionally capping the maximum number of retained non-zeros per column.
- class pygeoinf.preconditioners.ExactBlockPreconditioningMethod(blocks: list[list[int]], /, *, galerkin: bool = True, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a sparse block preconditioner using exact matrix-vector evaluations.
Explicitly probes the operator with basis vectors but only retains the entries specified by the interaction blocks. Factorizes the resulting sparse matrix using exact or incomplete LU.
- class pygeoinf.preconditioners.IdentityPreconditioningMethod[source]¶
Bases:
LinearSolverA trivial preconditioning method that returns the Identity operator.
This acts as a “no-op” placeholder in the preconditioning framework, useful for benchmarking or default configurations.
- class pygeoinf.preconditioners.IterativePreconditioningMethod(inner_solver: IterativeLinearSolver, max_inner_iter: int = 5, rtol: float = 0.1)[source]¶
Bases:
LinearSolverWraps an iterative solver to act as a preconditioner.
This is best used with FCGSolver to handle the potential variability of the inner iterations.
- class pygeoinf.preconditioners.JacobiPreconditioningMethod(num_samples: int | None = 20, method: str = 'variable', rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a Jacobi preconditioner.
- class pygeoinf.preconditioners.SpectralPreconditioningMethod(*, damping: float | None = None, rank: int = 20, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a spectral (low-rank) preconditioner.
This preconditioner uses a randomized eigendecomposition to invert the dominant modes of the operator. The unresolved tail is regularized using a damping parameter.
pygeoinf.quadratic_form_quantile module¶
Weighted chi-square distribution: CDF and quantile.
This module implements numerical methods for the distribution of
Q = sum_j w_j Z_j^2, Z_j ~ iid N(0, 1), w_j > 0,
which arises when calibrating Gaussian credible sets in function spaces. With weights $w_j = lambda_j$ (eigenvalues of the covariance) the distribution governs ambient norm balls; with $w_j = lambda_j^{1-theta}$ it governs weakened-covariance ellipsoids.
The mathematical background is in
docs/agent-docs/theory/function-space-hardening.md, section 4.
Public functions¶
weighted_chi2_cdf : evaluate $P(Q le t)$. weighted_chi2_quantile : invert the CDF for given probability $p$.
Both accept a method argument selecting between
"auto"(default): Automatically selects between"saddlepoint"and"imhof"based on spectrum isotropy (effective degrees of freedom $nu_{text{eff}} = (sum w)^2 / sum w^2$) and the caller’s requested relative tolerancetol. Saddlepoint is used when its expected error is well belowtol; Imhof is used otherwise."imhof": Imhof’s numerical inversion of the characteristic function. Exact to quadrature tolerance."ws": Welch–Satterthwaite moment-match to a scaled $chi^2_nu$. Closed form; exact when all weights are equal; degrades with anisotropy."saddlepoint": Lugannani–Rice saddlepoint approximation. Excellent in deep tails."mc": Monte Carlo empirical quantile / CDF. Unbiased reference.
The tol parameter (default 1e-2) sets the desired relative accuracy
of the result and is used only by "auto" mode to pick a method.
When an explicit method is specified, tol is ignored.
- pygeoinf.quadratic_form_quantile.weighted_chi2_cdf(weights: ndarray, t: float | ndarray, *, method: str = 'auto', tol: float = 0.01, rtol: float = 1e-08, n_samples: int = 100000, rng: Generator | None = None) float | ndarray[source]¶
Evaluate $P(Q le t)$ for $Q = sum_j w_j Z_j^2$.
- Parameters:
weights – Non-negative weights $w_j$. Length-zero or all-zero arrays are treated as the degenerate point mass at 0.
t – Threshold(s); scalar or array. Returns matching shape.
method – One of {“auto”, “imhof”, “ws”, “saddlepoint”, “mc”}.
"auto"selects saddlepoint or Imhof based on spectrum isotropy andtol.tol – Desired relative accuracy of the result. Used only when
method="auto"to decide whether saddlepoint is accurate enough or Imhof is required. Ignored for explicit methods.rtol – Relative quadrature tolerance for Imhof’s integral.
n_samples – Sample count for Monte Carlo. Ignored by other methods.
rng – Optional NumPy generator for Monte Carlo. Defaults to
np.random.default_rng().
- Returns:
$P(Q le t)$ as a float (if
tis scalar) or numpy array.- Raises:
ValueError – For unknown method, negative weights, or NaN inputs.
- pygeoinf.quadratic_form_quantile.weighted_chi2_quantile(weights: ndarray, probability: float, *, method: str = 'auto', tol: float = 0.01, rtol: float = 1e-06, n_samples: int = 100000, rng: Generator | None = None) float[source]¶
Return $r$ such that $P(sum_j w_j Z_j^2 le r) = $ probability.
- Parameters:
weights – Non-negative weights $w_j$.
probability – Target probability, strictly between 0 and 1.
method – One of {“auto”, “imhof”, “ws”, “saddlepoint”, “mc”}.
"auto"(default) selects between saddlepoint and Imhof based on spectrum isotropy andtol: saddlepoint is used when its expected error (empirically $approx 0.1/nu_{text{eff}}$ with $nu_{text{eff}} = (sum w)^2/sum w^2$) is comfortably belowtol; Imhof is used otherwise.tol – Desired relative accuracy of the result. Used only when
method="auto"; ignored for explicit method choices.rtol – Relative tolerance for CDF root-finding (Imhof, saddlepoint).
n_samples – Sample count for Monte Carlo.
rng – Optional NumPy generator for Monte Carlo.
- Returns:
The quantile $r$.
- Raises:
ValueError – For invalid probability, unknown method, or negative weights.
pygeoinf.spectral_operator module¶
Spectral functional calculus for self-adjoint operators.
Given an approximate eigendecomposition $A approx U Lambda U^*$ of a
self-adjoint operator on a Hilbert space, this module builds a matrix-free
LinearOperator representing $f(A) approx U f(Lambda) U^*$ for any
real-valued function $f$ on the spectrum. The intended use case is
covariance-derived ellipsoid metrics in pygeoinf.gaussian_measure,
specifically the family of fractional powers $C^theta$ for
$theta in mathbb{R}$.
The construction mirrors pygeoinf.low_rank.LowRankEig but lifts an arbitrary function $f$ rather than a fixed identity on the eigenvalues. For the standard square-root, inverse, and inverse-square-root operators this is more flexible than the diagonal functional calculus on DiagonalSparseMatrixLinearOperator, which only handles the natural coefficient basis.
Mathematical background: see
docs/agent-docs/theory/function-space-hardening.md section 3 and the
sequel.
- class pygeoinf.spectral_operator.SpectralFractionalOperator(u_op: LinearOperator, eigenvalues: ndarray | ArrayLike, func: Callable[[ndarray], ndarray])[source]¶
Bases:
LinearOperatorMatrix-free $f(A)$ from an eigendecomposition $A = U Lambda U^*$.
The operator acts as
- $$
f(A), v = U,mathrm{diag}(f(lambda_1), ldots, f(lambda_k)), U^* v.
$$
When $U$ is an isometry onto $mathrm{ran}(A)$ this is the standard functional calculus restricted to that range; outside the range the operator returns zero, consistent with $f(0) cdot 0 = 0$ for typical fractional powers.
- Parameters:
u_op – A
LinearOperatormapping the coefficient space ($mathbb{R}^k$ for some rank $k$) to the ambient Hilbert space $H$.eigenvalues – A 1-D array of $k$ eigenvalues.
func – A vectorised function that maps the eigenvalue array to the transformed-eigenvalue array. For fractional powers,
func = lambda x: x ** theta.
- Raises:
ValueError – if
eigenvalueslength does not matchu_op.domain.dim.
- property diagonal_operator: DiagonalSparseMatrixLinearOperator¶
The diagonal operator $mathrm{diag}(f(lambda_j))$ on $mathbb{R}^k$.
- classmethod from_callable(u_op: LinearOperator, eigenvalues: ndarray, func: Callable[[ndarray], ndarray]) SpectralFractionalOperator[source]¶
Build $f(A)$ from explicit factors and a callable.
This is the lowest-level constructor; the typical user wants
from_low_rank_eig().
- classmethod from_low_rank_eig(eig: LowRankEig, power: float, *, regularization: float = 0.0) SpectralFractionalOperator[source]¶
Build $A^{text{power}}$ from a
LowRankEigdecomposition.For
power < 0, the eigenvalues must be strictly positive — in practice $A$ is the covariance and the trailing eigenvalues from a randomised decomposition can be numerically zero or tiny. Theregularizationargument adds a constant offset to the eigenvalues before applying the power, to avoid blow-up.- Parameters:
eig – A
LowRankEiginstance, typically obtained viaLowRankEig.from_randomized(covariance, ...).power – The real exponent.
regularization – Constant added to every eigenvalue before the power; ignored if
power >= 0.
- Returns:
A
SpectralFractionalOperatoracting as $A^{text{power}}$ on the range ofeig.u_factor.
- quadratic_form_squared(v) float[source]¶
Return $langle v, f(A), vrangle_H$ via the spectral expansion.
Equals $sum_j f(lambda_j), c_j^2$ where $c = U^* v$ is the coefficient vector. Uses the underlying
u_op.adjointto compute coefficients, avoiding the extra round-trip throughu_op.
- property rank: int¶
Number of eigenvalue/eigenvector pairs retained.
- property raw_eigenvalues: ndarray¶
The input eigenvalues $lambda_j$ (before $f$).
- property transformed_eigenvalues: ndarray¶
The output eigenvalues $f(lambda_j)$.
- property u_factor: LinearOperator¶
Eigenvectors $U$ as a
LinearOperator$mathbb{R}^k to H$.
- pygeoinf.spectral_operator.fractional_operators_from_eig(eig: LowRankEig, theta: float, *, regularization: float | None = None) tuple[SpectralFractionalOperator, SpectralFractionalOperator, SpectralFractionalOperator][source]¶
Convenience triple for the weakened-ellipsoid construction.
Returns
(A, A_inv, A_inv_sqrt)corresponding to $C^{-theta}$, $C^{theta}$, $C^{theta/2}$ respectively. These are exactly the operator/inverse/inverse-sqrt arguments thatpygeoinf.subsets.Ellipsoidneeds to support its quadratic form and support-function evaluations.- Parameters:
eig – Eigendecomposition of the covariance $C$.
theta – Fractional power; expected in $(0, 1)$.
regularization – Constant offset added to eigenvalues before applying negative powers. Defaults to a relative floor of
1e-12times the largest eigenvalue.
pygeoinf.subsets module¶
Defines classes for representing subsets of a Hilbert space.
This module provides a hierarchy of classes for sets, ranging from abstract definitions to concrete geometric shapes. It supports Constructive Solid Geometry (CSG) operations, with specialized handling for convex intersections via functional combination.
Hierarchy: - Subset (Abstract Base)
EmptySet / UniversalSet
- LevelSet (f(x) = c)
EllipsoidSurface -> Sphere
- SublevelSet (f(x) <= c)
ConvexSubset -> Ellipsoid -> Ball
ConvexIntersection (Max-Functional Combination)
Intersection (Generic)
Union (Generic)
Complement (S^c)
- class pygeoinf.subsets.Ball(domain: HilbertSpace, center: Vector, radius: float, open_set: bool = True)[source]¶
Bases:
EllipsoidRepresents a ball in a Hilbert space: B = {x | ||x - c||^2 <= r^2}. This is an Ellipsoid where A is the Identity operator.
- directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point in direction of ‘direction’.
- For a ball B(c, r) and direction q:
x_max = c + r * (q / ||q||) h(q) = ⟨q, c⟩ + r||q||
- Parameters:
direction – The direction vector q.
- Returns:
(x_max, h(q))
- Return type:
tuple[Vector, float]
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if x lies within the ball. Optimized to use geometric distance ||x-c|| directly.
- property support_function: SupportFunction¶
Returns the support function object for this ball.
Always available for valid Ball instances.
- class pygeoinf.subsets.Complement(subset: Subset)[source]¶
Bases:
SubsetRepresents the complement of a set: S^c = {x | x ∉ S}.
- class pygeoinf.subsets.ConvexIntersection(subsets: Iterable[ConvexSubset])[source]¶
Bases:
ConvexSubsetRepresents the intersection of multiple convex sets as a single convex set.
This class combines the defining functionals of its components into a single max-functional: F(x) = max_i (f_i(x) - c_i). The intersection is then defined as {x | F(x) <= 0}.
This allows the intersection to be treated as a standard ConvexSubset for optimization algorithms, providing gradients and Hessians of the active constraint, while preserving access to the individual constraints.
- directional_bound(direction: Vector) tuple['Vector', float][source]¶
Directional bound for an intersection requires solving a constrained maximization problem.
In general, picking the component set with the smallest support value is NOT correct, because the corresponding support point need not satisfy the other constraints.
- Use:
support_upper_bound(direction) for a safe upper bound
feasible_lower_bound(direction) for a safe (feasible) lower bound
or supply/implement an optimizer to solve the true problem.
- feasible_lower_bound(direction: Vector, /, *, rtol: float = 1e-06) tuple['Vector' | None, float][source]¶
Feasible lower bound on the true intersection support.
- Strategy:
Try candidate maximizers from each component set (their directional_bound). Keep the best candidate that is feasible for ALL constraints (i.e., belongs to the intersection).
This is always safe (never overestimates), but may be loose.
- Returns:
x_best is a feasible candidate point (or None if none found)
value_best = ⟨direction, x_best⟩, or -∞ if none found
- Return type:
(x_best, value_best)
- property subsets: List[ConvexSubset]¶
Direct access to the individual convex constraints.
- property support_function: 'SupportFunction' | None¶
Support function of an intersection is not generally available.
- In general,
σ_{∩_i C_i}(q) != min_i σ_{C_i}(q).
The pointwise minimum of support functions is typically NOT sublinear, hence not a valid support function of any closed convex set.
- Returns:
by default. Use support_upper_bound(direction) for a safe upper bound, or provide an optimizer to compute the true support.
- Return type:
None
- support_upper_bound(direction: Vector) float[source]¶
Safe upper bound for the true intersection support.
- Because ∩_i C_i ⊆ C_i for each i, we always have
σ_{∩_i C_i}(q) ≤ min_i σ_{C_i}(q).
- Returns:
min_i σ_{C_i}(direction)
- Return type:
float
- Raises:
ValueError – if any component subset lacks a support function.
- class pygeoinf.subsets.ConvexSubset(form: NonLinearForm, level: float, open_set: bool = False, support_fn: 'SupportFunction' | None = None)[source]¶
Bases:
SublevelSetRepresents a closed convex set via dual representations.
A closed convex set can be equivalently defined by: 1. A sublevel set: S = {x | f(x) <= c} where f is convex 2. Its support function: h(q) = sup{⟨q, x⟩ : x ∈ S}
This class supports both representations. The support function is abstract and must be implemented by all concrete subclasses (Ball, Ellipsoid, etc.).
- check(n_samples: int = 10, /, *, rtol: float = 1e-05, atol: float = 1e-08) None[source]¶
Performs a randomized check of the convexity inequality: f(tx + (1-t)y) <= t*f(x) + (1-t)*f(y)
- Parameters:
n_samples – Number of random pairs to test.
rtol – Relative tolerance.
atol – Absolute tolerance.
- Raises:
AssertionError – If the function is found to be non-convex.
- closure() ConvexSubset[source]¶
Returns the closure of this convex set.
For a convex set S: - If S is already closed ({f <= c}), returns self (no copy needed). - If S is open ({f < c}), returns a new closed version.
The closure is the smallest closed set containing S. Note: The returned object uses the same functional and level as self, with open_set flag set to False.
- Returns:
A ConvexSubset instance (subclass) representing cl(S).
- Return type:
- abstract directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point and support value in a given direction.
- For a convex set S and direction q, computes:
x_max = argmax{⟨q, x⟩ : x ∈ S} h(q) = sup{⟨q, x⟩ : x ∈ S}
This method must be implemented by all concrete ConvexSubset subclasses.
- Parameters:
direction – A vector q specifying the direction.
- Returns:
- (x_max, h(q)) where x_max achieves the supremum
and h(q) is the support function value.
- Return type:
tuple[Vector, float]
- Raises:
NotImplementedError – If not implemented for this set type.
- property is_closed: bool¶
Returns True if the set is closed (defined by <=), False if open (<).
- property support_fn: 'SupportFunction' | None¶
Access the stored support function object, if any.
- abstract property support_function: 'SupportFunction' | None¶
Returns the SupportFunction instance for this set, or None if unavailable.
This property should not raise errors if the support function cannot be created (e.g., missing inverse operators for ellipsoids). The SupportFunction itself is responsible for raising errors when required inputs are missing during evaluation.
- class pygeoinf.subsets.Ellipsoid(domain: HilbertSpace, center: Vector, radius: float, operator: LinearOperator, open_set: bool = False, *, inverse_operator: LinearOperator | None = None, inverse_sqrt_operator: LinearOperator | None = None)[source]¶
Bases:
ConvexSubset,_EllipsoidalGeometryRepresents a solid ellipsoid: E = {x | <A(x-c), x-c> <= r^2}.
- directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point in given direction.
- For an ellipsoid E(c, r, A) and direction q:
x_max = c + r * (A^{-1} q) / ||A^{-1/2} q|| h(q) = support_function(q)
- Parameters:
direction – The direction vector q.
- Returns:
(x_max, h(q))
- Return type:
tuple[Vector, float]
- property normalized: NormalisedEllipsoid¶
Returns a normalized version of this ellipsoid with radius 1. The operator is scaled by 1/r^2 to represent the same set.
- property support_function: SupportFunction¶
Returns the support function object for this ellipsoid.
This property does not require inverse operators at construction time. The returned SupportFunction will raise errors if missing operators are required for evaluation.
- class pygeoinf.subsets.EllipsoidSurface(domain: HilbertSpace, center: Vector, radius: float, operator: LinearOperator)[source]¶
Bases:
LevelSet,_EllipsoidalGeometryRepresents the surface of an ellipsoid: S = {x | <A(x-c), x-c> = r^2}.
- property normalized: EllipsoidSurface¶
Returns a normalized version of this surface with radius 1.
- class pygeoinf.subsets.EmptySet(domain: HilbertSpace | None = None)[source]¶
Bases:
SubsetRepresents the empty set (∅).
- property is_empty: bool¶
Returns True, as this is the empty set.
- class pygeoinf.subsets.HalfSpace(domain: HilbertSpace, normal_vector: Vector, offset: float, inequality_type: str = '<=')[source]¶
Bases:
SubsetRepresents a half-space in a Hilbert space: H_+ = {x | ⟨a, x⟩ ≤ b}.
A half-space is an unbounded convex set defined by a linear inequality. It is the epigraph or hypograph of a linear functional, depending on the orientation of the normal vector.
- property boundary: Subset¶
Returns the boundary of the half-space.
The boundary of {x | ⟨a, x⟩ ≤ b} is the hyperplane {x | ⟨a, x⟩ = b}.
- Returns:
The boundary hyperplane.
- Return type:
- distance_to(x: Vector) float[source]¶
Computes the perpendicular distance from x to the half-space boundary.
For a point inside the half-space, returns the distance to the boundary plane ⟨a, x⟩ = b. For points outside, distance is negative (by convention).
Distance = (⟨a, x⟩ - b) / ||a|| (unsigned distance to boundary plane)
- Parameters:
x – A vector from the domain.
- Returns:
- The signed distance to the boundary plane:
Positive if x is on the “outside” (violating constraint)
Negative if x is inside the half-space
Zero if x is on the boundary
- Return type:
float
- property inequality_type: str¶
‘<=’ or ‘>=’.
- Type:
The inequality type
- is_bounded() bool[source]¶
Returns False, as half-spaces are unbounded convex sets.
A half-space extends to infinity in at least one direction.
- Returns:
Always False for half-spaces.
- Return type:
bool
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if x lies within the half-space.
For ‘<=’ type: checks if ⟨a, x⟩ ≤ b + rtol * max(1, |b|). For ‘>=’ type: checks if ⟨a, x⟩ ≥ b - rtol * max(1, |b|).
- Parameters:
x – A vector from the domain.
rtol – Relative tolerance for the inequality check.
- Returns:
True if x satisfies the half-space inequality.
- Return type:
bool
- property is_empty: bool¶
Returns False. A half-space is never empty.
Mathematically, any half-space {x | ⟨a, x⟩ ≤ b} or {x | ⟨a, x⟩ ≥ b} is non-empty in a Hilbert space.
- Returns:
Always False.
- Return type:
bool
- property normal_norm: float¶
The Euclidean norm of the normal vector.
- property normal_vector: Vector¶
The normal vector defining the half-space.
- property offset: float¶
The offset scalar b in the definition ⟨a, x⟩ ≤ b or ⟨a, x⟩ ≥ b.
- project(x: Vector) Vector[source]¶
Projects a point onto the half-space boundary.
This is the orthogonal projection onto the boundary hyperplane {z | ⟨a, z⟩ = b}, which is independent of inequality type.
Projection: x_proj = x - ((⟨a, x⟩ - b) / ||a||²) * a
- Parameters:
x – A vector from the domain.
- Returns:
The orthogonal projection of x onto the boundary plane.
- Return type:
Vector
- property support_function: HalfSpaceSupportFunction¶
Returns the support function for this half-space.
Note
Half-spaces are UNBOUNDED, so their support functions are infinite in SOME directions (depends on query q and inequality type). The support function may raise ValueError when unbounded. This property is provided for completeness and theoretical consistency with other convex sets.
Half-spaces are more useful as constraints in optimization (via their indicator functions) rather than through support functions.
- Returns:
- Support function (may raise
ValueError when called with unbounded directions).
- Return type:
- class pygeoinf.subsets.HyperPlane(domain: HilbertSpace, normal_vector: Vector, offset: float)[source]¶
Bases:
SubsetRepresents a hyperplane in a Hilbert space: H = {x | ⟨a, x⟩ = b}.
A hyperplane is a flat affine subspace of codimension 1, defined by a normal vector ‘a’ and an offset scalar ‘b’.
- property boundary: Subset¶
Returns the boundary of the hyperplane (itself). A hyperplane is ‘thin’ so its boundary is itself.
- dimension() int[source]¶
Returns the geometric dimension of the hyperplane: dim(domain) - 1.
A hyperplane has codimension 1.
- Returns:
The dimension of this hyperplane subspace.
- Return type:
int
- distance_to(x: Vector) float[source]¶
Computes the perpendicular distance from x to the hyperplane.
Distance = |⟨a, x⟩ - b| / ||a||
- Parameters:
x – A vector from the domain.
- Returns:
The perpendicular distance from x to this hyperplane.
- Return type:
float
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if x lies on the hyperplane.
Checks if ⟨a, x⟩ ≈ b within relative tolerance.
- Parameters:
x – A vector from the domain.
rtol – Relative tolerance for the equality check.
- Returns:
True if |⟨a, x⟩ - b| ≤ rtol * max(1, |b|).
- Return type:
bool
- property normal_norm: float¶
The Euclidean norm of the normal vector.
- property normal_vector: Vector¶
The normal vector defining the hyperplane.
- property offset: float¶
The offset scalar b in the definition ⟨a, x⟩ = b.
- class pygeoinf.subsets.Intersection(subsets: Iterable[Subset])[source]¶
Bases:
SubsetRepresents the generic intersection of multiple subsets: S = S_1 ∩ S_2 …
Used when the subsets cannot be mathematically combined into a single functional (e.g., non-convex sets).
- property boundary: Subset¶
Returns the boundary of the intersection.
The general topological boundary is complex: ∂(A ∩ B) ⊆ (∂A ∩ B) ∪ (A ∩ ∂B). Currently raises NotImplementedError.
- property complement: Subset¶
Returns the complement of the intersection.
Applies De Morgan’s Law: (A ∩ B)^c = A^c ∪ B^c. Returns a Union of the complements.
- class pygeoinf.subsets.LevelSet(form: NonLinearForm, level: float)[source]¶
Bases:
SubsetRepresents a level set of a functional: S = {x | f(x) = c}.
- property boundary: Subset¶
Returns the boundary of the level set. Assuming regularity, a level set is a closed manifold without boundary.
- property form: NonLinearForm¶
The defining functional f(x).
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if f(x) is approximately equal to c. Tolerance is scaled by max(1.0, |c|).
- property level: float¶
The scalar value c.
- class pygeoinf.subsets.NormalisedEllipsoid(domain: HilbertSpace, center: Vector, operator: LinearOperator, open_set: bool = False)[source]¶
Bases:
EllipsoidRepresents a normalised ellipsoid with radius 1: E = {x | <A(x-c), x-c> <= 1}.
- class pygeoinf.subsets.PolyhedralSet(domain: HilbertSpace, half_spaces: list['HalfSpace'])[source]¶
Bases:
SubsetRepresents a polyhedral set as the intersection of half-spaces.
P = {x | ⟨a_i, x⟩ ≤ b_i for all i} ∩ {x | ⟨a_j, x⟩ ≥ b_j for all j}
A polyhedral set is a closed, bounded or unbounded convex set defined as the intersection of finitely many half-spaces.
- property boundary: Subset¶
Returns the boundary of the polyhedral set.
The boundary consists of faces where one or more constraints are active (⟨a_i, x⟩ = b_i). Computing the complete boundary is complex in general Hilbert spaces, so this raises NotImplementedError.
- Raises:
NotImplementedError – General polyhedral boundary computation is not yet implemented for arbitrary Hilbert spaces.
- property half_spaces: list[HalfSpace]¶
Returns the list of half-spaces defining this polyhedral set.
- is_bounded() bool[source]¶
Check if the polyhedral set is bounded.
A polyhedral set is bounded iff it’s a polytope (all variables have finite bounds). This check is non-trivial in general Hilbert spaces and is not yet implemented.
- Returns:
Raises NotImplementedError.
- Return type:
bool
- Raises:
NotImplementedError – Boundedness detection for general polyhedral sets is not yet implemented.
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Check if x belongs to the polyhedral set.
x ∈ P iff x satisfies all half-space constraints.
- Parameters:
x – A vector from the domain.
rtol – Relative tolerance for constraint checks.
- Returns:
True if x satisfies all half-space constraints.
- Return type:
bool
- property is_empty: bool¶
Check if the polyhedral set is empty.
A polyhedral set is empty iff the intersection of half-spaces is empty. This is a feasibility problem and requires LP techniques to determine precisely.
- Returns:
Raises NotImplementedError.
- Return type:
bool
- Raises:
NotImplementedError – Emptiness checking for general polyhedral sets requires LP feasibility testing, not yet implemented.
- property support_function: SupportFunction | None¶
Returns the support function of the polyhedral set.
For a polyhedral set P = ∩_i H_i (intersection of half-spaces), the support function is:
σ_P(q) = inf_{i} σ_{H_i}(q)
However, evaluating the infimum of support functions is complex and may require iterative methods (e.g., linear programming).
- Returns:
- Support function for general polyhedral sets is not yet
implemented. Consider using the half-space constraints directly in optimization or implementing LP-based evaluation.
- Return type:
None
Note
For specific cases (e.g., bounded polytopes or simplices), specialized implementations are available in other modules.
- class pygeoinf.subsets.Sphere(domain: HilbertSpace, center: Vector, radius: float)[source]¶
Bases:
EllipsoidSurfaceRepresents a sphere in a Hilbert space: S = {x | ||x - c||^2 = r^2}. This is an EllipsoidSurface where A is the Identity operator.
- class pygeoinf.subsets.SublevelSet(form: NonLinearForm, level: float, open_set: bool = False)[source]¶
Bases:
SubsetRepresents a sublevel set defined by a functional: S = {x | f(x) <= c}.
This class serves as a base for sets defined by inequalities. Unlike ConvexSubset, it does not assume the defining functional is convex.
- property boundary: Subset¶
Returns the boundary of the sublevel set. The boundary is typically the LevelSet {x | f(x) = c}.
- property form: NonLinearForm¶
The defining functional f(x).
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if f(x) <= c (or < c). Tolerance is scaled by max(1.0, |c|).
- property is_open: bool¶
True if the set is defined by strict inequality.
- property level: float¶
The scalar upper bound c.
- class pygeoinf.subsets.Subset(domain: HilbertSpace | None = None)[source]¶
Bases:
ABCAbstract base class for a subset of a HilbertSpace.
This class defines the minimal interface required for a mathematical set: knowing which space it lives in, determining if a vector belongs to it, accessing its boundary, and performing logical set operations.
- abstract property boundary: Subset¶
Returns the boundary of the subset.
- Returns:
A new Subset instance representing ∂S.
- Return type:
- property complement: Subset¶
S^c = {x | x not in S}.
- Returns:
A generic Complement wrapper around this set.
- Return type:
- Type:
Returns the complement of this set
- property domain: HilbertSpace¶
The underlying Hilbert space.
- Returns:
The HilbertSpace instance associated with this subset.
- Raises:
ValueError – If the domain was not set during initialization.
- intersect(other: Subset) Subset[source]¶
Returns the intersection of this set and another: S ∩ O.
If both sets are instances of ConvexSubset, this returns a ConvexIntersection, which combines their functionals into a single convex constraint F(x) = max(f1(x), f2(x)).
- Parameters:
other – Another Subset instance.
- Returns:
A new set representing elements present in both sets.
- Return type:
- abstract is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if the vector x lies within the subset.
- Parameters:
x – A vector from the domain.
rtol – Relative tolerance for floating-point comparisons (e.g., checking equality f(x) = c or inequality f(x) <= c).
- Returns:
True if x ∈ S, False otherwise.
- Return type:
bool
- property is_empty: bool¶
Returns True if the set is known to be empty.
- Returns:
True if the set contains no elements, False otherwise. Note that returning False does not guarantee the set is non-empty, only that it is not trivially known to be empty.
- Return type:
bool
- plot(on_subspace=None, *, bounds=None, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax=None, backend: str = 'auto')[source]¶
Visualize this subset along a 1D, 2D, or 3D affine subspace.
Delegates to pygeoinf.plot.plot_slice. For EuclideanSpace domains of dimension 1 or 2, on_subspace may be omitted and a canonical full-space
AffineSubspacewill be constructed automatically. For all other domains, on_subspace is required.- Parameters:
on_subspace – The
AffineSubspaceto slice along. Required unless the domain is a 1D or 2DEuclideanSpace.bounds – Plot bounds passed to
plot_slice.grid_size – Samples per axis (passed to
plot_slice).rtol – Oracle tolerance (passed to
plot_slice).alpha – Fill transparency in [0, 1] (passed to
plot_slice).cmap – Colormap for 2D plots (passed to
plot_slice).color – Color string for 1D plots (passed to
plot_slice).show_plot – Whether to call
plt.show()(passed toplot_slice).ax – Optional existing
Axesto draw into (passed toplot_slice).backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"(passed toplot_slice).
- Returns:
(fig, ax, payload)— identical toplot_slice.- Raises:
ValueError – If on_subspace is
Noneand the domain is not a 1D or 2DEuclideanSpace.TypeError – If the domain is not an
EuclideanSpace.
- class pygeoinf.subsets.Union(subsets: Iterable[Subset])[source]¶
Bases:
SubsetRepresents the union of multiple subsets: S = S_1 ∪ S_2 …
- property complement: Subset¶
Returns the complement of the union.
Applies De Morgan’s Law: (A ∪ B)^c = A^c ∩ B^c. Returns an Intersection of the complements.
- class pygeoinf.subsets.UniversalSet(domain: HilbertSpace | None = None)[source]¶
Bases:
SubsetRepresents the entire domain (Ω).
pygeoinf.subspaces module¶
Defines classes for representing affine and linear subspaces, including hyperplanes and half-spaces.
The primary abstraction is the AffineSubspace, which represents a subset of a Hilbert space defined by a translation and a closed linear tangent space. This module integrates with the subset module, allowing subspaces to be treated as standard geometric sets.
- class pygeoinf.subspaces.AffineSubspace(projector: OrthogonalProjector, translation: Vector | None = None, constraint_operator: LinearOperator | None = None, constraint_value: Vector | None = None, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None)[source]¶
Bases:
SubsetRepresents an affine subspace A = x0 + V.
This class serves two primary roles: 1. A geometric subset that can project points and check membership. 2. A constraint definition for Bayesian inversion (conditioning a Gaussian
measure on the subspace).
- property boundary: Subset¶
Returns the boundary of the affine subspace.
Geometrically, an affine subspace (like a line or plane) is a closed manifold without a boundary. Returns EmptySet.
- condition_gaussian_measure(prior: GaussianMeasure, geometric: bool = False) GaussianMeasure[source]¶
Conditions a Gaussian measure on this subspace.
- Parameters:
prior – The prior Gaussian measure.
geometric – If True, performs a geometric projection of the measure (equivalent to conditioning on “measurement = truth” with infinite precision, effectively squashing the distribution onto the subspace). If False (default), performs standard Bayesian conditioning using the constraint equation B(u) = w.
- Returns:
The posterior (conditioned) GaussianMeasure.
- Raises:
ValueError – If geometric=False and the subspace was constructed without a solver capable of handling the constraint operator.
- property constraint_operator: LinearOperator¶
Returns the operator B defining the subspace as {u | B(u)=w}.
If no explicit operator was provided (geometric construction), this falls back to the complement projector (I - P).
- property constraint_value: Vector¶
Returns the value w defining the subspace as {u | B(u)=w}.
If no explicit operator was provided, this falls back to (I - P)x0.
- classmethod from_complement_basis(domain: HilbertSpace, basis_vectors: List[Vector], translation: Vector | None = None, orthonormalize: bool = True) AffineSubspace[source]¶
Constructs a subspace defined by orthogonality to a set of complement basis vectors.
The subspace is defined as {u | <u - x0, v_i> = 0} for all v_i in basis. This provides an explicit constraint operator B where B(u)_i = <u, v_i>.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the orthogonal complement.
translation – A point x0 in the subspace.
orthonormalize – If True, orthonormalizes the complement basis.
- classmethod from_hyperplanes(hyperplanes: List[Subset], solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs an affine subspace as the intersection of hyperplanes.
Each hyperplane is defined as {x | ⟨a_i, x⟩ = b_i}. The intersection of m hyperplanes defines an affine subspace of codimension m (assuming the normal vectors are linearly independent).
- Parameters:
hyperplanes – A list of HyperPlane objects from subsets module. All hyperplanes must have the same domain.
solver – Solver used to invert the Gram matrix (B B*) during construction. Defaults to CholeskySolver.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
The affine subspace defined by the intersection.
- Return type:
- Raises:
ValueError – If hyperplanes list is empty or domains don’t match.
ImportError – If hyperplanes don’t have the required attributes.
- classmethod from_linear_equation(operator: LinearOperator, value: Vector, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs a subspace defined by the linear equation B(u) = w.
- Parameters:
operator – The linear operator B.
value – The RHS vector w.
solver – Solver used to invert the Gram matrix (B B*) during construction and later conditioning. Defaults to CholeskySolver.
preconditioner – Optional preconditioner for iterative solvers.
- classmethod from_tangent_basis(domain: HilbertSpace, basis_vectors: List[Vector], translation: Vector | None = None, orthonormalize: bool = True, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs an affine subspace from a translation and a basis for the tangent space.
This method defines the subspace geometrically. The constraint is implicit: (I - P)u = (I - P)x0.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the tangent space V.
translation – A point x0 in the subspace.
orthonormalize – If True, orthonormalizes the basis.
solver – A linear solver capable of handling the singular operator (I-P). Required if you intend to use this subspace for Bayesian conditioning.
preconditioner – Optional preconditioner for the solver.
- get_tangent_basis() List[Vector][source]¶
Returns an orthonormal basis for the tangent space of this affine subspace.
Extracts orthonormal basis vectors that span the tangent space $V$ by applying the projector $P$ to each standard basis vector $e_i$, then performing a tolerant Gram-Schmidt orthogonalisation to discard linearly dependent projections.
- Returns:
Orthonormal basis vectors for the tangent space.
- Return type:
List[Vector]
- property has_explicit_equation: bool¶
True if defined by B(u)=w, False if defined only by geometry.
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if the vector x lies within the subspace.
Checks if the projection residual ||x - P_A(x)|| is small relative to the norm of x (or 1.0).
- Parameters:
x – The vector to check.
rtol – Relative tolerance for the residual check.
- property preconditioner: LinearOperator | None¶
Returns the preconditioner associated with the solver, if any.
- project(x: Vector) Vector[source]¶
Orthogonally projects a vector x onto the affine subspace.
Formula: P_A(x) = P(x - x0) + x0
- property projection_operator: AffineOperator¶
Returns the affine orthogonal projection operator onto the subspace. P_A(x) = P(x) + (I - P)x_0
- property projector: OrthogonalProjector¶
Returns the orthogonal projector P onto the tangent space.
- property pseudo_inverse: LinearOperator¶
Returns the right pseudo-inverse operator B^dagger = B* (B B*)^{-1}.
- property solver: LinearSolver | None¶
Returns the linear solver associated with this subspace.
- property tangent_space: LinearSubspace¶
Returns the LinearSubspace V parallel to this affine subspace.
- to_hyperplanes() List[Subset][source]¶
Decomposes this affine subspace into a minimal set of hyperplanes.
Returns a list of HyperPlane objects whose intersection equals this affine subspace. The number of hyperplanes equals the codimension of the subspace (i.e., the rank of the constraint operator).
- Returns:
The minimal set of hyperplanes defining this subspace.
- Return type:
List[HyperPlane]
- Raises:
ValueError – If the subspace does not have an explicit constraint operator.
ImportError – If HyperPlane class is not available.
- property translation: Vector¶
Returns the translation vector x0.
- with_constraint_value(new_value: Vector) AffineSubspace[source]¶
Returns a new AffineSubspace parallel to this one, shifted to satisfy the new explicit constraint equation B(u) = new_value.
- with_translation(new_translation: Vector) AffineSubspace[source]¶
Returns a new AffineSubspace parallel to this one, shifted to pass through the new translation vector.
- class pygeoinf.subspaces.LinearSubspace(projector: OrthogonalProjector)[source]¶
Bases:
AffineSubspaceRepresents a linear subspace (an affine subspace passing through the origin).
- property complement: LinearSubspace¶
Returns the orthogonal complement of this subspace as a new LinearSubspace.
- classmethod from_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) LinearSubspace[source]¶
Constructs a linear subspace from a set of basis vectors.
- Parameters:
domain – The Hilbert space.
basis_vectors – List of vectors spanning the subspace.
orthonormalize – Whether to orthonormalize the basis.
solver – Optional solver for implicit constraints (see AffineSubspace.from_tangent_basis).
preconditioner – Optional preconditioner.
- classmethod from_complement_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True) LinearSubspace[source]¶
Constructs a linear subspace defined by orthogonality to a complement basis. S = {u | <u, v_i> = 0}.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the complement.
orthonormalize – Whether to orthonormalize the complement basis.
- classmethod from_kernel(operator: LinearOperator, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) LinearSubspace[source]¶
Constructs the subspace corresponding to the kernel (null space) of an operator. K = {u | A(u) = 0}.
- Parameters:
operator – The operator A.
solver – Solver used for the Gram matrix (A A*).
preconditioner – Optional preconditioner.
- class pygeoinf.subspaces.OrthogonalProjector(domain: HilbertSpace, mapping: Callable[[Any], Any], complement_projector: LinearOperator | None = None)[source]¶
Bases:
LinearOperatorInternal engine for subspace projections. Represents an orthogonal projection operator P = P* = P^2.
- property complement: LinearOperator¶
Returns the projector onto the orthogonal complement (I - P).
If a complement projector was not provided at initialization, one is constructed automatically as the difference between the identity and self.
- classmethod from_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True) OrthogonalProjector[source]¶
Constructs a projector P onto the span of the provided basis vectors.
- Parameters:
domain – The Hilbert space.
basis_vectors – A list of vectors spanning the subspace.
orthonormalize – If True, performs Gram-Schmidt orthonormalization on the basis vectors before constructing the projector. If False, assumes the basis is already orthonormal.
- Returns:
An OrthogonalProjector instance.
pygeoinf.utils module¶
- pygeoinf.utils.configure_threading(n_threads: int = 1)[source]¶
Sets the maximum number of threads used by underlying linear algebra backends (MKL, OpenBLAS, etc.).
- Parameters:
n_threads – The number of threads to allow. Set to 1 for serial execution (safe for multiprocessing). Set to -1 or None to use all available cores.
Module contents¶
Unified imports for the package.
- class pygeoinf.AffineOperator(linear_part: LinearOperator, translation: Any)[source]¶
Bases:
AffineOperatorAxiomChecks,NonLinearOperatorRepresents an affine transformation between two Hilbert spaces.
An affine operator is a mapping F(x) = A(x) + b, where ‘A’ is a bounded linear operator and ‘b’ is a fixed translation vector in the codomain.
- property linear_part: LinearOperator¶
The underlying linear mapping ‘A’.
- property translation_part: Any¶
The translation vector ‘b’.
- class pygeoinf.AffineSubspace(projector: OrthogonalProjector, translation: Vector | None = None, constraint_operator: LinearOperator | None = None, constraint_value: Vector | None = None, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None)[source]¶
Bases:
SubsetRepresents an affine subspace A = x0 + V.
This class serves two primary roles: 1. A geometric subset that can project points and check membership. 2. A constraint definition for Bayesian inversion (conditioning a Gaussian
measure on the subspace).
- property boundary: Subset¶
Returns the boundary of the affine subspace.
Geometrically, an affine subspace (like a line or plane) is a closed manifold without a boundary. Returns EmptySet.
- condition_gaussian_measure(prior: GaussianMeasure, geometric: bool = False) GaussianMeasure[source]¶
Conditions a Gaussian measure on this subspace.
- Parameters:
prior – The prior Gaussian measure.
geometric – If True, performs a geometric projection of the measure (equivalent to conditioning on “measurement = truth” with infinite precision, effectively squashing the distribution onto the subspace). If False (default), performs standard Bayesian conditioning using the constraint equation B(u) = w.
- Returns:
The posterior (conditioned) GaussianMeasure.
- Raises:
ValueError – If geometric=False and the subspace was constructed without a solver capable of handling the constraint operator.
- property constraint_operator: LinearOperator¶
Returns the operator B defining the subspace as {u | B(u)=w}.
If no explicit operator was provided (geometric construction), this falls back to the complement projector (I - P).
- property constraint_value: Vector¶
Returns the value w defining the subspace as {u | B(u)=w}.
If no explicit operator was provided, this falls back to (I - P)x0.
- classmethod from_complement_basis(domain: HilbertSpace, basis_vectors: List[Vector], translation: Vector | None = None, orthonormalize: bool = True) AffineSubspace[source]¶
Constructs a subspace defined by orthogonality to a set of complement basis vectors.
The subspace is defined as {u | <u - x0, v_i> = 0} for all v_i in basis. This provides an explicit constraint operator B where B(u)_i = <u, v_i>.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the orthogonal complement.
translation – A point x0 in the subspace.
orthonormalize – If True, orthonormalizes the complement basis.
- classmethod from_hyperplanes(hyperplanes: List[Subset], solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs an affine subspace as the intersection of hyperplanes.
Each hyperplane is defined as {x | ⟨a_i, x⟩ = b_i}. The intersection of m hyperplanes defines an affine subspace of codimension m (assuming the normal vectors are linearly independent).
- Parameters:
hyperplanes – A list of HyperPlane objects from subsets module. All hyperplanes must have the same domain.
solver – Solver used to invert the Gram matrix (B B*) during construction. Defaults to CholeskySolver.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
The affine subspace defined by the intersection.
- Return type:
- Raises:
ValueError – If hyperplanes list is empty or domains don’t match.
ImportError – If hyperplanes don’t have the required attributes.
- classmethod from_linear_equation(operator: LinearOperator, value: Vector, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs a subspace defined by the linear equation B(u) = w.
- Parameters:
operator – The linear operator B.
value – The RHS vector w.
solver – Solver used to invert the Gram matrix (B B*) during construction and later conditioning. Defaults to CholeskySolver.
preconditioner – Optional preconditioner for iterative solvers.
- classmethod from_tangent_basis(domain: HilbertSpace, basis_vectors: List[Vector], translation: Vector | None = None, orthonormalize: bool = True, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) AffineSubspace[source]¶
Constructs an affine subspace from a translation and a basis for the tangent space.
This method defines the subspace geometrically. The constraint is implicit: (I - P)u = (I - P)x0.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the tangent space V.
translation – A point x0 in the subspace.
orthonormalize – If True, orthonormalizes the basis.
solver – A linear solver capable of handling the singular operator (I-P). Required if you intend to use this subspace for Bayesian conditioning.
preconditioner – Optional preconditioner for the solver.
- get_tangent_basis() List[Vector][source]¶
Returns an orthonormal basis for the tangent space of this affine subspace.
Extracts orthonormal basis vectors that span the tangent space $V$ by applying the projector $P$ to each standard basis vector $e_i$, then performing a tolerant Gram-Schmidt orthogonalisation to discard linearly dependent projections.
- Returns:
Orthonormal basis vectors for the tangent space.
- Return type:
List[Vector]
- property has_explicit_equation: bool¶
True if defined by B(u)=w, False if defined only by geometry.
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if the vector x lies within the subspace.
Checks if the projection residual ||x - P_A(x)|| is small relative to the norm of x (or 1.0).
- Parameters:
x – The vector to check.
rtol – Relative tolerance for the residual check.
- property preconditioner: LinearOperator | None¶
Returns the preconditioner associated with the solver, if any.
- project(x: Vector) Vector[source]¶
Orthogonally projects a vector x onto the affine subspace.
Formula: P_A(x) = P(x - x0) + x0
- property projection_operator: AffineOperator¶
Returns the affine orthogonal projection operator onto the subspace. P_A(x) = P(x) + (I - P)x_0
- property projector: OrthogonalProjector¶
Returns the orthogonal projector P onto the tangent space.
- property pseudo_inverse: LinearOperator¶
Returns the right pseudo-inverse operator B^dagger = B* (B B*)^{-1}.
- property solver: LinearSolver | None¶
Returns the linear solver associated with this subspace.
- property tangent_space: LinearSubspace¶
Returns the LinearSubspace V parallel to this affine subspace.
- to_hyperplanes() List[Subset][source]¶
Decomposes this affine subspace into a minimal set of hyperplanes.
Returns a list of HyperPlane objects whose intersection equals this affine subspace. The number of hyperplanes equals the codimension of the subspace (i.e., the rank of the constraint operator).
- Returns:
The minimal set of hyperplanes defining this subspace.
- Return type:
List[HyperPlane]
- Raises:
ValueError – If the subspace does not have an explicit constraint operator.
ImportError – If HyperPlane class is not available.
- property translation: Vector¶
Returns the translation vector x0.
- with_constraint_value(new_value: Vector) AffineSubspace[source]¶
Returns a new AffineSubspace parallel to this one, shifted to satisfy the new explicit constraint equation B(u) = new_value.
- with_translation(new_translation: Vector) AffineSubspace[source]¶
Returns a new AffineSubspace parallel to this one, shifted to pass through the new translation vector.
- pygeoinf.BICGMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- pygeoinf.BICGStabMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.BICGStabSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the BiCGStab algorithm.
Suitable for non-symmetric linear systems Ax = y. It operates directly on Hilbert space vectors using native inner products and arithmetic.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.Ball(domain: HilbertSpace, center: Vector, radius: float, open_set: bool = True)[source]¶
Bases:
EllipsoidRepresents a ball in a Hilbert space: B = {x | ||x - c||^2 <= r^2}. This is an Ellipsoid where A is the Identity operator.
- directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point in direction of ‘direction’.
- For a ball B(c, r) and direction q:
x_max = c + r * (q / ||q||) h(q) = ⟨q, c⟩ + r||q||
- Parameters:
direction – The direction vector q.
- Returns:
(x_max, h(q))
- Return type:
tuple[Vector, float]
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if x lies within the ball. Optimized to use geometric distance ||x-c|| directly.
- property support_function: SupportFunction¶
Returns the support function object for this ball.
Always available for valid Ball instances.
- class pygeoinf.BallSupportFunction(primal_domain: HilbertSpace, center: Vector, radius: float)[source]¶
Bases:
SupportFunctionSupport function of a closed ball B(c, r) = {x : ||x - c|| ≤ r}:
h(q) = ⟨q, c⟩ + r ||q||
- support_point(q: Vector) 'Vector' | None[source]¶
Return x* = c + r * (q / ||q||) achieving the supremum.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))computing $|q|$ once.Both $h(q) = langle q, c rangle + r|q|$ and $x^*(q) = c + r , q / |q|$ depend on $|q|$, so computing it once halves the number of norm evaluations compared to the default two-call fallback.
- Parameters:
q – A vector in the primal domain $H$.
- Returns:
(value, point)wherevalue$= h(q)$ andpoint$= x^*(q)$, or the center $c$ when $q approx 0$.
- class pygeoinf.BandedPreconditioningMethod(bandwidth: int, /, *, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a symmetrically banded sparse preconditioner.
Extracts a symmetric band of diagonals from the operator’s Galerkin matrix representation, constructs a sparse matrix, and uses a sparse direct solver (exact or incomplete LU) to invert it.
- class pygeoinf.BlockDiagonalLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureA block operator where all off-diagonal blocks are zero operators.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
If i equals j, this is one of the diagonal operators. Otherwise, it is a zero operator.
- class pygeoinf.BlockLinearOperator(blocks: List[List[LinearOperator]])[source]¶
Bases:
LinearOperator,BlockStructureA linear operator between direct sum spaces, defined by a matrix of sub-operators.
This operator acts like a matrix where each entry is itself a LinearOperator. It maps a list of input vectors [x_1, x_2, …] to a list of output vectors [y_1, y_2, …]. The constructor checks for dimensional consistency between the blocks.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
- class pygeoinf.BlockStructure(row_dim: int, col_dim: int)[source]¶
Bases:
ABCAn abstract base class for operators with a block structure.
- abstract block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, j)-th sub-block.
- property col_dim: int¶
Returns the number of columns in the block structure.
- property row_dim: int¶
Returns the number of rows in the block structure.
- pygeoinf.CGMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.CGSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 0.0, maxiter: int | None = None, callback: Callable[[Vector], None] | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the Conjugate Gradient (CG) algorithm.
This solver operates directly on Hilbert space vectors and operator actions without explicitly forming a matrix. It is suitable for self-adjoint, positive-definite operators on a general Hilbert space.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.CallableSupportFunction(primal_domain: HilbertSpace, fn: Callable[[Vector], float], support_point_fn: Callable[[Vector], Vector] | None = None)[source]¶
Bases:
SupportFunctionSupport function defined by a user-provided callable.
Wraps an arbitrary callable $q mapsto h(q)$ as a
SupportFunction. Optionally accepts a second callable $q mapsto x^*(q)$ that returns the support point (subgradient of $h$ at $q$).- Parameters:
primal_domain – The Hilbert space $H$ on which $h$ is defined.
fn – A callable
fn(q) -> floatcomputing the support value $h(q)$.support_point_fn – An optional callable
support_point_fn(q) -> Vectorreturning $x^*(q) in argmax_{x in C} langle q, x rangle$. When provided,support_point()delegates to it andsubgradient()returns the result. WhenNone,support_point()returnsNoneandsubgradient()raisesNotImplementedError.
Example:
fn = lambda q: float(np.linalg.norm(q)) # L2-ball support sp = lambda q: q / np.linalg.norm(q) # support point h = CallableSupportFunction(space, fn, support_point_fn=sp)
- class pygeoinf.CholeskySolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on Cholesky decomposition.
- class pygeoinf.ColumnLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureAn operator that maps from a single space to a direct sum space.
It can be visualized as a column vector of operators, [A_1, A_2, …]^T. It takes a single input vector x and produces a list of output vectors [A_1(x), A_2(x), …]. This is often used to represent a joint forward operator in an inverse problem.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (i, 0)-th sub-block.
- class pygeoinf.ColumnThresholdedPreconditioningMethod(threshold: float, /, *, max_nnz: int | None = None, galerkin: bool = True, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a sparse preconditioner by evaluating the operator column-by-column, dropping elements that are small relative to the diagonal element, and optionally capping the maximum number of retained non-zeros per column.
- class pygeoinf.Complement(subset: Subset)[source]¶
Bases:
SubsetRepresents the complement of a set: S^c = {x | x ∉ S}.
- class pygeoinf.ConstrainedLinearLeastSquaresInversion(forward_problem: LinearForwardProblem, constraint: AffineSubspace, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem subject to an affine subspace constraint.
This method finds the model u that minimizes the Tikhonov-regularized least-squares functional while strictly confining the solution to an affine subspace (e.g., enforcing a specific average property value or boundary condition).
Supports both ‘model_space’ and ‘data_space’ formalisms for the underlying unconstrained inversion.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearLeastSquaresInversion[source]¶
Constructs a surrogate of the constrained linear inversion using a reduced data space.
- least_squares_operator(damping: float, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None) AffineOperator[source]¶
Returns an operator that maps data to the constrained least-squares solution.
- normal_residual_callback(damping: float, data: Vector, /, *, message: str = 'Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True)[source]¶
Generates a ResidualTrackingCallback for the reduced, unconstrained normal equations.
- parameterized_inversion(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearLeastSquaresInversion[source]¶
Constructs a parameterized surrogate of the constrained least-squares inversion.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new ConstrainedLinearLeastSquaresInversion instance operating on the parameter space.
- with_formalism(formalism: Literal['model_space', 'data_space']) ConstrainedLinearLeastSquaresInversion[source]¶
Returns a new instance of the constrained inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new ConstrainedLinearLeastSquaresInversion instance with the updated formalism.
- class pygeoinf.ConstrainedLinearMinimumNormInversion(forward_problem: LinearForwardProblem, constraint: AffineSubspace, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionFinds the minimum-norm solution subject to an affine subspace constraint.
This class solves the regularized inverse problem using the discrepancy principle while strictly confining the solution to an affine subspace.
- constraint_value_mapping(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator[source]¶
Returns an operator mapping a constraint value ‘w’ to the corresponding constrained minimum norm solution ‘u’ for a strictly fixed dataset. The operator has its derivative set.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearMinimumNormInversion[source]¶
Constructs a surrogate of the constrained linear inversion using a reduced data space.
- minimum_norm_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator[source]¶
Returns an operator that maps data to the constrained minimum-norm solution. The operator has its derivative set.
- parameterized_inversion(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) ConstrainedLinearMinimumNormInversion[source]¶
Constructs a parameterized surrogate of the constrained minimum norm inversion.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new ConstrainedLinearMinimumNormInversion instance operating on the parameter space.
- with_formalism(formalism: Literal['model_space', 'data_space']) ConstrainedLinearMinimumNormInversion[source]¶
Returns a new instance of the constrained inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new ConstrainedLinearMinimumNormInversion instance with the updated formalism.
- class pygeoinf.ConvexSubset(form: NonLinearForm, level: float, open_set: bool = False, support_fn: 'SupportFunction' | None = None)[source]¶
Bases:
SublevelSetRepresents a closed convex set via dual representations.
A closed convex set can be equivalently defined by: 1. A sublevel set: S = {x | f(x) <= c} where f is convex 2. Its support function: h(q) = sup{⟨q, x⟩ : x ∈ S}
This class supports both representations. The support function is abstract and must be implemented by all concrete subclasses (Ball, Ellipsoid, etc.).
- check(n_samples: int = 10, /, *, rtol: float = 1e-05, atol: float = 1e-08) None[source]¶
Performs a randomized check of the convexity inequality: f(tx + (1-t)y) <= t*f(x) + (1-t)*f(y)
- Parameters:
n_samples – Number of random pairs to test.
rtol – Relative tolerance.
atol – Absolute tolerance.
- Raises:
AssertionError – If the function is found to be non-convex.
- closure() ConvexSubset[source]¶
Returns the closure of this convex set.
For a convex set S: - If S is already closed ({f <= c}), returns self (no copy needed). - If S is open ({f < c}), returns a new closed version.
The closure is the smallest closed set containing S. Note: The returned object uses the same functional and level as self, with open_set flag set to False.
- Returns:
A ConvexSubset instance (subclass) representing cl(S).
- Return type:
- abstract directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point and support value in a given direction.
- For a convex set S and direction q, computes:
x_max = argmax{⟨q, x⟩ : x ∈ S} h(q) = sup{⟨q, x⟩ : x ∈ S}
This method must be implemented by all concrete ConvexSubset subclasses.
- Parameters:
direction – A vector q specifying the direction.
- Returns:
- (x_max, h(q)) where x_max achieves the supremum
and h(q) is the support function value.
- Return type:
tuple[Vector, float]
- Raises:
NotImplementedError – If not implemented for this set type.
- property is_closed: bool¶
Returns True if the set is closed (defined by <=), False if open (<).
- property support_fn: 'SupportFunction' | None¶
Access the stored support function object, if any.
- abstract property support_function: 'SupportFunction' | None¶
Returns the SupportFunction instance for this set, or None if unavailable.
This property should not raise errors if the support function cannot be created (e.g., missing inverse operators for ellipsoids). The SupportFunction itself is responsible for raising errors when required inputs are missing during evaluation.
- class pygeoinf.DenseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray, /, *, galerkin=False)[source]¶
Bases:
MatrixLinearOperatorA specialisation of the MatrixLinearOperator class to instances where the matrix representation is always provided as a numpy array.
This is a class provides some additional methods for component-wise access.
- static from_linear_operator(operator: LinearOperator, /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) DenseMatrixLinearOperator[source]¶
Converts a LinearOperator into a DenseMatrixLinearOperator by forming its dense matrix representation.
- Parameters:
operator – The operator to be converted.
galerkin – If True, the Galerkin representation is used. Default is False.
parallel – If True, dense matrix calculation is done in parallel. Default is False.
n_jobs – Number of jobs used for parallel calculations. Default is False.
- class pygeoinf.DiagonalSparseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, diagonals: Tuple[np.ndarray, List[int]], /, *, galerkin: bool = False)[source]¶
Bases:
SparseMatrixLinearOperatorA highly specialized operator for matrices defined purely by a set of non-zero diagonals.
This class internally stores the operator using a scipy.sparse.dia_array for maximum efficiency in storage and matrix-vector products. It provides extremely fast methods for extracting diagonals, as this is its native storage format.
A key feature of this class is its support for functional calculus. It dynamically proxies element-wise mathematical functions (e.g., .sqrt(), .log(), abs(), **) to the underlying sparse array. For reasons of mathematical correctness, these operations are restricted to operators that are strictly diagonal (i.e., have only a non-zero main diagonal) and will raise a NotImplementedError otherwise.
Aggregation methods that do not return a new operator (e.g., .sum()) are not restricted and can be used on any multi-diagonal operator.
Class Methods¶
- from_diagonal_values:
Constructs a strictly diagonal operator from a 1D array of values.
- from_operator:
Creates a diagonal approximation of another LinearOperator.
Properties¶
- offsets:
The array of stored diagonal offsets.
- is_strictly_diagonal:
True if the operator only has a non-zero main diagonal.
- inverse:
The inverse of a strictly diagonal operator.
- sqrt:
The square root of a strictly diagonal operator.
- apply_function(func: str | Callable[[ndarray], ndarray]) DiagonalSparseMatrixLinearOperator[source]¶
Applies a function to the diagonal values (eigenvalues) of the operator.
This supports functional calculus for strictly diagonal operators. For maximum performance, pass a NumPy ufunc (e.g., np.sqrt, np.exp).
- Parameters:
func – A callable function, or the string name of a SciPy sparse method.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = True, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for extreme efficiency.
This operation is nearly free, as it involves selecting the requested diagonals from the data already stored in the native format.
- classmethod from_diagonal_values(domain: HilbertSpace, codomain: HilbertSpace, diagonal_values: np.ndarray, /, *, galerkin: bool = False) DiagonalSparseMatrixLinearOperator[source]¶
Constructs a purely diagonal operator from a 1D array of values.
This provides a convenient way to create an operator with non-zero entries only on its main diagonal (offset k=0).
- Parameters:
domain – The domain of the operator.
codomain – The codomain of the operator. Must have the same dimension.
diagonal_values – A 1D NumPy array of the values for the main diagonal.
galerkin – If True, the operator is in Galerkin form.
- Returns:
A new DiagonalSparseMatrixLinearOperator.
- classmethod from_operator(operator: LinearOperator, offsets: List[int], /, *, galerkin: bool = True) DiagonalSparseMatrixLinearOperator[source]¶
Creates a diagonal approximation of another LinearOperator.
This factory method works by calling the source operator’s .extract_diagonals() method and using the result to construct a new, highly efficient DiagonalSparseMatrixLinearOperator.
- Parameters:
operator – The source operator to approximate.
offsets – The list of diagonal offsets to extract and keep.
galerkin – Specifies which matrix representation to use.
- Returns:
A new DiagonalSparseMatrixLinearOperator.
- property inverse: DiagonalSparseMatrixLinearOperator¶
The inverse of the operator, computed via functional calculus. Requires the operator to be strictly diagonal with no zero entries.
- property is_strictly_diagonal: bool¶
True if the operator only has a non-zero main diagonal (offset=0).
- property offsets: ndarray¶
Returns the array of stored diagonal offsets.
- property sqrt: DiagonalSparseMatrixLinearOperator¶
The square root of the operator, computed via functional calculus. Requires the operator to be strictly diagonal with non-negative entries.
- class pygeoinf.DirectLinearSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverAn abstract base class for direct linear solvers that rely on matrix factorization.
- class pygeoinf.DualHilbertSpace(space: HilbertSpace)[source]¶
Bases:
HilbertSpaceA wrapper class representing the dual of a HilbertSpace.
An element of a dual space is a continuous linear functional, represented in this library by the LinearForm class. This wrapper provides a full HilbertSpace interface for these LinearForm objects, allowing them to be treated as vectors in their own right.
- property dim: int¶
The dimension of the dual space.
- property dual: HilbertSpace¶
The dual of the dual space, which is the original primal space.
- final duality_product(xp: LinearForm, x: Vector) float[source]¶
Computes the duality product <x, xp>.
In this context, x is from the primal space and xp is the dual vector (a LinearForm). This is unconventional but maintains the method signature; it evaluates x(xp).
- from_components(c: np.ndarray) LinearForm[source]¶
Creates a LinearForm from a NumPy component array.
- from_dual(xp: Vector) LinearForm[source]¶
Maps a primal vector to its corresponding dual LinearForm.
- to_components(x: LinearForm) np.ndarray[source]¶
Maps a LinearForm to its NumPy component array.
- to_dual(x: LinearForm) Any[source]¶
Maps a dual vector back to its representative in the primal space.
- property underlying_space: HilbertSpace¶
The primal HilbertSpace of which this is the dual.
- class pygeoinf.DualMasterCostFunction(data_space: HilbertSpace, property_space: HilbertSpace, model_space: HilbertSpace, G: LinearOperator, T: LinearOperator, model_prior_support: SupportFunction, data_error_support: SupportFunction, observed_data: Vector, q_direction: Vector)[source]¶
Bases:
NonLinearFormCost function for the master dual equation (Hilbert form):
h_U(q) = inf_{λ ∈ D}
{ (λ, d̃)_D + σ_B(T* q - G* λ) + σ_V(-λ) }
i.e.
φ(λ; q) = (λ, d̃)_D + σ_B(T* q - G* λ) + σ_V(-λ)
- where:
σ_B is the support function of the model prior convex set B ⊆ M
σ_V is the support function of the data error convex set V ⊆ D
Minimizing φ(λ; q) over λ ∈ D yields h_U(q).
- property direction: Vector¶
Current property direction q ∈ P.
- property observed_data: Vector¶
Observed data vector d̃ ∈ D.
- value_and_subgradient(lam: Vector) tuple[float, Vector][source]¶
Compute the value and a subgradient of $varphi(lambda; q)$ in one pass.
Shares the computation of $G^* lambda$ and the support points $v$, $w$ between the value and subgradient evaluations, avoiding redundant work.
The dual master cost function is
\[\varphi(\lambda; q) = \langle \lambda, \tilde{d} \rangle_D + \sigma_B(T^* q - G^* \lambda) + \sigma_V(-\lambda)\]and a subgradient at $lambda$ is
\[g = \tilde{d} - G v - w,\]where $v in partial sigma_B(T^* q - G^* lambda)$ and $w in partial sigma_V(-lambda)$.
- Parameters:
lam – Dual variable $lambda in D$.
- Returns:
A tuple
(f, g)wheref = φ(λ; q)is the scalar value andg ∈ ∂φ(λ; q)is a subgradient vector in $D$.
- class pygeoinf.EigenSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1, rtol: float = 1e-12)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on the eigendecomposition of a symmetric operator.
- class pygeoinf.Ellipsoid(domain: HilbertSpace, center: Vector, radius: float, operator: LinearOperator, open_set: bool = False, *, inverse_operator: LinearOperator | None = None, inverse_sqrt_operator: LinearOperator | None = None)[source]¶
Bases:
ConvexSubset,_EllipsoidalGeometryRepresents a solid ellipsoid: E = {x | <A(x-c), x-c> <= r^2}.
- directional_bound(direction: Vector) tuple['Vector', float][source]¶
Returns extreme point in given direction.
- For an ellipsoid E(c, r, A) and direction q:
x_max = c + r * (A^{-1} q) / ||A^{-1/2} q|| h(q) = support_function(q)
- Parameters:
direction – The direction vector q.
- Returns:
(x_max, h(q))
- Return type:
tuple[Vector, float]
- property normalized: NormalisedEllipsoid¶
Returns a normalized version of this ellipsoid with radius 1. The operator is scaled by 1/r^2 to represent the same set.
- property support_function: SupportFunction¶
Returns the support function object for this ellipsoid.
This property does not require inverse operators at construction time. The returned SupportFunction will raise errors if missing operators are required for evaluation.
- class pygeoinf.EllipsoidSupportFunction(primal_domain: HilbertSpace, center: Vector, radius: float, shape_operator: LinearOperator, inverse_operator: LinearOperator | None = None, inverse_sqrt_operator: LinearOperator | None = None)[source]¶
Bases:
SupportFunctionSupport function of an ellipsoid E(c, r, A) defined by:
E = {x : ⟨A(x-c), (x-c)⟩ ≤ r²} with A SPD
- Then:
h(q) = ⟨q, c⟩ + r ||A^{-1/2} q||
- Parameters:
primal_domain – The Hilbert space H.
center – The center c of the ellipsoid.
radius – The radius r.
shape_operator – The SPD operator A.
inverse_operator – A^{-1}. Required for support_point and sufficient for computing h(q) through $sqrt{langle q, A^{-1}qrangle}$.
inverse_sqrt_operator – A^{-1/2}. Optional direct square-root inverse used for computing h(q).
Note
If neither inverse operator is provided, the support function cannot be evaluated. If
inverse_operatoris omitted, support_point returns None.- support_point(q: Vector) 'Vector' | None[source]¶
Return x* = c + r * (A^{-1} q) / ||A^{-1/2} q|| achieving the supremum.
For an ellipsoid E(c, r, A), the extreme point in direction q is found by transforming q through the inverse metric A^{-1} and normalizing.
Returns None if inverse_operator was not provided.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))computing $A^{-1} q$ once.When $A^{-1}$ is available, both the value
\[h(q) = \langle q, c \rangle + r\,\sqrt{\langle q,\, A^{-1} q \rangle}\]and the support point
\[x^*(q) = c + \frac{r}{\sqrt{\langle q, A^{-1} q \rangle}} A^{-1} q\]share the intermediate $A^{-1} q$ and the norm $|A^{-1/2} q| = sqrt{langle q, A^{-1} q rangle}$, so only one operator application is needed instead of two.
When $A^{-1}$ is not available, falls back to calling
self(q)(which uses $A^{-1/2}$) and returnsNonefor the support point, matching the behaviour ofsupport_point().- Parameters:
q – A vector in the primal domain $H$.
- Returns:
(value, point)wherepointisNonewhen $A^{-1}$ was not supplied at construction.
- class pygeoinf.EllipsoidSurface(domain: HilbertSpace, center: Vector, radius: float, operator: LinearOperator)[source]¶
Bases:
LevelSet,_EllipsoidalGeometryRepresents the surface of an ellipsoid: S = {x | <A(x-c), x-c> = r^2}.
- property normalized: EllipsoidSurface¶
Returns a normalized version of this surface with radius 1.
- class pygeoinf.EmptySet(domain: HilbertSpace | None = None)[source]¶
Bases:
SubsetRepresents the empty set (∅).
- property is_empty: bool¶
Returns True, as this is the empty set.
- class pygeoinf.EuclideanSpace(dim: int)[source]¶
Bases:
HilbertSpaceAn n-dimensional Euclidean space, R^n.
This is a concrete HilbertSpace where vectors are represented directly by NumPy arrays, and the inner product is the standard dot product.
- property dim: int¶
The dimension of the space.
- from_components(c: ndarray) ndarray[source]¶
Returns the component array itself, as it is the vector.
- from_dual(xp: LinearForm) np.ndarray[source]¶
Maps a LinearForm back to a vector via its components.
- inner_product(x1: ndarray, x2: ndarray) float[source]¶
Computes the inner product of two vectors.
Notes
Default implementation overrident for efficiency.
- subspace_projection(indices: int | List[int]) LinearOperator[source]¶
Returns a projection operator onto specified coordinates.
This creates a linear operator that extracts the components at the given indices, projecting from this space to a lower-dimensional Euclidean space.
- Parameters:
indices – Single index or list of indices to project onto (0-indexed).
- Returns:
LinearOperator from this space to EuclideanSpace(len(indices)).
- Raises:
IndexError – If any index is out of range for this space’s dimension.
- to_components(x: ndarray) ndarray[source]¶
Returns the vector itself, as it is already a component array.
- to_dual(x: np.ndarray) LinearForm[source]¶
Maps a vector x to a LinearForm with the same components.
- class pygeoinf.ExactBlockPreconditioningMethod(blocks: list[list[int]], /, *, galerkin: bool = True, incomplete: bool = False, drop_tol: float = 0.0001, fill_factor: float = 10.0, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a sparse block preconditioner using exact matrix-vector evaluations.
Explicitly probes the operator with basis vectors but only retains the entries specified by the interaction blocks. Factorizes the resulting sparse matrix using exact or incomplete LU.
- class pygeoinf.FCGSolver(*, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None, preconditioning_method: LinearSolver | None = None)[source]¶
Bases:
IterativeLinearSolverFlexible Conjugate Gradient (FCG) solver.
FCG is designed to handle variable preconditioning, such as using an inner iterative solver to approximate the action of M^-1.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.ForwardProblem(forward_operator: NonLinearOperator, /, *, data_error_measure: GaussianMeasure | None = None)[source]¶
Bases:
objectRepresents a general forward problem.
An instance is defined by a forward operator that maps from a model space to a data space, and an optional Gaussian measure representing the statistical distribution of errors in the data.
- property data_error_measure: GaussianMeasure¶
The measure from which data errors are drawn.
- property data_error_measure_set: bool¶
True if a data error measure has been set.
- property data_space: HilbertSpace¶
The data space (codomain of the forward operator).
- property forward_operator: LinearOperator¶
The forward operator, mapping from model to data space.
- property model_space: HilbertSpace¶
The model space (domain of the forward operator).
- pygeoinf.GMRESMatrixSolver(galerkin: bool = False, **kwargs) ScipyIterativeSolver[source]¶
- class pygeoinf.GaussianMeasure(*, covariance: LinearOperator = None, covariance_factor: LinearOperator = None, expectation: Vector = None, sample: Callable[[], Vector] = None, inverse_covariance: LinearOperator = None, inverse_covariance_factor: LinearOperator = None)[source]¶
Bases:
objectRepresents a Gaussian measure on a Hilbert space.
This class generalizes the multivariate normal distribution to abstract, potentially infinite-dimensional, Hilbert spaces. A measure is defined by its expectation (mean vector) and its covariance, which is a LinearOperator on the space.
- affine_mapping(*, operator: LinearOperator = None, translation: Vector = None, affine_operator: AffineOperator = None, inverse_solver: LinearSolver = None, inverse_preconditioner: LinearOperator = None) GaussianMeasure[source]¶
Transforms the measure under an affine map y = A(x) + b.
This method calculates the push-forward measure. It can also construct the implied inverse covariance (precision) using a saddle-point (KKT) system.
- Parameters:
operator – The linear part of the mapping (A).
translation – The translation vector (b).
affine_operator – An AffineOperator instance (cannot be used with operator or translation).
inverse_solver – A solver used to evaluate the KKT inverse covariance.
inverse_preconditioner – A preconditioner for the inverse_solver.
- Returns:
A new GaussianMeasure representing the push-forward distribution.
- Raises:
ValueError – If mutually exclusive arguments are provided, or if an inverse solve is requested but the prior lacks an inverse covariance.
- ambient_ball(probability: float, /, **kwargs)[source]¶
Shortcut for
credible_set(..., geometry='ambient_ball', ...).
- as_multivariate_normal(*, parallel: bool = False, n_jobs: int = -1) <scipy.stats._multivariate.multivariate_normal_gen object at 0x7d8aa0531940>[source]¶
Returns the measure as a scipy.stats.multivariate_normal object.
- Parameters:
parallel – If True, evaluates the dense covariance matrix concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A frozen scipy.stats.multivariate_normal object.
- Raises:
NotImplementedError – If the measure is not defined on a EuclideanSpace.
- property covariance: LinearOperator¶
The covariance operator of the measure.
- property covariance_factor: LinearOperator¶
The covariance factor L. Raises AttributeError if not set.
- property covariance_factor_set: bool¶
True if a covariance factor L (such that C = L @ L*) is available.
- credible_set(probability: float, /, *, geometry: str = 'ellipsoid', rank: int | None = None, open_set: bool = False, theta: float | None = None, spectrum=None, spectrum_size: int | None = None, radius_method: str = 'auto', quantile_method: str = 'auto', quantile_tol: float = 0.01, fractional_apply: str = 'auto', n_samples: int = 10000, lanczos_size_estimate: int = 50, lanczos_method: Literal['variable', 'fixed'] = 'fixed', lanczos_max_k: int | None = None, lanczos_rtol: float = 0.001, lanczos_atol: float = 1e-08, lanczos_check_interval: int = 5, spectrum_low_rank_kwargs: dict | None = None, rng: Generator | None = None)[source]¶
Return a probability-calibrated Gaussian credible subset.
Five geometries are supported:
"ellipsoid"/"mahalanobis"/"domain"The classical Mahalanobis ellipsoid.
"cameron_martin"/"cm"/"ball"/"norm_ball"The ellipsoid expressed as a unit ball in the Cameron-Martin geometry.
"ambient_ball"/"ambient"The ambient norm ball ${m : |m - m_0|_H le r_p}$.
"weakened_ellipsoid"/"fractional"The weakened-covariance ellipsoid ${m : |C^{-theta/2}(m-m_0)|_H le r_p}$.
- Parameters:
probability – Credible probability $p$, strictly between 0 and 1.
geometry – Selects the ball/ellipsoid family (see above).
rank – Chi-square degrees of freedom (legacy modes only).
open_set – If true, return the open version of the set.
theta – Fractional exponent in $(0, 1)$, required for weakened_ellipsoid.
spectrum – Covariance spectrum specification.
spectrum_size – Truncation length when
spectrumis callable orNone.radius_method –
"auto","spectral", or"sampling".quantile_method – Weighted-chi-square quantile method.
quantile_tol – Desired relative accuracy of the weighted-chi-square quantile.
fractional_apply – How to apply $C^{-theta/2}$ for the weakened ellipsoid.
n_samples – Monte Carlo sample count for sampling radius.
lanczos_size_estimate – Initial or fixed Krylov dimension for Lanczos fractional evaluation.
lanczos_method – ‘fixed’ or ‘variable’ dynamic convergence for Lanczos.
lanczos_max_k – Maximum Krylov dimension if ‘variable’ is used.
lanczos_rtol – Relative tolerance for Lanczos convergence.
lanczos_atol – Absolute tolerance for Lanczos convergence.
lanczos_check_interval – Number of iterations between Lanczos convergence checks.
spectrum_low_rank_kwargs – Extra kwargs forwarded to
LowRankEig.from_randomized.rng – Optional NumPy generator for Monte Carlo paths.
- Returns:
An Ellipsoid or Ball defining the credible subset.
- deflated_pointwise_std(rank: int, /, *, size_estimate: int = 0, method: str = 'variable', max_samples: int = None, rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise standard deviation field using a deflated Hutchinson’s method.
- Parameters:
rank – The rank of the deterministic SVD deflation.
size_estimate – The initial number of stochastic residual samples.
method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on stochastic residual samples.
rtol – Relative tolerance for the stochastic residual phase.
block_size – Number of samples added per check in the ‘variable’ method.
parallel – If True, draws stochastic samples in parallel.
n_jobs – The number of CPU cores to use.
- Returns:
A vector representing the pointwise standard deviation field.
- deflated_pointwise_variance(rank: int, /, *, size_estimate: int = 0, method: str = 'variable', max_samples: int = None, rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise variance field using a deflated Hutchinson’s method.
This combines a deterministic low-rank extraction (via SVD deflation) with a stochastic Hutchinson trace estimator for the residual variance.
- Parameters:
rank – The rank of the deterministic SVD deflation.
size_estimate – The initial number of stochastic residual samples.
method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on stochastic residual samples.
rtol – Relative tolerance for the stochastic residual phase.
block_size – Number of samples added per check in the ‘variable’ method.
parallel – If True, draws stochastic samples in parallel.
n_jobs – The number of CPU cores to use.
- Returns:
A vector representing the pointwise variance field.
- Raises:
NotImplementedError – If the domain is not a HilbertModule.
- directional_covariance(d1: Vector, d2: Vector, /) float[source]¶
Returns the covariance between the scalar projections <x, d1> and <x, d2>.
- Parameters:
d1 – The first test vector.
d2 – The second test vector.
- Returns:
The covariance scalar.
- directional_statistics(direction: Vector, /) Tuple[float, float][source]¶
Returns the expectation and variance of the scalar Gaussian <x, direction>.
- Parameters:
direction – The test vector.
- Returns:
A tuple containing (expectation, variance).
- directional_variance(d: Vector, /) float[source]¶
Returns the variance of the scalar projection <x, d>.
- Parameters:
d – The test vector.
- Returns:
The variance scalar.
- property domain: HilbertSpace¶
The Hilbert space the measure is defined on.
- property expectation: Vector¶
The expectation (mean) vector of the measure.
- static from_covariance_matrix(domain: HilbertSpace, covariance_matrix: np.ndarray, /, *, expectation: Vector = None, rtol: float = 1e-10) GaussianMeasure[source]¶
Creates a Gaussian measure from a dense covariance matrix.
- Parameters:
domain – The Hilbert space on which the measure is defined.
covariance_matrix – A 2D symmetric positive semi-definite NumPy array.
expectation – The mean vector. Defaults to the zero vector.
rtol – Relative tolerance for clipping small negative eigenvalues caused by floating-point inaccuracies.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the matrix has significantly negative eigenvalues.
- static from_direct_sum(measures: List[GaussianMeasure], /) GaussianMeasure[source]¶
Constructs a product measure from a list of other measures.
The resulting measure resides on the direct sum of the input domains, with block-diagonal covariance and concatenated expectations.
- Parameters:
measures – A list of GaussianMeasure instances.
- Returns:
A new GaussianMeasure instance defined on the direct sum space.
- static from_samples(domain: HilbertSpace, samples: List[Vector], /) GaussianMeasure[source]¶
Estimates a Gaussian measure from a collection of sample vectors.
Constructs an empirical mean and an unnormalized sample covariance operator using a tensor product expansion.
- Parameters:
domain – The Hilbert space the samples belong to.
samples – A list of sample vectors.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the list of samples is empty.
- static from_standard_deviation(domain: HilbertSpace, standard_deviation: float, /, *, expectation: Vector = None) GaussianMeasure[source]¶
Creates an isotropic Gaussian measure with a scaled identity covariance.
- Parameters:
domain – The Hilbert space on which the measure is defined.
standard_deviation – The uniform standard deviation for all dimensions.
expectation – The mean vector. Defaults to the zero vector.
- Returns:
A new GaussianMeasure instance.
- static from_standard_deviations(domain: HilbertSpace, standard_deviations: np.ndarray, /, *, expectation: Vector = None) GaussianMeasure[source]¶
Creates a Gaussian measure with a diagonal covariance operator.
- Parameters:
domain – The Hilbert space on which the measure is defined.
standard_deviations – A 1D NumPy array representing the diagonal entries of the covariance factor.
expectation – The mean vector. Defaults to the zero vector.
- Returns:
A new GaussianMeasure instance.
- Raises:
ValueError – If the size of the array does not match the space dimension.
- property has_zero_expectation: bool¶
True if the measure is internally stored with an exactly zero expectation.
- property inverse_covariance: LinearOperator¶
The inverse covariance (precision) operator. Raises AttributeError if not set.
- property inverse_covariance_factor: LinearOperator¶
The inverse covariance factor. Raises AttributeError if not set.
- property inverse_covariance_factor_set: bool¶
True if an inverse covariance factor is available.
- property inverse_covariance_set: bool¶
True if the inverse covariance (precision) operator is available.
- kl_divergence(other: GaussianMeasure, /, *, method: Literal['dense', 'randomized'] = 'dense', hutchinson_size_estimate: int = 10, hutchinson_method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_size_estimate: int = 40, lanczos_method: Literal['variable', 'fixed'] = 'variable', lanczos_max_k: int | None = None, lanczos_rtol: float = 0.001, lanczos_atol: float = 1e-08, lanczos_check_interval: int = 5, parallel: bool = False, n_jobs: int = -1) float[source]¶
Computes the exact or approximate Kullback-Leibler (KL) divergence D_KL(self || other).
This calculates the divergence of ‘self’ (P) from the prior/reference measure ‘other’ (Q).
- Parameters:
other – The reference GaussianMeasure (Q).
method – ‘dense’ uses exact dense matrix factorizations (O(N^3)). ‘randomized’ uses matrix-free Stochastic Lanczos Quadrature (SLQ).
hutchinson_size_estimate – Initial samples for the randomized trace estimator.
hutchinson_method – ‘variable’ to sample until rtol is met, ‘fixed’ otherwise.
max_samples – Hard limit on Hutchinson samples.
rtol – Relative tolerance for the Hutchinson estimator.
block_size – Samples added per check in the ‘variable’ Hutchinson method.
lanczos_size_estimate – Initial Krylov dimension for fractional evaluations.
lanczos_method – ‘variable’ or ‘fixed’ convergence for Lanczos.
lanczos_max_k – Maximum Krylov dimension if ‘variable’ is used.
lanczos_rtol – Relative tolerance for Lanczos convergence.
lanczos_atol – Absolute tolerance for Lanczos convergence.
lanczos_check_interval – Iterations between Lanczos convergence checks.
parallel – If True, evaluates the stochastic probes concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The calculated KL divergence.
- Raises:
ValueError – If the measures reside on different domains, or if the ‘randomized’ method is called without an inverse covariance on the reference measure.
- low_rank_approximation(size_estimate: int, /, *, method: str = 'variable', max_rank: int = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Constructs a low-rank approximation of the measure.
Uses randomized matrix-free algorithms to factorize the covariance.
- Parameters:
size_estimate – Target rank or initial sample size for the algorithm.
method – ‘variable’ to sample dynamically, ‘fixed’ otherwise.
max_rank – Upper limit on rank for the ‘variable’ method.
power – Number of power iterations to enhance spectral decay.
rtol – Relative tolerance for the ‘variable’ method.
block_size – Samples drawn per iteration in the ‘variable’ method.
parallel – If True, parallelizes the evaluations.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure backed by a LowRankCholesky covariance factor.
- rescale_directional_variance(direction: Vector, std: float, /) GaussianMeasure[source]¶
Returns a new measure where Var[<x, direction>] is scaled to std^2.
- Parameters:
direction – The test vector to scale against.
std – The target standard deviation for the projection.
- Returns:
A variance-scaled GaussianMeasure.
- Raises:
ValueError – If the current directional variance is zero or negative.
- sample() Vector[source]¶
Returns a single random sample drawn from the measure.
- Returns:
A randomly sampled vector.
- Raises:
NotImplementedError – If a sample method is not set for this measure.
- sample_expectation(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the expectation vector by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use for the estimation.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
The empirical expectation vector.
- sample_pointwise_std(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise standard deviation field by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A vector representing the pointwise standard deviation field.
- sample_pointwise_variance(n: int, /, *, parallel: bool = False, n_jobs: int = -1) Vector[source]¶
Estimates the pointwise variance field by drawing n Monte Carlo samples.
- Parameters:
n – The number of samples to use.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A vector representing the pointwise variance field.
- Raises:
NotImplementedError – If the domain is not a HilbertModule (which provides pointwise multiplication).
- property sample_set: bool¶
True if a method for drawing random samples is available.
- samples(n: int, /, *, parallel: bool = False, n_jobs: int = -1) List[Vector][source]¶
Returns a list of n independent random samples from the measure.
- Parameters:
n – The number of samples to draw.
parallel – If True, draws samples concurrently.
n_jobs – The number of CPU cores to use if parallel=True.
- Returns:
A list of sampled vectors.
- Raises:
ValueError – If n is less than 1.
- two_point_covariance(point: Any, /) Vector[source]¶
Computes the two-point covariance function radiating from a specific point.
- Parameters:
point – The spatial coordinate to evaluate from.
- Returns:
The covariance field evaluated at the chosen point.
- Raises:
NotImplementedError – If the domain lacks a dirac_representation method.
- weakened_ellipsoid(probability: float, /, *, theta: float, **kwargs)[source]¶
Shortcut for the weakened-covariance ellipsoid mode.
- with_dense_covariance(*, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Forms a new Gaussian measure equivalent to the existing one, but with its covariance matrix stored explicitly in dense form.
- Parameters:
parallel – If True, computes the dense matrix concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure instance backed by a dense matrix.
- with_regularized_inverse(solver: LinearSolver, /, *, damping: float = 0.0, preconditioner: LinearOperator | None = None) GaussianMeasure[source]¶
Returns a new GaussianMeasure with a well-defined precision operator (inverse covariance) computed via Tikhonov regularization.
- Parameters:
solver – The linear solver used to invert the covariance.
damping – Tikhonov regularization parameter added to the diagonal.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A new GaussianMeasure instance equipped with an inverse covariance.
- Raises:
ValueError – If the damping parameter is negative.
- with_sparse_approximation(*, threshold: float = 0.001, max_nnz: int | None = None, diag_rank: int = 0, diag_samples: int = 0, regularization_fraction: float = 0.0001, parallel: bool = False, n_jobs: int = -1) GaussianMeasure[source]¶
Creates an approximately equivalent measure with a sparse covariance matrix and an exactly factorized sparse inverse, built entirely matrix-free.
- Parameters:
threshold – Minimum correlation required to keep an off-diagonal element.
max_nnz – Maximum number of non-zero elements allowed per column.
diag_rank – Rank of deterministic SVD used to estimate the diagonal.
diag_samples – Number of stochastic samples used to estimate the diagonal.
regularization_fraction – Tikhonov regularization applied before sparse inversion.
parallel – If True, computes the sparse approximations concurrently.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
A new GaussianMeasure backed by sparse operators.
- zero_expectation() GaussianMeasure[source]¶
Returns a new measure with the same covariance, but zero expectation.
- Returns:
A mean-shifted GaussianMeasure.
- class pygeoinf.HalfSpaceSupportFunction(primal_domain: HilbertSpace, normal_vector: Vector, offset: float, inequality_type: str = '<=', *, parallel_rtol: float = 1e-12, parallel_atol: float = 1e-14, return_min_norm_support_point: bool = True)[source]¶
Bases:
NonLinearFormSupport function of a (closed) half-space in a Hilbert space H.
We support two conventions:
(<=) H = { x ∈ H : ⟨a, x⟩ ≤ b } (>=) H = { x ∈ H : ⟨a, x⟩ ≥ b } which is equivalent to { x : ⟨-a, x⟩ ≤ -b }.
- Mathematical facts (extended-real-valued):
For H = {x : ⟨a, x⟩ ≤ b} with a ≠ 0,
- σ_H(q) = sup_{x∈H} ⟨q, x⟩
- = { α b, if q = α a with α ≥ 0,
+∞, otherwise. }
For H = {x : ⟨a, x⟩ ≥ b},
- σ_H(q) = { α b, if q = α a with α ≤ 0,
+∞, otherwise. }
Notes
Half-spaces are unbounded, so σ_H is typically +∞.
This implementation returns float(‘inf’) for unbounded directions.
A support point is not unique when σ_H(q) is finite; the maximizers form the boundary hyperplane ⟨a, x⟩ = b. We optionally return the minimum-norm boundary point as a canonical representative.
- property inequality_type: str¶
- property normal_vector: Vector¶
- property offset: float¶
- support_point(q: Vector) 'Vector' | None[source]¶
Return a canonical maximizer when σ_H(q) is finite.
When finite, the maximizers are all x with ⟨a,x⟩ = b (boundary hyperplane). If return_min_norm_support_point=True, we return the minimum-norm boundary point:
x_min = (b / ||a||^2) a.
Otherwise return None (non-unique support set).
- class pygeoinf.HilbertModule[source]¶
Bases:
HilbertSpace,ABCAn ABC for a HilbertSpace where vector multiplication is defined.
This acts as a “mixin” interface, adding the vector_multiply requirement to the HilbertSpace contract.
- class pygeoinf.HilbertSpace[source]¶
Bases:
ABC,HilbertSpaceAxiomChecksAn abstract base class for real Hilbert spaces.
This class provides a mathematical abstraction for a vector space equipped with an inner product. It defines a formal interface that separates abstract vector operations from their concrete representation (e.g., as NumPy arrays). Subclasses must implement all abstract methods to be instantiable.
- axpy(a: float, x: Vector, y: Vector) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- final basis_vector(i: int) Vector[source]¶
Returns the i-th standard basis vector.
This is the vector whose component array is all zeros except for a one at index i.
- Parameters:
i – The index of the basis vector.
- Returns:
The i-th basis vector.
- property coordinate_inclusion: LinearOperator¶
The linear operator mapping R^n component vectors into this space.
- property coordinate_projection: LinearOperator¶
The linear operator projecting vectors from this space to R^n.
- abstract property dim: int¶
The finite dimension of the space.
- property dual: HilbertSpace¶
The dual of this Hilbert space.
The dual space is the space of all continuous linear functionals (i.e., LinearForm objects) that map vectors from this space to real numbers. This implementation returns a DualHilbertSpace wrapper.
- duality_product(xp: LinearForm, x: Vector) float[source]¶
Computes the duality product <xp, x>.
This evaluates the linear functional xp (an element of the dual space) at the vector x (an element of the primal space).
- Parameters:
xp – The linear functional from the dual space.
x – The vector from the primal space.
- Returns:
The result of the evaluation xp(x).
- abstract from_components(c: ndarray) Vector[source]¶
Maps a NumPy component array back to a vector in the space.
- Parameters:
c – The components of the vector as a NumPy array.
- Returns:
The corresponding vector in the space.
- abstract from_dual(xp: Any) Vector[source]¶
Maps a dual vector back to its representative in the primal space.
This is the inverse of the Riesz representation map defined by to_dual.
- Parameters:
xp – A vector in the dual space.
- Returns:
The corresponding vector in the primal space.
- final gram_schmidt(vectors: List[Vector]) List[Vector][source]¶
Orthonormalizes a list of vectors using the Gram-Schmidt process.
- Parameters:
vectors – A list of linearly independent vectors.
- Returns:
A list of orthonormalized vectors spanning the same subspace.
- Raises:
ValueError – If not all items in the list are elements of the space.
- final identity_operator() LinearOperator[source]¶
Returns the identity operator I on the space.
- inner_product(x1: Vector, x2: Vector) float[source]¶
Computes the inner product of two vectors, (x1, x2).
This is defined via the duality product as <R(x1), x2>, where R is the Riesz map (to_dual).
- Parameters:
x1 – The first vector.
x2 – The second vector.
- Returns:
The inner product as a float.
- property inverse_riesz: LinearOperator¶
The inverse Riesz map (primal to dual) as a LinearOperator.
- is_element(x: Any) bool[source]¶
Checks if an object is a valid element of the space.
Note: The default implementation checks the object’s type against the type of the zero vector. This may not be robust for all vector representations and can be overridden if needed.
- Parameters:
x – The object to check.
- Returns:
True if the object is an element of the space, False otherwise.
- final norm(x: Vector) float[source]¶
Computes the norm of a vector, ||x||.
- Parameters:
x – The vector.
- Returns:
The norm of the vector.
- random() Vector[source]¶
Generates a random vector from the space.
The vector’s components are drawn from a standard normal distribution.
- Returns:
A new random vector.
- property riesz: LinearOperator¶
The Riesz map (dual to primal) as a LinearOperator.
- final sample_expectation(vectors: List[Vector]) Vector[source]¶
Computes the sample mean of a list of vectors.
- Parameters:
vectors – A list of vectors from the space.
- Returns:
The sample mean (average) vector.
- Raises:
TypeError – If not all items in the list are elements of the space.
- final squared_norm(x: Vector) float[source]¶
Computes the squared norm of a vector, ||x||^2.
- Parameters:
x – The vector.
- Returns:
The squared norm of the vector.
- subtract(x: Vector, y: Vector) Vector[source]¶
Computes the difference of two vectors. Defaults to x - y.
- abstract to_components(x: Vector) ndarray[source]¶
Maps a vector to its representation as a NumPy component array.
- Parameters:
x – A vector in the space.
- Returns:
The components of the vector as a NumPy array.
- abstract to_dual(x: Vector) Any[source]¶
Maps a vector to its canonical dual vector (a linear functional).
This method, along with from_dual, defines the Riesz representation map and implicitly defines the inner product of the space.
- Parameters:
x – A vector in the primal space.
- Returns:
The corresponding vector in the dual space.
- property zero: Vector¶
The zero vector (additive identity) of the space.
- final zero_operator(codomain: HilbertSpace | None = None) LinearOperator[source]¶
Returns the zero operator 0 from this space to a codomain.
- Parameters:
codomain – The target space of the operator. If None, the operator maps to this space itself.
- Returns:
The zero linear operator.
- class pygeoinf.HilbertSpaceDirectSum(spaces: List[HilbertSpace])[source]¶
Bases:
HilbertSpaceA Hilbert space formed from the direct sum of a list of other spaces.
A vector in this space is represented as a list of vectors, where the i-th element of the list is a vector from the i-th component subspace. The inner product is the sum of the inner products of the components.
- add(xs: List[Any], ys: List[Any]) List[Any][source]¶
Computes the sum of two vectors. Defaults to x + y.
- axpy(a: float, xs: List[Any], ys: List[Any]) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- canonical_dual_inverse_isomorphism(xp: LinearForm) List[LinearForm][source]¶
Maps a dual vector on the sum space to a list of dual vectors.
This is the inverse of the canonical isomorphism, projecting the action of a dual vector onto each subspace.
- Parameters:
xp (LinearForm) – A dual vector on the direct sum space.
- canonical_dual_isomorphism(xps: List[LinearForm]) LinearForm[source]¶
Maps a list of dual vectors to a single dual vector on the sum space.
This is the canonical isomorphism from the direct sum of the dual spaces to the dual of the direct sum space.
- Parameters:
xps (List[LinearForm]) – A list of dual vectors, one for each subspace.
- property dim: int¶
Returns the dimension of the direct sum space.
- from_components(c: ndarray) List[Any][source]¶
Maps a NumPy component array back to a vector in the space.
- Parameters:
c – The components of the vector as a NumPy array.
- Returns:
The corresponding vector in the space.
- from_dual(xp: LinearForm) List[Any][source]¶
Maps a dual vector back to its representative in the primal space.
This is the inverse of the Riesz representation map defined by to_dual.
- Parameters:
xp – A vector in the dual space.
- Returns:
The corresponding vector in the primal space.
- is_element(xs: Any) bool[source]¶
Checks if a list of vectors is a valid element of the direct sum space.
- multiply(a: float, xs: List[Any]) List[Any][source]¶
Computes scalar multiplication. Defaults to a * x.
- property number_of_subspaces: int¶
Returns the number of subspaces in the direct sum.
- subspace(i: int) HilbertSpace[source]¶
Returns the i-th subspace.
- Parameters:
i (int) – The index of the subspace to retrieve.
- subspace_inclusion(i: int) LinearOperator[source]¶
Returns the inclusion operator from the i-th subspace into the sum.
- Parameters:
i (int) – The index of the subspace to include from.
- subspace_projection(i: int) LinearOperator[source]¶
Returns the projection operator onto the i-th subspace.
- Parameters:
i (int) – The index of the subspace to project onto.
- property subspaces: List[HilbertSpace]¶
Returns the list of subspaces that form the direct sum.
- subtract(xs: List[Any], ys: List[Any]) List[Any][source]¶
Computes the difference of two vectors. Defaults to x - y.
- to_components(xs: List[Any]) ndarray[source]¶
Maps a vector to its representation as a NumPy component array.
- Parameters:
x – A vector in the space.
- Returns:
The components of the vector as a NumPy array.
- to_dual(xs: List[Any]) LinearForm[source]¶
Maps a vector to its canonical dual vector (a linear functional).
This method, along with from_dual, defines the Riesz representation map and implicitly defines the inner product of the space.
- Parameters:
x – A vector in the primal space.
- Returns:
The corresponding vector in the dual space.
- property zero: List[Any]¶
each subspace contributes its own zero.
- Type:
The zero element
- class pygeoinf.IdentityPreconditioningMethod[source]¶
Bases:
LinearSolverA trivial preconditioning method that returns the Identity operator.
This acts as a “no-op” placeholder in the preconditioning framework, useful for benchmarking or default configurations.
- class pygeoinf.Intersection(subsets: Iterable[Subset])[source]¶
Bases:
SubsetRepresents the generic intersection of multiple subsets: S = S_1 ∩ S_2 …
Used when the subsets cannot be mathematically combined into a single functional (e.g., non-convex sets).
- property boundary: Subset¶
Returns the boundary of the intersection.
The general topological boundary is complex: ∂(A ∩ B) ⊆ (∂A ∩ B) ∪ (A ∩ ∂B). Currently raises NotImplementedError.
- property complement: Subset¶
Returns the complement of the intersection.
Applies De Morgan’s Law: (A ∩ B)^c = A^c ∪ B^c. Returns a Union of the complements.
- class pygeoinf.IterativeLinearSolver(*, preconditioning_method: LinearSolver = None)[source]¶
Bases:
LinearSolverAn abstract base class for iterative linear solvers.
- property iterations: int¶
Returns the number of iterations within the last solve. The value is zero if the solver has yet to be called.
- solve_adjoint_linear_system(operator: LinearOperator, adjoint_preconditioner: LinearOperator | None, x: Vector, y0: Vector | None) Vector[source]¶
Solves the adjoint linear system A*y = x for y.
- abstract solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.IterativePreconditioningMethod(inner_solver: IterativeLinearSolver, max_inner_iter: int = 5, rtol: float = 0.1)[source]¶
Bases:
LinearSolverWraps an iterative solver to act as a preconditioner.
This is best used with FCGSolver to handle the potential variability of the inner iterations.
- class pygeoinf.JacobiPreconditioningMethod(num_samples: int | None = 20, method: str = 'variable', rtol: float = 0.01, block_size: int = 10, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a Jacobi preconditioner.
- class pygeoinf.KKTResult(m: Vector, multipliers: tuple[float, float], converged: bool, num_iterations: int)[source]¶
Bases:
objectResult from
PrimalKKTSolver.- m¶
Optimal primal model vector $u^*$ in the model space.
- Type:
Vector
- multipliers¶
KKT multipliers $(lambda^*, mu^*)$. $lambda^*$ enforces the model prior constraint and $mu^*$ enforces the data-fit constraint. Both are non-negative.
- Type:
tuple[float, float]
- converged¶
Trueif the root-finder converged to the required tolerance.- Type:
bool
- num_iterations¶
Number of function evaluations used by the root-finder (or 1 for the closed-form branch).
- Type:
int
- converged: bool¶
- m: Vector¶
- multipliers: tuple[float, float]¶
- num_iterations: int¶
- class pygeoinf.LUSolver(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
DirectLinearSolverA direct linear solver based on the LU decomposition of an operator’s dense matrix representation.
- class pygeoinf.LanczosOperatorFunction(operator: LinearOperator, func: Callable[[ndarray], ndarray], size_estimate: int, *, method: Literal['variable', 'fixed'] = 'variable', max_k: int | None = None, reorth: str = 'full', rtol: float = 0.001, atol: float = 1e-08, check_interval: int = 5)[source]¶
Bases:
LinearOperatorA matrix-free LinearOperator representing the action of a continuous function applied to a self-adjoint positive operator.
Rather than explicitly computing and storing the dense matrix f(A), this class evaluates the matrix-vector product f(A)x dynamically on the fly using the Lanczos process. This allows for highly efficient evaluations in massive or infinite-dimensional Hilbert spaces.
- property base_operator: LinearOperator¶
Returns the underlying base LinearOperator.
- class pygeoinf.LevelSet(form: NonLinearForm, level: float)[source]¶
Bases:
SubsetRepresents a level set of a functional: S = {x | f(x) = c}.
- property boundary: Subset¶
Returns the boundary of the level set. Assuming regularity, a level set is a closed manifold without boundary.
- property form: NonLinearForm¶
The defining functional f(x).
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if f(x) is approximately equal to c. Tolerance is scaled by max(1.0, |c|).
- property level: float¶
The scalar value c.
- class pygeoinf.LinearBayesianInversion(forward_problem: LinearForwardProblem, model_prior_measure: GaussianMeasure, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem using Bayesian methods.
This class applies to problems of the form d = A(u) + e, where u is a Gaussian random variable representing the model prior, and e is a Gaussian random variable representing observation noise.
It computes the exact posterior Gaussian measure p(u|d), providing access to the posterior expectation, the posterior covariance operator, and an efficient exact-sampling mechanism using the randomize-then-optimize technique.
- property data_prior_measure: GaussianMeasure¶
The prior predictive distribution on the data space. This represents the expected distribution of data before observation.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate of the Bayesian inversion using a reduced data space.
- Parameters:
reduction_operator – A LinearOperator mapping from the current data space to the new, reduced data space.
reduced_data_error_measure – An optional data error measure defined on the reduced data space.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion.
- Returns:
A new LinearBayesianInversion instance operating on the reduced data space.
- diagonal_normal_preconditioner(*, blocks: List[List[int]] | None = None, parallel: bool = False, n_jobs: int = -1) LinearOperator[source]¶
Constructs a diagonal preconditioner specifically for the data-space Bayesian normal operator (A Q A* + R).
This exploits the identity <v, A Q A* v> = <A* v, Q A* v>. If blocks of data indices are provided, it acts on the averaged basis vector for each block to compute a robust representative regional variance, requiring only one adjoint action of the forward operator per block.
- Parameters:
blocks – An optional list of lists, where each sub-list contains indices of data points grouped together. Must perfectly partition the data space.
parallel – If True, computes the adjoint actions in parallel.
n_jobs – Number of parallel jobs to use. -1 means all available cores.
- Returns:
A DiagonalSparseMatrixLinearOperator representing the inverse of the approximated normal operator.
- Raises:
ValueError – If the inversion was initialized with formalism=’model_space’, as this preconditioner is mathematically invalid for that normal operator.
- estimate_log_determinant(*, operator_type: Literal['data_space', 'model_space'] = 'data_space', size_estimate: int = 10, method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_degree: int = 40, lanczos_rtol: float | None = 0.001, parallel: bool = False, n_jobs: int = -1) float[source]¶
Estimates the log-determinant of the Bayesian normal operator using Stochastic Lanczos Quadrature (SLQ).
This acts as a public interface for computing the log-determinant of either the data-space normal operator (A Q A* + R) or the model-space normal operator (Q^-1 + A* R^-1 A). It securely resolves the correct algebraic space and delegates to the internal matrix-free SLQ engine.
- Parameters:
operator_type – The target normal operator (‘data_space’ or ‘model_space’).
size_estimate – Initial number of Hutchinson samples (probe vectors).
method – ‘variable’ to sample until ‘rtol’ is met, ‘fixed’ otherwise.
max_samples – Hard limit on the number of Hutchinson samples.
rtol – Relative tolerance for the Hutchinson trace estimate.
block_size – Number of new samples per iteration in the ‘variable’ method.
lanczos_degree – Maximum Krylov dimension (k) per probe vector.
lanczos_rtol – Relative tolerance for dynamic Lanczos truncation. If None, uses fixed ‘lanczos_degree’ steps.
parallel – If True, evaluates probe vectors in parallel.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The estimated log-determinant ln(|N|).
- Return type:
float
- get_normal_equations_rhs(data: Vector) Vector[source]¶
Computes the exact right-hand side vector (v) of the normal equations N * w = v for a given observed data vector, automatically accounting for non-zero prior and noise expectations.
- property joint_prior_measure: GaussianMeasure¶
The joint prior distribution of both the model and the data.
- kalman_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) LinearOperator[source]¶
Constructs the Kalman gain operator K.
The Kalman gain maps data residuals to model space updates.
For ‘data_space’: K = Q A* (A Q A* + R)^-1 For ‘model_space’: K = (Q^-1 + A* R^-1 A)^-1 A* R^-1
- Parameters:
solver – The LinearSolver used to invert the normal operator.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A LinearOperator representing the Kalman gain.
- log_evidence(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None, size_estimate: int = 10, method: Literal['variable', 'fixed'] = 'variable', max_samples: int | None = None, rtol: float = 0.01, block_size: int = 5, lanczos_degree: int = 40, lanczos_rtol: float | None = 0.001, parallel: bool = False, n_jobs: int = -1) float[source]¶
Computes the approximate log marginal likelihood (evidence) of the data, ln(p(d)).
The log-evidence is a critical metric for Bayesian model selection, allowing users to quantitatively compare different prior assumptions or forward models. It evaluates the likelihood of the observed data marginalized over all possible model states.
- The computation evaluates the Gaussian marginal density equation:
ln p(d) = -0.5 * [ ln|N_d| + <v, N_d^-1 v> + M * ln(2*pi) ]
- Parameters:
data – The observed data vector ‘d’.
solver – The LinearSolver used to invert the normal operator for the Mahalanobis misfit term.
preconditioner – Optional preconditioner for the iterative solver.
size_estimate – Initial number of SLQ Hutchinson samples.
method – ‘variable’ to dynamically bound SLQ error, ‘fixed’ otherwise.
max_samples – Hard limit on SLQ Hutchinson samples.
rtol – Relative tolerance for the SLQ trace estimate.
block_size – Number of new SLQ samples per iteration.
lanczos_degree – Maximum Krylov dimension for SLQ.
lanczos_rtol – Relative tolerance for dynamic Lanczos truncation.
parallel – If True, evaluates SLQ probe vectors in parallel.
n_jobs – Number of CPU cores to use if parallel=True.
- Returns:
The estimated log-evidence ln(p(d)).
- Return type:
float
- Raises:
ValueError – If the ‘model_space’ formalism is used but no data error measure has been set on the forward problem.
- low_rank_surrogate(*, forward_rank: int | None = None, prior_rank: int | None = None, data_error_rank: int | None = None, forward_kwargs: dict | None = None, prior_kwargs: dict | None = None, data_error_kwargs: dict | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate Bayesian inversion problem by replacing the exact physics and statistical measures with their low-rank approximations.
This method generates computationally cheap surrogate models to be used in constructing preconditioners for massive, ill-conditioned inverse problems (e.g., using spectral or banded methods). The low-rank approximations are computed using randomized SVD and eigendecomposition algorithms.
- Parameters:
forward_rank – Target rank for the randomized SVD of the forward operator.
prior_rank – Target rank for the randomized eigendecomposition of the prior.
data_error_rank – Target rank for the randomized eigendecomposition of the noise.
forward_kwargs – Additional kwargs passed directly to LinearOperator.random_svd.
prior_kwargs – Additional kwargs passed directly to GaussianMeasure.low_rank_approximation.
data_error_kwargs – Additional kwargs passed directly to GaussianMeasure.low_rank_approximation.
- Returns:
A LinearBayesianInversion representing the low-rank surrogate problem.
- mahalanobis_evidence_term(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) float[source]¶
Computes the data-dependent Mahalanobis term of the log-evidence.
This value represents the optimal, penalty-balanced data misfit. It is equivalent to the unnormalized log-posterior evaluated at the posterior expectation.
Mathematically, for a shifted data residual vector v = d - A(mu_u) - mu_e, the term evaluates the quadratic form:
Misfit = <v, (A Q A* + R)^-1 v>
In the ‘model_space’ formalism, this is computed far more efficiently using the Woodbury matrix identity to bypass the massive data-space inversion:
Misfit = <v, R^-1 v> - <A* R^-1 v, (Q^-1 + A* R^-1 A)^-1 A* R^-1 v>
- Parameters:
data – The observed data vector ‘d’.
solver – The LinearSolver used to invert the normal operator.
preconditioner – An optional preconditioner to accelerate iterative solvers.
- Returns:
The scalar Mahalanobis distance.
- Return type:
float
- Raises:
ValueError – If the forward problem lacks a defined data error measure.
- model_posterior_measure(data: Vector, solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) GaussianMeasure[source]¶
Computes and returns the posterior Gaussian measure p(u|d).
This method applies the Kalman update equations to find the posterior expectation and covariance. If both the prior and data error measures have sampling enabled, it automatically constructs a randomize-then-optimize exact sampling function for the posterior.
- Parameters:
data – The observed data vector.
solver – A linear solver for inverting the normal operator.
preconditioner – An optional preconditioner for iterative solvers.
- Returns:
A GaussianMeasure representing the posterior distribution.
- property model_prior_measure: GaussianMeasure¶
The prior Gaussian measure on the model space.
- property normal_operator: LinearOperator¶
Constructs the Bayesian Normal operator for the chosen formalism.
For ‘data_space’: Returns N = A Q A* + R For ‘model_space’: Returns N = Q^-1 + A* R^-1 A
- Returns:
A LinearOperator representing the normal equations matrix.
- normal_residual_callback(data: Vector, /, *, message: str = 'CG Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True) ResidualTrackingCallback[source]¶
Generates a ResidualTrackingCallback pre-configured to track the convergence of the Bayesian normal equations for the given data vector.
- Parameters:
data – The observed data vector.
message – The formatting string for printing progress.
print_progress – If True, prints the message to stdout at each iteration.
- Returns:
A configured ResidualTrackingCallback ready to be passed to a solver.
- parameterized_inversion(parameterization: LinearOperator, /, *, parameter_prior: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearBayesianInversion[source]¶
Constructs a parameterized surrogate of the Bayesian inversion.
If the target formalism resolves to ‘model_space’ (which is typical for parameterized inversions), the parameter prior’s covariance matrix will be automatically densified to explicitly compute the required precision (inverse covariance) operator.
- Parameters:
parameterization – A LinearOperator mapping from the parameter space to the full model space.
parameter_prior – An optional prior measure on the parameter space. If not provided, the original model prior is pulled back to the parameter space automatically.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
formalism – An optional override for the formalism of the new inversion. If None, inherits the formalism of the parent inversion.
- Returns:
A new LinearBayesianInversion instance operating on the parameter space.
- posterior_expectation_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | None = None) LinearOperator | AffineOperator[source]¶
Constructs the operator mapping observed data to the posterior expectation.
The mapping evaluates F(d) = mu_u + K(d - A(mu_u) - mu_e).
If the prior and data error measures both have a zero expectation, this mapping is purely linear and returns the Kalman gain operator directly. Otherwise, it regroups the terms into an AffineOperator: F(d) = K(d) + (mu_u - K(A(mu_u) + mu_e)).
- Parameters:
solver – The LinearSolver used to invert the normal operator.
preconditioner – Optional preconditioner for iterative solvers.
- Returns:
A LinearOperator (if expectations are zero) or an AffineOperator.
- sparse_localized_preconditioner(interacting_blocks: list[list[int]], rank: int = 10, parallel: bool = False, n_jobs: int = -1) LinearOperator[source]¶
Builds a sparse preconditioner specifically for the data-space Bayesian normal equations using randomized Nystrom approximations on localized, potentially overlapping sub-blocks.
- Parameters:
interacting_blocks – A list of lists, where each sub-list contains the indices of data points that strongly couple to each other.
rank – The rank of the randomized Nystrom approximation to use per block.
parallel – If True, computes the sub-block approximations in parallel.
n_jobs – Number of CPU cores to use if parallel=True (-1 uses all cores).
- Returns:
A LinearOperator representing the inverse of the sparse approximation.
- Raises:
ValueError – If the inversion was initialized with formalism=’model_space’, as this preconditioner is mathematically invalid for that normal operator.
- surrogate_inversion(*, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearBayesianInversion[source]¶
Constructs a surrogate Bayesian inversion problem using simplified physics, priors, or data errors.
This is primarily used to construct robust, computationally cheap surrogate models to use as preconditioners for the full, complex inverse problem.
- Parameters:
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A new LinearBayesianInversion instance representing the surrogate problem. The surrogate inherits the formalism of the parent problem.
- Raises:
ValueError – If the alternative operators/measures exist in incompatible domains/codomains.
- surrogate_normal_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a preconditioner by exactly inverting the normal operator of a simplified surrogate inverse problem.
- Parameters:
solver – The LinearSolver to use to exactly invert the surrogate normal operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A LinearOperator representing the inverse of the surrogate normal equations.
- surrogate_woodbury_data_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None, prior_solver: LinearSolver | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Builds a data-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
This method chains the construction of the surrogate model with the extraction of the Woodbury inverse in one step.
Note
Ensure that any alternate measures provided have well-defined inverse covariances, or use .with_regularized_inverse() on them before passing them to this method.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
prior_solver – Optional solver for the prior covariance.
noise_solver – Optional solver for the noise covariance.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- surrogate_woodbury_model_preconditioner(solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_prior_measure: GaussianMeasure | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a model-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_prior_measure – An optional simplified prior measure.
alternate_data_error_measure – An optional simplified data error measure.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearBayesianInversion[source]¶
Returns a new instance of the Bayesian inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearBayesianInversion instance sharing the exact same forward problem and prior measure, but configured to use the specified formalism.
- woodbury_data_preconditioner(solver: LinearSolver, /, *, prior_solver: LinearSolver | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Constructs a data-space preconditioner using the Woodbury matrix identity.
Data Space Normal Operator: N_d = A Q A* + R Woodbury Identity: N_d^-1 = R^-1 - R^-1 A (Q^-1 + A* R^-1 A)^-1 A* R^-1
Note
This method assumes the prior (Q) and noise (R) measures either already have well-defined inverse covariances, or are well-conditioned enough to be inverted by the provided solvers. If your prior is an unbounded operator on a function space, use Q.with_regularized_inverse() before passing it to the inversion.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator (N_m).
prior_solver – An optional solver used to explicitly invert the prior covariance (Q) if its inverse is not already set. Defaults to solver if not provided.
noise_solver – An optional solver used to explicitly invert the data error covariance (R) if its inverse is not already set. Defaults to solver if not provided.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- woodbury_model_preconditioner(solver: LinearSolver, /) LinearOperator[source]¶
Constructs a model-space preconditioner using the Woodbury matrix identity.
Model Space Normal Operator: N_m = Q^-1 + A* R^-1 A Woodbury Identity: N_m^-1 = Q - Q A* (R + A Q A*)^-1 A Q
Note
Unlike the data-space Woodbury identity, this formulation does not require evaluating the explicit inverses of the prior (Q) or noise (R) covariances, making it highly robust for unbounded or complex measures.
- Parameters:
solver – The LinearSolver used to invert the inner Woodbury operator (N_d).
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- class pygeoinf.LinearForm(domain: HilbertSpace, /, *, components: np.ndarray | None = None, mapping: Callable[[Vector], float] | None = None, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
NonLinearFormRepresents a linear form as an efficient, component-based functional.
A LinearForm is an element of a dual HilbertSpace and is defined by its action on vectors from its domain. Internally, this action is represented by a component vector. This class provides optimized arithmetic operations and correctly defines the gradient (a constant vector) and the Hessian (the zero operator) for any linear functional.
- property as_linear_operator: LinearOperator¶
Represents the linear form as a LinearOperator.
The resulting operator maps from the form’s original domain to a 1-dimensional EuclideanSpace, where the single component of the output is the scalar result of the form’s action.
- property components: ndarray¶
The component vector of the form.
- copy() LinearForm[source]¶
Creates a deep copy of the linear form.
- property domain: HilbertSpace¶
The Hilbert space on which the form is defined.
- static from_linear_operator(operator: LinearOperator) LinearForm[source]¶
Creates a LinearForm from an operator that maps to a 1D Euclidean space.
- class pygeoinf.LinearForwardProblem(forward_operator: LinearOperator, /, *, data_error_measure: GaussianMeasure | None = None)[source]¶
Bases:
ForwardProblemRepresents a linear forward problem of the form d = A(u) + e.
Here, d is the data, A is the linear forward operator, u is the model, and e is a random error drawn from a Gaussian distribution.
- chi_squared(model: Vector, data: Vector) float[source]¶
Calculates the chi-squared statistic for a given model and data.
This measures the misfit between the predicted and observed data.
If a data error measure with an inverse covariance C_e^-1 is defined, this is the weighted misfit: (d - A(u))^T * C_e^-1 * (d - A(u)).
Otherwise, it is the squared L2 norm of the data residual: ||d - A(u)||^2.
- Parameters:
model – A vector from the model space.
data – An observed data vector from the data space.
- Returns:
The chi-squared statistic.
- chi_squared_from_residual(residual: Vector) float[source]¶
Calculates the chi-squared statistic from a residual vector.
- Parameters:
residual – The residual vector.
- Returns:
The chi-squared statistic.
- chi_squared_test(significance_level: float, model: Vector, data: Vector) bool[source]¶
Performs a chi-squared test for goodness of fit.
- Parameters:
significance_level – The significance level for the test (e.g., 0.95).
model – A vector from the model space.
data – An observed data vector from the data space.
- Returns:
True if the model is statistically compatible with the data at the specified significance level, False otherwise.
- critical_chi_squared(significance_level: float) float[source]¶
Returns the critical value of the chi-squared statistic.
This value serves as the threshold for the chi-squared test at a given significance level.
- Parameters:
significance_level – The desired significance level (e.g., 0.95).
- Returns:
The critical chi-squared value.
- data_measure_from_model(model: Vector) GaussianMeasure[source]¶
Returns the Gaussian measure for the data, given a specific model.
The resulting measure has a mean of A(model) and the covariance of the data error.
- Parameters:
model – A vector from the model space.
- Returns:
The Gaussian measure representing the distribution of possible data.
- data_measure_from_model_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the induced measure on the data space.
- data_reduced_problem(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1) LinearForwardProblem[source]¶
Creates a new forward problem by applying a reduction (or sketching) operator to the data space.
- Parameters:
reduction_operator – A LinearOperator mapping from the current data space to the new reduced data space.
reduced_data_error_measure – An optional data error measure on the reduced data space. If not provided, the original data error measure is pushed forward automatically.
dense – If True, computes and stores operators as dense matrices.
parallel – If True, computes the dense matrices in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
- Returns:
A new LinearForwardProblem operating in the reduced data space.
- static from_direct_sum(forward_problems: List[LinearForwardProblem]) LinearForwardProblem[source]¶
Forms a joint forward problem from a list of separate problems.
This is a powerful tool for joint inversions, where a single underlying model is observed through multiple, independent measurement systems (e.g., different types of geophysical surveys).
- Parameters:
forward_problems – A list of LinearForwardProblem instances that share a common model space.
- Returns:
A single LinearForwardProblem where the data space is the direct sum of the individual data spaces.
- joint_measure(model_measure: GaussianMeasure) GaussianMeasure[source]¶
Given a measure for the model space, returns the joint measure for the model and data.
- parameterized_problem(parameterization: LinearOperator, /, *, dense: bool = False, parallel: bool = False, n_jobs: int = -1) LinearForwardProblem[source]¶
Creates a new forward problem based on a model parameterization.
- synthetic_data(model: Vector) Vector[source]¶
Generates a synthetic data vector for a given model.
The data is computed as d = A(model) + e, where e is a random sample from the data error measure.
- Parameters:
model – A vector from the model space.
- Returns:
A synthetic data vector.
- synthetic_model_and_data(prior: GaussianMeasure) Tuple[Vector, Vector][source]¶
Generates a random model and corresponding synthetic data.
- Parameters:
prior – A Gaussian measure on the model space, from which the random model u will be drawn.
- Returns:
A tuple (u, d), where u is the random model and d is the corresponding synthetic data.
- class pygeoinf.LinearImageSupportFunction(base: SupportFunction, operator: LinearOperator)[source]¶
Bases:
SupportFunctionSupport function of the linear image $A(C)$ of a convex set $C$.
For a convex set $C subseteq H$ with support function $h_C$ and a bounded linear operator $A: H to K$, the support function of the image $A(C) subseteq K$ is
\[h_{A(C)}(q) = h_C(A^* q), \quad q \in K,\]where $A^*: K to H$ is the Hilbert-space adjoint of $A$.
- Parameters:
base – The support function $h_C$ of the base set $C subseteq H$. Its
primal_domainmust equaloperator.domain.operator – A bounded linear operator $A: H to K$.
operator.domainmust equalbase.primal_domain.
- Raises:
ValueError – If
operator.domaindoes not equalbase.primal_domain.
Note
The
primal_domainof the returned object isoperator.codomain(the space $K$ where the image $A(C)$ lives).Note
Phase 3:
support_point()propagates support points from the base, returning $x_C^*(A^* q)$ when available, orNoneif the base has no support point available.- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the image set $A(C)$ at direction $q in K$.
For the image support function $h_{A(C)}(q) = h_C(A^* q)$, the support point in direction $q$ is obtained by computing the base support point $x_C^*(A^* q)$ and then applying the operator: $x_{A(C)}^*(q) = A(x_C^*(A^* q))$.
- Parameters:
q – A vector in the codomain $K$.
- Returns:
The support point $A(x_C^*(A^* q)) in K$ if available, or
None.
- class pygeoinf.LinearLeastSquaresInversion(forward_problem: LinearForwardProblem, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionSolves a linear inverse problem using Tikhonov-regularized least-squares.
- This method finds the model u that minimizes the cost functional:
J(u) = ||A(u) - d||^2_R + damping * ||u||^2
where A is the forward operator, d is the observed data, R is the data covariance (if a data error measure is set), and damping is the Tikhonov regularization parameter.
This class supports two formalisms for constructing the linear system: 1. ‘model_space’: Solves the standard normal equations of size (N x N),
where N is the model dimension. Best for overdetermined problems.
‘data_space’: Solves the dual formulation of size (M x M), where M is the data dimension. Best for highly underdetermined problems.
- data_reduced_inversion(reduction_operator: LinearOperator, /, *, reduced_data_error_measure: GaussianMeasure | None = None, dense: bool = False, parallel: bool = False, n_jobs: int = -1, formalism: Literal['model_space', 'data_space'] | None = None) LinearLeastSquaresInversion[source]¶
Constructs a surrogate of the least-squares inversion using a reduced data space.
- least_squares_operator(damping: float, solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None) LinearOperator | AffineOperator[source]¶
Constructs the full operator that maps observed data directly to the least-squares model solution.
This method solves the internal normal equations and applies the necessary algebraic transformations (and affine shifts) to recover the model parameters from the data, seamlessly handling whichever formalism was selected during initialization.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver instance used to invert the normal operator.
preconditioner – An optional LinearOperator, or a LinearSolver factory, used to precondition the normal equations. Only utilized if the provided solver is an IterativeLinearSolver.
- Returns:
A LinearOperator (or AffineOperator, if a non-zero data expectation exists) that maps a vector from the data space to the optimal vector in the model space.
- Raises:
TypeError – If the provided preconditioner is neither a LinearOperator nor a LinearSolver.
- normal_operator(damping: float) LinearOperator[source]¶
Constructs the regularized normal operator for the chosen formalism.
For ‘model_space’, this returns: A* R^{-1} A + damping * I For ‘data_space’, this returns: A A* + damping * R
- Parameters:
damping – The non-negative Tikhonov regularization parameter.
- Returns:
A LinearOperator representing the left-hand side of the normal equations.
- Raises:
ValueError – If the damping parameter is negative.
- normal_residual_callback(damping: float, data: Vector, /, *, message: str = 'Iteration: {iter} | Normal Residual: {res:.3e}', print_progress: bool = True)[source]¶
Generates a ResidualTrackingCallback pre-configured to track the convergence of the least-squares normal equations for the given data vector.
- normal_rhs(data: Vector) Vector[source]¶
Computes the right-hand side vector for the normal equations.
Prior to construction, the data is shifted by the expected value of the data error measure (i.e., v - z_bar), if applicable.
For ‘model_space’, this returns: A* R^{-1} (v - z_bar) For ‘data_space’, this returns: (v - z_bar)
- Parameters:
data – The observed data vector in the data space.
- Returns:
The right-hand side Vector for the chosen linear system.
- surrogate_inversion(*, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearLeastSquaresInversion[source]¶
Constructs a surrogate least-squares inversion problem using simplified physics or data errors.
- surrogate_woodbury_data_preconditioner(damping: float, solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Builds a data-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
Note
Ensure that any alternate measures provided have well-defined inverse covariances, or use .with_regularized_inverse() on them before passing them to this method.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator.
alternate_forward_operator – An optional simplified forward operator.
alternate_data_error_measure – An optional simplified data error measure.
noise_solver – Optional solver for the noise covariance.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- surrogate_woodbury_model_preconditioner(damping: float, solver: LinearSolver, /, *, alternate_forward_operator: LinearOperator | None = None, alternate_data_error_measure: GaussianMeasure | None = None) LinearOperator[source]¶
Builds a model-space preconditioner by applying the Woodbury matrix identity to a simplified surrogate inverse problem.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearLeastSquaresInversion[source]¶
Returns a new instance of the inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearLeastSquaresInversion instance with the updated formalism.
- woodbury_data_preconditioner(damping: float, solver: LinearSolver, /, *, noise_solver: LinearSolver | None = None) LinearOperator[source]¶
Constructs a data-space preconditioner using the Woodbury matrix identity.
Data Space Normal Operator: N_d = A A* + damping * R Woodbury Identity: N_d^-1 = (1/damping) * [R^-1 - R^-1 A (A* R^-1 A + damping * I)^-1 A* R^-1]
Note
This method assumes the noise measure (R) either already has a well-defined inverse covariance, or is well-conditioned enough to be inverted by the provided solver. If it is an unbounded operator on a function space, use R.with_regularized_inverse() before passing it to the inversion.
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator (N_m).
noise_solver – An optional solver used to explicitly invert the data error covariance (R) if its inverse is not already set. Defaults to solver if not provided.
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- woodbury_model_preconditioner(damping: float, solver: LinearSolver, /) LinearOperator[source]¶
Constructs a model-space preconditioner using the Woodbury matrix identity.
Model Space Normal Operator: N_m = A* R^-1 A + damping * I Woodbury Identity: N_m^-1 = (1/damping) * [I - A* (damping * R + A A*)^-1 A]
Note
This formulation does not require evaluating the explicit inverse of the noise covariance (R).
- Parameters:
damping – The Tikhonov regularization parameter.
solver – The LinearSolver used to invert the inner Woodbury operator (N_d).
- Returns:
A LinearOperator representing the Woodbury-approximated inverse.
- class pygeoinf.LinearMinimumNormInversion(forward_problem: LinearForwardProblem, /, *, formalism: Literal['model_space', 'data_space'] = 'data_space')[source]¶
Bases:
LinearInversionFinds a regularized solution using the discrepancy principle.
This method finds the model u with the smallest norm that fits the data to a statistically acceptable degree (determined by a target chi-squared value and significance level).
This class supports two formalisms for constructing the linear systems: 1. ‘model_space’: Solves the normal equations of size (N x N). 2. ‘data_space’: Solves the dual formulation of size (M x M).
- minimum_norm_operator(solver: LinearSolver, /, *, preconditioner: LinearOperator | LinearSolver | None = None, significance_level: float = 0.95, minimum_damping: float = 0.0, maxiter: int = 100, rtol: float = 1e-06, atol: float = 0.0) NonLinearOperator | LinearOperator[source]¶
Maps data to the minimum-norm solution matching target chi-squared.
The returned NonLinearOperator includes the exact analytical Fréchet derivative of the discrepancy search, complete with its adjoint mapping.
- with_formalism(formalism: Literal['model_space', 'data_space']) LinearMinimumNormInversion[source]¶
Returns a new instance of the inversion using the specified formalism.
- Parameters:
formalism – The algebraic space in which the normal equations should be assembled and solved. Must be ‘model_space’ or ‘data_space’.
- Returns:
A new LinearMinimumNormInversion instance with the updated formalism.
- class pygeoinf.LinearOperator(domain: HilbertSpace, codomain: HilbertSpace, mapping: Callable[[Any], Any], /, *, dual_mapping: Callable[[Any], Any] | None = None, adjoint_mapping: Callable[[Any], Any] | None = None, dual_base: LinearOperator | None = None, adjoint_base: LinearOperator | None = None)[source]¶
Bases:
NonLinearOperator,LinearOperatorAxiomChecksA linear operator between two Hilbert spaces.
This class represents a linear map L(x) = Ax and provides rich functionality for linear algebraic operations. It specializes NonLinearOperator, with the derivative mapping taking the required form (i.e., the derivative is just the operator itself).
Key features include operator algebra (@, +, *), automatic derivation of adjoint (.adjoint) and dual (.dual) operators, and multiple matrix representations (.matrix()) for use with numerical solvers.
- property adjoint: LinearOperator¶
The adjoint of the operator.
- property dual: LinearOperator¶
The dual of the operator.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Computes the main diagonal of the operator’s matrix representation.
This method is highly parallelizable and memory-efficient, as it avoids forming the full dense matrix.
- Parameters:
galerkin – If True, computes the diagonal of the Galerkin matrix.
parallel – If True, computes the entries in parallel.
n_jobs – Number of parallel jobs to use.
- Returns:
A NumPy array containing the diagonal entries.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Computes specified diagonals of the operator’s matrix representation.
This is a memory-efficient and parallelizable method that computes the matrix one column at a time.
- Parameters:
offsets – A list of diagonal offsets to extract (e.g., [0] for the main diagonal, [-1, 0, 1] for a tridiagonal matrix).
galerkin – If True, computes the diagonals of the Galerkin matrix.
parallel – If True, computes columns in parallel.
n_jobs – Number of parallel jobs to use.
- Returns:
A NumPy array where each row is a diagonal.
The list of offsets.
This format is compatible with scipy.sparse.spdiags.
- Return type:
A tuple containing
- static from_formal_adjoint(domain: HilbertSpace, codomain: HilbertSpace, operator: LinearOperator) LinearOperator[source]¶
Constructs an operator on weighted spaces from one on the underlying spaces.
This is a key method for working with MassWeightedHilbertSpace. It takes an operator A that is defined on the simple, unweighted underlying spaces and “lifts” it to be a proper operator on the mass-weighted spaces. It correctly defines the new operator’s adjoint with respect to the weighted inner products.
This method automatically handles cases where the domain and/or codomain are a HilbertSpaceDirectSum, recursively building the necessary block-structured mass operators.
- Parameters:
domain – The (potentially) mass-weighted domain of the new operator.
codomain – The (potentially) mass-weighted codomain of the new operator.
operator – The original operator defined on the underlying, unweighted spaces.
- Returns:
A new LinearOperator that acts between the mass-weighted spaces.
- static from_formally_self_adjoint(domain: HilbertSpace, operator: LinearOperator) LinearOperator[source]¶
Constructs a self-adjoint operator on a weighted space.
This method takes an operator that is formally self-adjoint on an underlying (unweighted) space and promotes it to a truly self-adjoint operator on the MassWeightedHilbertSpace. It automatically handles HilbertSpaceDirectSum domains.
- Parameters:
domain (HilbertSpace) – The domain of the operator, which can be a MassWeightedHilbertSpace or a HilbertSpaceDirectSum.
operator (LinearOperator) – The operator to be converted.
- static from_linear_form(form: LinearForm) LinearOperator[source]¶
Creates a rank-1 LinearOperator from a single LinearForm.
The resulting operator maps from the form’s domain to a 1-dimensional Euclidean space.
The forward mapping evaluates the form: A(x) = [form(x)]. The dual mapping scales the form: A’(y’) = y’_0 * form. The adjoint mapping is handled automatically by the base class.
- Parameters:
form – A LinearForm representing a continuous linear functional.
- Returns:
A LinearOperator mapping from ‘form.domain’ to EuclideanSpace(1).
- static from_linear_forms(forms: List[LinearForm]) LinearOperator[source]¶
Creates an operator from a list of linear forms.
The resulting operator maps from the forms’ domain to an N-dimensional Euclidean space, where N is the number of forms.
- static from_matrix(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray | sp.sparray | ScipyLinOp, /, *, galerkin: bool = False) MatrixLinearOperator[source]¶
Creates the most appropriate LinearOperator from a matrix representation.
This factory method acts as a dispatcher, inspecting the type of the input matrix and returning the most specialized and optimized operator subclass (e.g., Dense, Sparse, or DiagonalSparse). It also handles matrix-free scipy.sparse.linalg.LinearOperator objects.
- Parameters:
domain – The operator’s domain space.
codomain – The operator’s codomain space.
matrix – The matrix representation (NumPy ndarray, SciPy sparray, or SciPy LinearOperator).
galerkin – If True, the matrix is interpreted in Galerkin form.
- Returns:
An instance of the most appropriate MatrixLinearOperator subclass.
- static from_tensor_product(domain: HilbertSpace, codomain: HilbertSpace, vector_pairs: List[Tuple[Any, Any]], /, *, weights: List[float] | None = None) LinearOperator[source]¶
Creates an operator from a weighted sum of tensor products.
The operator represents A(x) = sum_i( w_i * <x, v_i> * u_i ), where vector_pairs are (u_i, v_i).
- static from_vector(domain: HilbertSpace, vector: Vector) LinearOperator[source]¶
Creates a rank-1 LinearOperator from a single domain vector.
The resulting operator maps from the given domain to a 1-dimensional Euclidean space.
The forward mapping evaluates the inner product: A(x) = [<vector, x>]. The adjoint mapping scales the vector: A*(y) = y[0] * vector.
- Parameters:
domain – The Hilbert space the vector belongs to.
vector – A single vector in the domain space.
- Returns:
A LinearOperator mapping from ‘domain’ to EuclideanSpace(1).
- static from_vectors(domain: HilbertSpace, vectors: List[Vector]) LinearOperator[source]¶
Creates a LinearOperator from a list of domain vectors.
The resulting operator maps from the given domain to a Euclidean space of dimension n (where n is the number of vectors).
The forward mapping is given by A(x)_i = <vectors[i], x>. The adjoint mapping is given by A*(y) = sum(y_i * vectors[i]).
- Parameters:
domain – The Hilbert space the vectors belong to.
vectors – A list of vectors in the domain space.
- Returns:
A LinearOperator mapping from ‘domain’ to EuclideanSpace(len(vectors)).
- Raises:
ValueError – If the list of vectors is empty.
- property linear: bool¶
True, as this is a LinearOperator.
- matrix(*, dense: bool = False, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) LinearOperator | ndarray[source]¶
Returns a matrix representation of the operator.
This provides a concrete matrix that represents the operator’s action on the underlying component vectors.
- Parameters:
dense – If True, returns a dense numpy.ndarray. If False (default), returns a memory-efficient, matrix-free scipy.sparse.linalg.LinearOperator.
galerkin – If True, the returned matrix is the Galerkin representation, whose rmatvec corresponds to the adjoint operator. If False (default), the rmatvec corresponds to the dual operator. The Galerkin form is essential for algorithms that rely on symmetry/self-adjointness.
parallel – If True and dense=True, computes the matrix columns in parallel.
n_jobs – Number of parallel jobs to use. -1 uses all available cores.
- Returns:
The matrix representation, either dense or matrix-free.
- static self_adjoint(domain: HilbertSpace, mapping: Callable[[Any], Any]) LinearOperator[source]¶
Creates a self-adjoint operator.
- static self_adjoint_from_matrix(domain: HilbertSpace, matrix: np.ndarray | sp.sparray | ScipyLinOp) MatrixLinearOperator[source]¶
Creates the most appropriate self-adjoint LinearOperator from a matrix.
This factory acts as a dispatcher, returning the most specialized subclass for the given matrix type (e.g., Dense, Sparse).
It ALWAYS assumes the provided matrix is the Galerkin representation of the operator. The user is responsible for ensuring the input matrix is symmetric (or self-adjoint for ScipyLinOp).
- Parameters:
domain – The operator’s domain and codomain space.
matrix – The symmetric matrix representation.
- Returns:
An instance of the most appropriate MatrixLinearOperator subclass.
- static self_adjoint_from_tensor_product(domain: HilbertSpace, vectors: List[Any], /, *, weights: List[float] | None = None) LinearOperator[source]¶
Creates a self-adjoint operator from a tensor product sum.
- static self_dual(domain: HilbertSpace, mapping: Callable[[Any], Any]) LinearOperator[source]¶
Creates a self-dual operator.
- with_dense_matrix(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) DenseMatrixLinearOperator[source]¶
Returns a new operator equivalent to the existing one, but with its matrix representation computed and stored internally in dense form.
- Parameters:
galerkin – If True, the Galerkin representation is used. Default is False.
parallel – If True, computes the dense matrix in parallel.
n_jobs – Number of CPU cores to use. -1 means all available.
- Returns:
A DenseMatrixLinearOperator instance.
- class pygeoinf.LinearSubspace(projector: OrthogonalProjector)[source]¶
Bases:
AffineSubspaceRepresents a linear subspace (an affine subspace passing through the origin).
- property complement: LinearSubspace¶
Returns the orthogonal complement of this subspace as a new LinearSubspace.
- classmethod from_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) LinearSubspace[source]¶
Constructs a linear subspace from a set of basis vectors.
- Parameters:
domain – The Hilbert space.
basis_vectors – List of vectors spanning the subspace.
orthonormalize – Whether to orthonormalize the basis.
solver – Optional solver for implicit constraints (see AffineSubspace.from_tangent_basis).
preconditioner – Optional preconditioner.
- classmethod from_complement_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True) LinearSubspace[source]¶
Constructs a linear subspace defined by orthogonality to a complement basis. S = {u | <u, v_i> = 0}.
- Parameters:
domain – The Hilbert space.
basis_vectors – Basis vectors for the complement.
orthonormalize – Whether to orthonormalize the complement basis.
- classmethod from_kernel(operator: LinearOperator, solver: LinearSolver | None = None, preconditioner: LinearOperator | None = None) LinearSubspace[source]¶
Constructs the subspace corresponding to the kernel (null space) of an operator. K = {u | A(u) = 0}.
- Parameters:
operator – The operator A.
solver – Solver used for the Gram matrix (A A*).
preconditioner – Optional preconditioner.
- class pygeoinf.LowRankCholesky(l_op: LinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the Cholesky-like factorization: A ≈ L @ L*.
This class provides a memory-efficient low-rank Cholesky decomposition of a positive semi-definite operator, highly useful for drawing samples from Gaussian measures.
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = True, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankCholesky[source]¶
Computes a robust approximate Cholesky factorization via randomized range finding.
Attempts a direct dense Cholesky factorization on the projected core matrix. If it fails (due to numerical precision issues), it safely falls back to an Eigendecomposition-based square root.
- Parameters:
operator (LinearOperator) – Positive semi-definite operator to factorize.
size_estimate (int) – Target rank or initial block size.
measure (GaussianMeasure, optional) – Prior measure for drawing test vectors.
galerkin (bool) – Default True. Computes Galerkin representation on fallback.
method (str) – {‘variable’, ‘fixed’}.
max_rank (int, optional) – Upper limit on rank for ‘variable’ method.
power (int) – Number of power iterations.
rtol (float) – Relative tolerance for ‘variable’ method.
block_size (int) – Samples per iteration.
parallel (bool) – Parallelize the sampling/multiplication.
n_jobs (int) – CPU cores to utilize.
- Returns:
An instantiated operator containing the L factor.
- Return type:
- Raises:
ValueError – If the operator is not an automorphism.
- property l_factor: LinearOperator¶
The Cholesky factor (L).
- Type:
- property rank: int¶
The rank of the approximation.
- Type:
int
- class pygeoinf.LowRankEig(u_op: LinearOperator, d_op: DiagonalSparseMatrixLinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the eigendecomposition: A ≈ U @ D @ U*.
This class encapsulates the components of an Eigendecomposition for a self-adjoint operator, allowing it to act as a LinearOperator while exposing the eigenvectors and eigenvalues.
- apply_function(func: Callable[[ndarray], ndarray], *, regularization: float = 0.0) LowRankEig[source]¶
Applies a function to the spectrum of the operator. Returns a new LowRankEig representing f(A).
- property d_factor: DiagonalSparseMatrixLinearOperator¶
The diagonal matrix of eigenvalues (D).
- property eigenvalues: ndarray¶
A 1D array of the computed eigenvalues.
- Type:
np.ndarray
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = True, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankEig[source]¶
Computes the Eigendecomposition using a unified randomized range finder.
- Parameters:
operator (LinearOperator) – The self-adjoint operator to approximate.
size_estimate (int) – Target rank or initial block size.
measure (GaussianMeasure, optional) – Prior measure for drawing test vectors.
galerkin (bool) – Default True for Eig. Computes Galerkin representation on fallback.
method (str) – {‘variable’, ‘fixed’}.
max_rank (int, optional) – Upper limit on rank for ‘variable’ method.
power (int) – Number of power iterations.
rtol (float) – Relative tolerance for ‘variable’ method.
block_size (int) – Samples per iteration.
parallel (bool) – Parallelize the sampling/multiplication.
n_jobs (int) – CPU cores to utilize.
- Returns:
An instantiated operator containing the U and D factors.
- Return type:
- Raises:
ValueError – If the operator is not an automorphism (domain != codomain).
- property rank: int¶
The rank of the approximation.
- Type:
int
- property u_factor: LinearOperator¶
The eigenvectors (U).
- Type:
- class pygeoinf.LowRankSVD(u_op: LinearOperator, sigma_op: DiagonalSparseMatrixLinearOperator, v_op: LinearOperator)[source]¶
Bases:
LinearOperatorA LinearOperator representing the low-rank SVD: A ≈ U @ Sigma @ V*.
This class encapsulates the components of a Singular Value Decomposition, allowing it to be used directly as a LinearOperator while providing access to the individual low-rank factors.
- classmethod from_randomized(operator: LinearOperator, size_estimate: int, *, measure: GaussianMeasure | None = None, galerkin: bool = False, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1) LowRankSVD[source]¶
Computes the SVD using a unified randomized range finder.
- Parameters:
operator (LinearOperator) – The operator to approximate.
size_estimate (int) – For ‘fixed’ method, the exact target rank. For ‘variable’ method, this is the initial rank to sample.
measure (GaussianMeasure, optional) – A prior measure used to draw test vectors. If provided, respects the domain’s geometry. If None, falls back to a component-based SciPy LinearOperator representation.
galerkin (bool) – If True, computes the Galerkin representation when falling back to components.
method (str) – {‘variable’, ‘fixed’}. The rank-determination algorithm to use.
max_rank (int, optional) – Hard limit on the rank for the ‘variable’ method.
power (int) – Number of power iterations to improve accuracy.
rtol (float) – Relative tolerance for the ‘variable’ method.
block_size (int) – Number of new vectors to sample per iteration in ‘variable’ method.
parallel (bool) – Whether to parallelize the matrix/operator evaluations.
n_jobs (int) – Number of cores to use if parallel=True (-1 for all).
- Returns:
An instantiated operator containing the U, Sigma, and V factors.
- Return type:
- property rank: int¶
The rank of the approximation.
- Type:
int
- property sigma_factor: DiagonalSparseMatrixLinearOperator¶
The diagonal matrix of singular values (Sigma).
- property singular_values: ndarray¶
A 1D array of the computed singular values.
- Type:
np.ndarray
- property u_factor: LinearOperator¶
The left singular vectors (U).
- Type:
- property v_factor: LinearOperator¶
The right singular vectors (V).
- Type:
- class pygeoinf.MassWeightedHilbertModule(underlying_space: HilbertModule, mass_operator: LinearOperator, inverse_mass_operator: LinearOperator)[source]¶
Bases:
MassWeightedHilbertSpace,HilbertModuleA mass-weighted Hilbert space that also supports vector multiplication.
This class inherits the mass-weighted inner product structure and mixes in the HilbertModule interface, delegating the multiplication operation to the underlying space.
- class pygeoinf.MassWeightedHilbertSpace(underlying_space: HilbertSpace, mass_operator: LinearOperator, inverse_mass_operator: LinearOperator)[source]¶
Bases:
HilbertSpaceA Hilbert space with an inner product weighted by a mass operator.
This class wraps an existing HilbertSpace (let’s call it X) and defines a new inner product for a space (Y) as: (u, v)_Y = (M @ u, v)_X, where M is a self-adjoint, positive-definite mass operator defined on X.
This is a common construction in numerical methods like the Finite Element Method, where the basis functions are not orthonormal.
- axpy(a: float, x: Vector, y: Vector) None[source]¶
Performs in-place operation y := y + a*x. Defaults to y += a*x.
- property dim: int¶
The dimension of the space.
- from_dual(xp: LinearForm) Vector[source]¶
Computes the inverse dual mapping R_Y^{-1}(xp) = M^{-1} R_X^{-1}(xp).
- inner_product(x1: Vector, x2: Vector) float[source]¶
Computes the inner product of two vectors.
Notes
Default implementation overrident for efficiency.
- property inverse_mass_operator: LinearOperator¶
The inverse of the mass operator.
- property mass_operator: LinearOperator¶
The mass operator (M) defining the weighted inner product.
- subtract(x: Vector, y: Vector) Vector[source]¶
Computes the difference of two vectors. Defaults to x - y.
- to_dual(x: Vector) LinearForm[source]¶
Computes the dual mapping R_Y(x) = R_X(M x).
- property underlying_space: HilbertSpace¶
The underlying Hilbert space (X) without mass weighting.
- property zero: Vector¶
The zero vector (additive identity) of the space.
- class pygeoinf.MatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: np.ndarray | ScipyLinOp, /, *, galerkin=False)[source]¶
Bases:
LinearOperatorA sub-class of LinearOperator for which the operator’s action is defined internally through its matrix representation.
This matrix can be either a dense numpy matrix or a scipy LinearOperator.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Overload for efficiency.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for efficiency by extracting diagonals directly from the stored dense matrix when possible.
- property is_dense: bool¶
Returns True if the matrix representation is stored internally in dense form.
- property is_galerkin: bool¶
Returns True if the matrix representation is stored in Galerkin form.
- class pygeoinf.MinResSolver(*, preconditioning_method: LinearSolver = None, rtol: float = 1e-05, atol: float = 1e-08, maxiter: int | None = None)[source]¶
Bases:
IterativeLinearSolverA matrix-free implementation of the MINRES algorithm.
Suitable for symmetric, possibly indefinite or singular linear systems. It minimizes the norm of the residual ||r|| in each step using the Hilbert space’s native inner product.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.MinkowskiSumSupportFunction(left: SupportFunction, right: SupportFunction)[source]¶
Bases:
SupportFunctionSupport function of the Minkowski sum $C oplus D$.
For two convex sets $C, D subseteq H$ with support functions $h_C$ and $h_D$ on the same Hilbert space $H$, the support function of their Minkowski sum $C oplus D = {c + d : c in C,, d in D}$ is
\[h_{C \oplus D}(q) = h_C(q) + h_D(q), \quad q \in H.\]- Parameters:
left – Support function $h_C$.
right – Support function $h_D$.
right.primal_domainmust equalleft.primal_domain.
- Raises:
ValueError – If
left.primal_domainandright.primal_domaindiffer.
Note
Phase 3:
support_point()conservatively returns the sum of support points only when both operands have support points available. If either operand has no support point, returnsNone(unavailable).- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the Minkowski sum $C oplus D$ at direction $q$.
If both the left and right operands have support points $x_L^*(q)$ and $x_R^*(q)$ available, return their sum $x_L^*(q) + x_R^*(q)$ (a support point of the sum set). Otherwise return
None(conservative: neither is available or computing the sum is unsafe).- Parameters:
q – A vector in the shared primal space $H$.
- Returns:
The sum of support points $x_L^*(q) + x_R^*(q)$ if both are available, or
None.
- class pygeoinf.NonLinearForm(domain: HilbertSpace, mapping: Callable[[Vector], float], /, *, gradient: Callable[[Vector], Vector] | None = None, subgradient: Callable[[Vector], Vector] | None = None, hessian: Callable[[Vector], LinearOperator] | None = None)[source]¶
Bases:
objectRepresents a general non-linear functional that maps vectors to scalars.
This class serves as the foundation for all forms. It defines the basic callable interface form(x) and overloads arithmetic operators (+, -, *) to create new forms. It also provides an optional framework for specifying a form’s gradient, Hessian, and subgradient.
For smooth functions, use gradient and hessian. For non-smooth convex functions, use subgradient.
- derivative(x: Vector) LinearForm[source]¶
Computes the derivative of the form at a given point.
- Parameters:
x – The vector at which to evaluate the derivative.
- Returns:
The derivative of the form as a LinearForm.
- Raises:
NotImplementedError – If a gradient function was not provided during initialization.
- property domain: HilbertSpace¶
The Hilbert space on which the form is defined.
- gradient(x: Any) Vector[source]¶
Computes the gradient of the form at a given point.
- Parameters:
x – The vector at which to evaluate the gradient.
- Returns:
The gradient of the form as a vector in the domain space.
- Raises:
NotImplementedError – If a gradient function was not provided during initialization.
- property has_gradient: bool¶
True if the form has a gradient.
- property has_hessian: bool¶
True if the form has a Hessian.
- property has_subgradient: bool¶
True if the form has a subgradient.
- hessian(x: Any) LinearOperator[source]¶
Computes the Hessian of the form at a given point.
- Parameters:
x – The vector at which to evaluate the Hessian.
- Returns:
The Hessian of the form as a LinearOperator mapping the domain to itself.
- Raises:
NotImplementedError – If a Hessian function was not provided during initialization.
- subgradient(x: Any) Vector[source]¶
Computes a subgradient of the form at a given point.
- For convex functions, a subgradient g ∈ ∂f(x) satisfies:
f(y) ≥ f(x) + ⟨g, y - x⟩ for all y
At points where the function is differentiable, the subgradient equals the gradient. At non-smooth points, there may be multiple subgradients; this method returns one of them.
- Parameters:
x – The vector at which to evaluate the subgradient.
- Returns:
A subgradient of the form as a vector in the domain space.
- Raises:
NotImplementedError – If a subgradient function was not provided during initialization.
- class pygeoinf.NonLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, mapping: Callable[[Vector], Any], /, *, derivative: Callable[[Vector], LinearOperator] = None)[source]¶
Bases:
NonLinearOperatorAxiomChecksRepresents a general non-linear operator that maps vectors to vectors.
This class provides a functional representation for an operator F(x), and includes an interface for its Fréchet derivative, F’(x), which is the linear operator that best approximates F at a given point x. It serves as the base class for the more specialized LinearOperator.
- property codomain: HilbertSpace¶
The codomain of the operator.
- derivative(x: Vector) LinearOperator[source]¶
Computes the Fréchet derivative of the operator at a given point.
The Fréchet derivative is the linear operator that best approximates the non-linear operator in the neighborhood of the point x.
- Parameters:
x – The point at which to compute the derivative.
- Returns:
The derivative as a LinearOperator.
- Raises:
NotImplementedError – If a derivative function was not provided.
- property domain: HilbertSpace¶
The domain of the operator.
- property has_derivative: bool¶
Returns true if the operators derivative is implemented.
- property is_automorphism: bool¶
True if the operator maps a space into itself.
- property is_square: bool¶
True if the operator’s domain and codomain have the same dimension.
- class pygeoinf.NormalisedEllipsoid(domain: HilbertSpace, center: Vector, operator: LinearOperator, open_set: bool = False)[source]¶
Bases:
EllipsoidRepresents a normalised ellipsoid with radius 1: E = {x | <A(x-c), x-c> <= 1}.
- class pygeoinf.OrthogonalProjector(domain: HilbertSpace, mapping: Callable[[Any], Any], complement_projector: LinearOperator | None = None)[source]¶
Bases:
LinearOperatorInternal engine for subspace projections. Represents an orthogonal projection operator P = P* = P^2.
- property complement: LinearOperator¶
Returns the projector onto the orthogonal complement (I - P).
If a complement projector was not provided at initialization, one is constructed automatically as the difference between the identity and self.
- classmethod from_basis(domain: HilbertSpace, basis_vectors: List[Vector], orthonormalize: bool = True) OrthogonalProjector[source]¶
Constructs a projector P onto the span of the provided basis vectors.
- Parameters:
domain – The Hilbert space.
basis_vectors – A list of vectors spanning the subspace.
orthonormalize – If True, performs Gram-Schmidt orthonormalization on the basis vectors before constructing the projector. If False, assumes the basis is already orthonormal.
- Returns:
An OrthogonalProjector instance.
- class pygeoinf.PointSupportFunction(primal_domain: HilbertSpace, point: Vector)[source]¶
Bases:
SupportFunctionSupport function of the singleton set ${p}$.
For a fixed point $p in H$, the support function of the singleton set ${p}$ is
\[h_{\{p\}}(q) = \langle q, p \rangle, \quad q \in H.\]The support point is always $p$ (the unique element of the set), so
subgradient()is available for all query directions.- Parameters:
primal_domain – The Hilbert space $H$ containing the point $p$.
point – The fixed point $p$.
Example:
p = np.array([1.0, 2.0]) h = PointSupportFunction(space, p) h(np.array([3.0, -1.0])) # returns 3*1 + (-1)*2 = 1.0
- class pygeoinf.PrimalKKTSolver(B: SupportFunction, V: SupportFunction, G: LinearOperator, d_tilde: Vector, /, *, fsolve_tol: float = 1e-10, fsolve_maxfev: int = 200)[source]¶
Bases:
objectPrimal KKT solver via Woodbury identity in abstract Hilbert spaces.
The solver operates on abstract Hilbert-space vectors throughout: the model space $H$ is never discretised. Only the data space $D$ (which is explicitly finite-dimensional) is discretised — and only inside
_woodbury_solve(), which builds the $M times M$ Woodbury system.The Woodbury reduction:
\[u^*(\lambda,\mu) = \frac{1}{\lambda} A_B^{-1} r_H - \frac{1}{\lambda} A_B^{-1} G^* K^{-1} G A_B^{-1} r_H\]where
\[r_H = c + \lambda A_B u_0 + \mu G^* A_V \tilde{d}, \qquad K = \tfrac{1}{\mu} A_V^{-1} + \tfrac{1}{\lambda} G A_B^{-1} G^*\]The $M times M$ matrix $P = G A_B^{-1} G^*$ is precomputed once via
.matrix(dense=True)which probes the data space only. No model-spaceto_componentsorfrom_componentsis ever called.Ball/ball simplification ($A_B = I_H$, $A_V = I_D$):
\[r_H = c + \lambda u_0 + \mu G^* \tilde{d}, \qquad P = G G^*, \qquad K = \tfrac{1}{\mu} I_D + \tfrac{1}{\lambda} G G^*\]so the only M×M solve is $K z = G w$ and no model-space matrix is ever formed.
Supports
BallSupportFunctionandEllipsoidSupportFunctionfor both $B$ and $V$ (four combinations).- Parameters:
B – Model prior support function.
V – Data error support function (ball or ellipsoid, centered at origin).
G – Forward operator $G : H to D$.
d_tilde – Observed data vector in $D$.
fsolve_tol – Tolerance for
scipy.optimize.fsolve.fsolve_maxfev – Maximum function evaluations for
fsolve.
- solve(c: Vector) KKTResult[source]¶
Solve for $u^*$ maximising $langle c, u rangle$ over the feasible set.
Uses a two-branch strategy:
Compute the support point $u_{rm ball}$ of $B$ in direction $c$. If the data constraint is satisfied, return immediately.
Otherwise both constraints are active; solve the $2 times 2$ root-finding problem in log-space via
scipy.optimize.fsolve, warm-started from $(lambda_{rm prev}, mu_{rm prev})$.
The model space is never discretised during this method.
- Parameters:
c – Linear objective in model space $H$.
- Returns:
KKTResultwith the optimal model vector $u^*$, KKT multipliers, convergence flag, and iteration count.
- class pygeoinf.ProgressCallback(message: str = 'Iteration: ')[source]¶
Bases:
objectA simple callback that prints the solver’s iteration count.
- class pygeoinf.ProximalBundleMethod(oracle: NonLinearForm, /, *, rho0: float = 1.0, rho_factor: float = 2.0, tolerance: float = 1e-06, max_iterations: int = 500, bundle_size: int = 100, store_iterates: bool = False, qp_solver: QPSolver | None = None)[source]¶
Bases:
objectProximal bundle method for minimising a non-smooth convex function.
- Solves:
min_{lambda in D} f(lambda)
where f is a convex function accessible through a value + subgradient oracle (a
NonLinearFormwithsubgradient).- At each iteration the master QP is:
min_{lambda, t} t + (rho / 2) ||lambda - lambda_hat||^2 subject to: f_j + <g_j, lambda - x_j> <= t for all j in bundle
where lambda_hat is the current stability centre and rho > 0 is the proximal weight.
A serious step is taken whenever the new oracle value f(lambda_+) < f(lambda_hat); otherwise a null step occurs and rho is increased to tighten the proximal term.
- Parameters:
oracle – Non-smooth convex functional with subgradient oracle.
rho0 – Initial proximal weight rho > 0.
rho_factor – Multiplicative factor applied to rho on null steps (divide on serious steps).
tolerance – Convergence tolerance; terminates when the duality gap f_up - f_low <= tolerance.
max_iterations – Maximum number of oracle calls.
bundle_size – Maximum number of cuts retained in the bundle.
store_iterates – If
True, all iterates are stored inBundleResult.iterates.qp_solver – QP solver implementing
QPSolver. Defaults toSciPyQPSolverifNone.
Examples
>>> from pygeoinf.hilbert_space import EuclideanSpace >>> from pygeoinf.nonlinear_forms import NonLinearForm >>> import numpy as np >>> domain = EuclideanSpace(1) >>> f = lambda x: float(x[0]**2 + 2*x[0]) >>> g = lambda x: np.array([2*x[0] + 2.0]) >>> oracle = NonLinearForm(domain, f, subgradient=g) >>> solver = ProximalBundleMethod(oracle, tolerance=1e-5) >>> result = solver.solve(domain.from_components(np.array([2.0]))) >>> np.testing.assert_allclose(domain.to_components(result.x_best), [-1.0], atol=1e-3)
- solve(x0: Vector) BundleResult[source]¶
Run the proximal bundle method starting from x0.
- Parameters:
x0 – Initial point in the domain of the oracle.
- Returns:
A
BundleResultsummarising the optimisation run.
- class pygeoinf.ResidualTrackingCallback(operator: LinearOperator, y: Vector, print_progress: bool = True, message: str = 'Iteration: {iter} | Residual: {res:.3e}')[source]¶
Bases:
ProgressCallbackA callback that computes and tracks the exact residual norm ||y - A(x)||.
Warning: This evaluates the forward operator once per iteration. For very large problems, this may introduce computational overhead.
- class pygeoinf.RowLinearOperator(operators: List[LinearOperator])[source]¶
Bases:
LinearOperator,BlockStructureAn operator that maps from a direct sum space to a single space.
It can be visualized as a row vector of operators, [A_1, A_2, …]. It takes a list of input vectors [x_1, x_2, …] and produces a single output vector y = A_1(x_1) + A_2(x_2) + …. The adjoint of a ColumnLinearOperator is a RowLinearOperator.
- block(i: int, j: int) LinearOperator[source]¶
Returns the operator in the (0, j)-th sub-block.
- class pygeoinf.ScaledSupportFunction(base: SupportFunction, alpha: float)[source]¶
Bases:
SupportFunctionSupport function of a nonnegatively scaled convex set $alpha C$.
For a convex set $C subseteq H$ with support function $h_C$ and a scalar $alpha geq 0$, the support function of the scaled set is
\[h_{\alpha C}(q) = \alpha\, h_C(q), \quad q \in H.\]When $alpha = 0$ the set $0 cdot C = {0}$ and $h(q) = 0$ for all $q$.
- Parameters:
base – The support function $h_C$.
alpha – A nonnegative scalar.
- Raises:
ValueError – If
alpha < 0.
Note
Phase 3:
support_point()propagates support points by scaling them. For $alpha > 0$: returns $alpha cdot x_C^*(q)$ if available; For $alpha = 0$: returns the zero vector (support point of ${0}$); If base has no support_point, returnsNone.- support_point(q: Vector) 'Vector' | None[source]¶
Return the support point of the scaled set $alpha C$ at direction $q$.
For $alpha > 0$: Returns $alpha cdot x_C^*(q)$ if the base has a support point. For $alpha = 0$: Returns the zero vector (the unique support point of the singleton ${0}$). If the base has no support point and $alpha > 0$, returns
None.- Parameters:
q – A vector in the primal space $H$.
- Returns:
The scaled support point $alpha cdot x_C^*(q)$, the zero vector for $alpha=0$, or
None.
- class pygeoinf.ScipyIterativeSolver(method: str, /, *, preconditioning_method: LinearSolver = None, galerkin: bool = False, **kwargs)[source]¶
Bases:
IterativeLinearSolverA general iterative solver that wraps SciPy’s iterative algorithms.
This class provides a unified interface to SciPy’s sparse iterative solvers like cg, gmres, bicgstab, etc. The specific algorithm is chosen during instantiation, and keyword arguments are passed directly to the chosen SciPy function.
- solve_linear_system(operator: LinearOperator, preconditioner: LinearOperator | None, y: Vector, x0: Vector | None) Vector[source]¶
Solves the linear system Ax = y for x.
- Parameters:
operator (LinearOperator) – The operator A of the linear system.
preconditioner (LinearOperator, optional) – The preconditioner.
y (Vector) – The right-hand side vector.
x0 (Vector, optional) – The initial guess for the solution.
- Returns:
The solution vector x.
- Return type:
Vector
- class pygeoinf.ScipyUnconstrainedOptimiser(method: str, /, **kwargs: Any)[source]¶
Bases:
objectA wrapper for scipy.optimize.minimize that adapts a NonLinearForm.
Note on derivative-free methods: Internal testing has shown that the ‘Nelder-Mead’ solver can be unreliable for some problems, failing to converge to the correct minimum while still reporting success. The ‘Powell’ method appears to be more robust. Users should exercise caution and verify results when using derivative-free methods.
- minimize(form: NonLinearForm, x0: Vector) Vector[source]¶
Finds the minimum of a NonLinearForm starting from an initial guess.
- Parameters:
form (NonLinearForm) – The non-linear functional to minimize.
x0 (Vector) – The initial guess in the Hilbert space.
- Returns:
The vector that minimizes the form.
- Return type:
Vector
- class pygeoinf.SolutionTrackingCallback(domain: HilbertSpace, message: str = 'Iteration: ', print_progress: bool = True)[source]¶
Bases:
ProgressCallbackA callback that tracks the solution vector at each iteration.
Useful for visualizing the convergence path of the solver or calculating diagnostics post-hoc without slowing down the inversion.
- class pygeoinf.SparseMatrixLinearOperator(domain: HilbertSpace, codomain: HilbertSpace, matrix: sp.sparray, /, *, galerkin: bool = False)[source]¶
Bases:
MatrixLinearOperatorA specialization for operators represented by a modern SciPy sparse array.
This class requires a scipy.sparse.sparray object (e.g., csr_array) and provides optimized methods that delegate to efficient SciPy routines.
Upon initialization, the internal array is converted to the CSR (Compressed Sparse Row) format to ensure consistently fast matrix-vector products and row-slicing operations.
- extract_diagonal(*, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) ndarray[source]¶
Overrides the base method to efficiently extract the main diagonal.
- extract_diagonals(offsets: List[int], /, *, galerkin: bool = False, parallel: bool = False, n_jobs: int = -1) Tuple[ndarray, List[int]][source]¶
Overrides the base method for efficiency by extracting diagonals directly from the stored sparse array.
- property sparse_array: sparray¶
Provides public read-only access to the underlying SciPy sparse array.
- class pygeoinf.SpectralPreconditioningMethod(*, damping: float | None = None, rank: int = 20, method: str = 'variable', max_rank: int | None = None, power: int = 2, rtol: float = 0.0001, block_size: int = 10, parallel: bool = False, n_jobs: int = -1)[source]¶
Bases:
LinearSolverA LinearSolver wrapper that generates a spectral (low-rank) preconditioner.
This preconditioner uses a randomized eigendecomposition to invert the dominant modes of the operator. The unresolved tail is regularized using a damping parameter.
- class pygeoinf.Sphere(domain: HilbertSpace, center: Vector, radius: float)[source]¶
Bases:
EllipsoidSurfaceRepresents a sphere in a Hilbert space: S = {x | ||x - c||^2 = r^2}. This is an EllipsoidSurface where A is the Identity operator.
- class pygeoinf.SubgradientDescent(oracle: NonLinearForm, /, *, step_size: float, max_iterations: int = 500, store_iterates: bool = False, stagnation_window: int | None = None)[source]¶
Bases:
objectBasic subgradient descent for minimising non-smooth convex functions.
- Algorithm:
x_{k+1} = x_k - α * g_k
where g_k ∈ ∂f(x_k) is a subgradient (obtained via oracle.subgradient(x_k)).
This implementation uses CONSTANT step size α for all k. Convergence is not guaranteed with constant step size; use for learning/testing only.
- Parameters:
oracle – A NonLinearForm with subgradient() method returning subgradients.
step_size – Constant step size α > 0.
max_iterations – Maximum number of iterations.
store_iterates – Whether to store full history (memory intensive).
stagnation_window – Optional number of iterations without improvement to declare convergence.
- property domain: HilbertSpace¶
- property oracle: NonLinearForm¶
- solve(x0: Vector) SubgradientResult[source]¶
Run subgradient descent from initial point x0.
- class pygeoinf.SublevelSet(form: NonLinearForm, level: float, open_set: bool = False)[source]¶
Bases:
SubsetRepresents a sublevel set defined by a functional: S = {x | f(x) <= c}.
This class serves as a base for sets defined by inequalities. Unlike ConvexSubset, it does not assume the defining functional is convex.
- property boundary: Subset¶
Returns the boundary of the sublevel set. The boundary is typically the LevelSet {x | f(x) = c}.
- property form: NonLinearForm¶
The defining functional f(x).
- is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if f(x) <= c (or < c). Tolerance is scaled by max(1.0, |c|).
- property is_open: bool¶
True if the set is defined by strict inequality.
- property level: float¶
The scalar upper bound c.
- class pygeoinf.Subset(domain: HilbertSpace | None = None)[source]¶
Bases:
ABCAbstract base class for a subset of a HilbertSpace.
This class defines the minimal interface required for a mathematical set: knowing which space it lives in, determining if a vector belongs to it, accessing its boundary, and performing logical set operations.
- abstract property boundary: Subset¶
Returns the boundary of the subset.
- Returns:
A new Subset instance representing ∂S.
- Return type:
- property complement: Subset¶
S^c = {x | x not in S}.
- Returns:
A generic Complement wrapper around this set.
- Return type:
- Type:
Returns the complement of this set
- property domain: HilbertSpace¶
The underlying Hilbert space.
- Returns:
The HilbertSpace instance associated with this subset.
- Raises:
ValueError – If the domain was not set during initialization.
- intersect(other: Subset) Subset[source]¶
Returns the intersection of this set and another: S ∩ O.
If both sets are instances of ConvexSubset, this returns a ConvexIntersection, which combines their functionals into a single convex constraint F(x) = max(f1(x), f2(x)).
- Parameters:
other – Another Subset instance.
- Returns:
A new set representing elements present in both sets.
- Return type:
- abstract is_element(x: Vector, /, *, rtol: float = 1e-06) bool[source]¶
Returns True if the vector x lies within the subset.
- Parameters:
x – A vector from the domain.
rtol – Relative tolerance for floating-point comparisons (e.g., checking equality f(x) = c or inequality f(x) <= c).
- Returns:
True if x ∈ S, False otherwise.
- Return type:
bool
- property is_empty: bool¶
Returns True if the set is known to be empty.
- Returns:
True if the set contains no elements, False otherwise. Note that returning False does not guarantee the set is non-empty, only that it is not trivially known to be empty.
- Return type:
bool
- plot(on_subspace=None, *, bounds=None, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax=None, backend: str = 'auto')[source]¶
Visualize this subset along a 1D, 2D, or 3D affine subspace.
Delegates to pygeoinf.plot.plot_slice. For EuclideanSpace domains of dimension 1 or 2, on_subspace may be omitted and a canonical full-space
AffineSubspacewill be constructed automatically. For all other domains, on_subspace is required.- Parameters:
on_subspace – The
AffineSubspaceto slice along. Required unless the domain is a 1D or 2DEuclideanSpace.bounds – Plot bounds passed to
plot_slice.grid_size – Samples per axis (passed to
plot_slice).rtol – Oracle tolerance (passed to
plot_slice).alpha – Fill transparency in [0, 1] (passed to
plot_slice).cmap – Colormap for 2D plots (passed to
plot_slice).color – Color string for 1D plots (passed to
plot_slice).show_plot – Whether to call
plt.show()(passed toplot_slice).ax – Optional existing
Axesto draw into (passed toplot_slice).backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"(passed toplot_slice).
- Returns:
(fig, ax, payload)— identical toplot_slice.- Raises:
ValueError – If on_subspace is
Noneand the domain is not a 1D or 2DEuclideanSpace.TypeError – If the domain is not an
EuclideanSpace.
- class pygeoinf.SubspaceSlicePlotter(subset: Subset, on_subspace: AffineSubspace, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, bar_pixel_height: int = 6)[source]¶
Bases:
objectPlotter for visualizing subsets sliced along 1D, 2D, or 3D affine subspaces.
Fully implemented for 1D, 2D, and 3D subspaces via three rendering paths:
PolyhedralSet→ exact affine slice viascipy.spatial.HalfspaceIntersection+ convex hull; payload is vertex array(n_vertices, n_dims).Ball/Ellipsoid→ exact quadratic slice via Cholesky-factored pullback metric; no grid sampling is performed:1D slice:
payloadisnp.array([lo, hi])— the two interval endpoints.2D slice:
payloadis boundary points, shape(N, 2)(N ≈ 360).3D slice:
payloadis surface points, shape(N_pts, 3).
An empty or degenerate slice raises
ValueErrorexplicitly.All other sets → raster oracle sampling on a
grid_size^ngrid; payload is boolean membership mask. For 3D, the mask is rendered as filled voxels using Matplotlib’smpl_toolkits.mplot3dbackend (Axes3D.voxels()).
Architecture:
Common methods (
parse_bounds,embed_point,sample_membership) work for 1D, 2D, and 3D.Dimension-specific
_render_*()methods handle visualization.
- embed_point(params: float | Tuple[float, ...] | List[float]) object[source]¶
Map parameter(s) to ambient point using tangent basis.
Universal formula (works for any dimension): x = translation + sum(params[i] * tangent_basis[i])
- Parameters:
params
1D (-) – Single float
2D (-) – 2-tuple (u, v)
3D (-) – 3-tuple (u, v, w)
- Returns:
Ambient point as Vector
- parse_bounds(bounds: tuple | List | None) tuple[source]¶
Parse and validate bounds for current dimension.
Flexible input format handling: - None: Use default [-1, 1] per dimension - 1D: (u_min, u_max) - 2D: (u_min, u_max, v_min, v_max) OR ((u_min, u_max), (v_min, v_max)) - 3D: (u_min, u_max, v_min, v_max, w_min, w_max) OR
((u_min, u_max), (v_min, v_max), (w_min, w_max))
- Parameters:
bounds – User-provided bounds or None
- Returns:
1D: (u_min, u_max)
2D: (u_min, u_max, v_min, v_max)
3D: (u_min, u_max, v_min, v_max, w_min, w_max)
- Return type:
Normalized tuple
- Raises:
ValueError – If bounds format doesn’t match dimension
- plot(bounds: tuple | List | None = None, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax: Axes | None = None, backend: str = 'auto') tuple[source]¶
Main plotting method. Orchestrates bounds parsing, grid generation, membership sampling, and dimension-specific rendering.
- Parameters:
bounds – Plot bounds (format depends on dimension)
cmap – Colormap for 2D/3D (ignored for 1D)
color – Color for 1D (ignored for 2D/3D)
show_plot – Whether to display the plot
ax – Optional existing Matplotlib Axes (must be
Nonewhenbackend='plotly').backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"."auto"selects Plotly for 3D when it is installed and falls back to Matplotlib otherwise. 1D/2D always use Matplotlib regardless of the backend value.
- Returns:
(fig, ax, payload)tuple.When the Matplotlib backend is used fig is a
matplotlib.figure.Figureand ax is a Matplotlib Axes. When the Plotly backend is used fig is aplotly.graph_objects.Figureand ax isNone.payload semantics depend on the rendering path:
PolyhedralSet(exact affine path): vertex array in parameter coords, shape(n_vertices, n_dims).Ball/Ellipsoid(exact quadratic path): interval endpoints[lo, hi]for 1D; boundary points(N, 2)for 2D; surface points(N_pts, 3)for 3D. Empty slices raiseValueError.All other sets (sampled path): boolean membership mask, shape
(grid_size,)in 1D,(grid_size, grid_size)in 2D, or(grid_size, grid_size, grid_size)in 3D.
- Raises:
ValueError – If
axis notNonewhenbackend='plotly'.
- sample_membership(param_grid: ndarray | Tuple[ndarray, ...]) ndarray[source]¶
Evaluate subset membership on parameter grid.
For each grid point, converts parameter coordinates to ambient space via embed_point(), then tests membership using subset.is_element().
- Parameters:
param_grid – Parameter grid from _generate_param_grid()
- Returns:
1D: shape (grid_size,)
2D: shape (grid_size, grid_size)
3D: shape (grid_size, grid_size, grid_size)
- Return type:
Boolean mask array
- class pygeoinf.SupportFunction(primal_domain: HilbertSpace)[source]¶
Bases:
NonLinearForm,ABCSupport function of a closed convex set S ⊆ H:
h_S(q) = sup_{x ∈ S} ⟨q, x⟩, q ∈ H
In a Hilbert space, we identify H ≅ H* via the Riesz map, so the functional is defined directly on the primal space H.
- The set S is uniquely recovered as:
S = {x : ⟨q, x⟩ ≤ h_S(q) for all q ∈ H}
- classmethod callable(primal_domain: HilbertSpace, mapping: Callable[[Vector], float], support_point: Callable[[Vector], Vector] | None = None) CallableSupportFunction[source]¶
Construct a support function from a user-supplied callable.
- Parameters:
primal_domain – The Hilbert space H.
mapping – A callable
q -> floatthat evaluates $h(q)$.support_point – An optional callable
q -> Vectorreturning $x^*(q) in argmax_{x in C} langle q, x rangle$. When provided,subgradient(q)delegates to it.
- Returns:
A
CallableSupportFunctioninstance.
- image(operator: LinearOperator) LinearImageSupportFunction[source]¶
Return the support function of the linear image $A(C)$.
For a bounded linear operator $A$ with
A.domain == self.primal_domain, returns the support function of the image set $A(C)$, which lives inA.codomain. Its value is $h_{A(C)}(q) = h_C(A^* q)$.- Parameters:
operator – A bounded linear operator $A: H to K$ with
operator.domainequal toself.primal_domain.- Returns:
A
LinearImageSupportFunctiononoperator.codomain.- Raises:
ValueError – If
operator.domain != self.primal_domain.
- classmethod point(primal_domain: HilbertSpace, point: Vector) PointSupportFunction[source]¶
Construct the support function of the singleton set ${p}$.
For a fixed point $p in H$, the support function is $h(q) = langle q, p rangle$.
- Parameters:
primal_domain – The Hilbert space H containing $p$.
point – The fixed point $p$.
- Returns:
A
PointSupportFunctioninstance.
- property primal_domain: HilbertSpace¶
The Hilbert space H in which the underlying convex set lives.
- scale(alpha: float) ScaledSupportFunction[source]¶
Return the support function of the scaled set $alpha C$.
Scaling satisfies $h_{alpha C}(q) = alpha, h_C(q)$ for $alpha geq 0$.
- Parameters:
alpha – A nonnegative scalar.
- Returns:
A
ScaledSupportFunctionon the same space.- Raises:
ValueError – If
alpha < 0.
- support_point(q: Vector) 'Vector' | None[source]¶
Optional: return x*(q) ∈ argmax_{x∈S} ⟨q, x⟩ if available/computable. Default: not provided (returns None). This is the subgradient of h_S at q.
- translate(point: Vector) MinkowskiSumSupportFunction[source]¶
Return the support function of the translated set $C + p$.
Translation by $p in H$ satisfies $h_{C+p}(q) = h_C(q) + langle q, p rangle$.
- Parameters:
point – The translation vector $p in H$ (same space as
primal_domain).- Returns:
A
MinkowskiSumSupportFunctionon the same space.
- value_and_support_point(q: Vector) tuple[float, Vector | None][source]¶
Return
(h(q), x*(q))sharing intermediate work where possible.For a support function $h_S(q) = sup_{x in S} langle q, x rangle$, the scalar value and the maximiser $x^*(q)$ often share intermediate computations (e.g. a norm or an operator application). This method provides a single entry point so that overriding subclasses can exploit that sharing.
The default implementation simply calls
self(q)andself.support_point(q)separately and is always correct. Concrete subclasses should override this when a fused computation is cheaper.- Parameters:
q – A vector in the primal domain $H$.
- Returns:
A tuple
(value, point)wherevalueis the float $h(q)$, always present;pointis $x^*(q) in argmax_{x in S} langle q, x rangle$ as aVector, orNonewhen a support point is unavailable.
- class pygeoinf.Union(subsets: Iterable[Subset])[source]¶
Bases:
SubsetRepresents the union of multiple subsets: S = S_1 ∪ S_2 …
- property complement: Subset¶
Returns the complement of the union.
Applies De Morgan’s Law: (A ∪ B)^c = A^c ∩ B^c. Returns an Intersection of the complements.
- class pygeoinf.UniversalSet(domain: HilbertSpace | None = None)[source]¶
Bases:
SubsetRepresents the entire domain (Ω).
- pygeoinf.configure_threading(n_threads: int = 1)[source]¶
Sets the maximum number of threads used by underlying linear algebra backends (MKL, OpenBLAS, etc.).
- Parameters:
n_threads – The number of threads to allow. Set to 1 for serial execution (safe for multiprocessing). Set to -1 or None to use all available cores.
- pygeoinf.download_gsn_stations(force: bool = False) None[source]¶
Fetches the Global Seismograph Network (GSN) stations from the IRIS FDSN API and saves them to a local CSV file in the data/ directory.
- pygeoinf.download_usgs_earthquakes(min_magnitude: float = 5.0, start_time: str = None, end_time: str = None, min_depth: float = None, max_depth: float = None, bbox: Tuple[float, float, float, float] = None, limit: int = 2000, force: bool = False, filename: str = 'usgs_events_filtered.csv') None[source]¶
Fetches a filtered catalog of earthquakes from the USGS API and saves it to a CSV in the centralized DATADIR.
- pygeoinf.load_gsn_stations(n_stations: int = None, include_names: bool = False) List[Tuple[float, float]] | List[Tuple[str, float, float]][source]¶
Loads a representative global set of seismic stations from the GSN.
If the internal CSV file is missing, this function will attempt to automatically download it from IRIS into the pygeoinf/data/ directory.
- Parameters:
n_stations – If provided, returns a random subsample of this size. If greater than the total available stations, returns all.
include_names – If True, returns (Name, Latitude, Longitude). If False, returns pure (Latitude, Longitude) tuples.
- Returns:
A list of station tuples in degrees.
- pygeoinf.plot_1d_distributions(posterior_measures: GaussianMeasure | Any | List[GaussianMeasure | Any], /, *, prior_measures: GaussianMeasure | Any | List[GaussianMeasure | Any] | None = None, true_value: float | None = None, show_true_value_in_legend: bool = False, ax: Axes | None = None, xlabel: str = 'Property Value', title: str = 'Prior and Posterior Probability Distributions', prior_labels: str | List[str] | None = None, posterior_labels: str | List[str] | None = None, width_scaling: float = 6.0, legend_position: tuple = (0.95, 0.95), fill_density: bool = False, **kwargs) Axes | Tuple[Axes, Axes][source]¶
Plot 1D probability distributions for prior and posterior measures using dual y-axes.
- Parameters:
posterior_measures – Single measure or list of measures for posterior distributions
prior_measures – Single measure or list of measures for prior distributions (optional)
true_value – True value to mark with a vertical line (optional)
ax – An existing Matplotlib Axes object. If None, plots to the current active axes.
xlabel – Label for x-axis
title – Title for the plot
prior_labels – Manual labels for prior distributions (optional)
posterior_labels – Manual labels for posterior distributions (optional)
width_scaling – Width scaling factor in standard deviations (default: 6.0)
legend_position – Position of legend as (x, y) tuple (default: (0.95, 0.95))
fill_density – Whether to fill the area under the PDF curves (default: False)
**kwargs – Additional kwargs (e.g., figsize) safely ignored or forwarded.
- Returns:
ax1 (if no priors) or (ax1, ax2) if dual axes are used.
- pygeoinf.plot_corner_distributions(posterior_measure: GaussianMeasure, /, *, prior_measure: GaussianMeasure | None = None, true_values: List[float] | ndarray | None = None, show_true_value_in_legend: bool = False, labels: List[str] | None = None, title: str = 'Joint Posterior Distribution', figsize: tuple | None = None, colormap: str = 'Blues', contour_color: str = 'darkblue', parallel: bool = False, n_jobs: int = -1, width_scaling: float = 3.75, legend_position: tuple = (0.9, 0.95), fill_density: bool = False, num_sigmas: int = 3) ndarray[source]¶
Create a professional corner plot for multi-dimensional posterior distributions.
- Parameters:
posterior_measure – Multi-dimensional posterior measure (pygeoinf GaussianMeasure)
prior_measure – Optional prior measure to plot secondary axes showing prior standard deviations.
true_values – True values for each dimension (optional)
labels – Labels for each dimension (optional)
title – Title for the plot
figsize – Figure size tuple (if None, calculated based on dimensions)
colormap – Colormap for 2D plots (used when fill_density=True)
contour_color – Uniform color for the 2D contour lines (used when fill_density=False)
parallel – Compute dense covariance matrix in parallel, default False.
n_jobs – Number of cores to use in parallel calculations, default -1.
width_scaling – Width scaling factor in standard deviations for default boundaries (default: 3.75)
legend_position – Position of legend as (x, y) tuple (default: (0.9, 0.95))
fill_density – Whether to fill the 2D contour background with color. False is recommended for sparse truth values.
num_sigmas – Minimum number of standard deviation contours to draw (dynamically scales up to enclose true values).
- Returns:
An N x N NumPy array of Matplotlib Axes objects.
- Return type:
axes
- pygeoinf.plot_slice(subset: Subset, on_subspace: AffineSubspace, bounds=None, grid_size: int = 200, rtol: float = 1e-06, alpha: float = 0.5, cmap: str = 'Blues', color: str = 'steelblue', show_plot: bool = True, ax=None, backend: str = 'auto') Tuple[Any, Axes | None, ndarray][source]¶
Convenience wrapper: slice a subset along a 1D, 2D, or 3D affine subspace and plot.
Thin wrapper over SubspaceSlicePlotter. See that class for full documentation on the
boundsformat and return-value semantics.- Parameters:
subset – The Subset to visualize (domain must be EuclideanSpace).
on_subspace – A 1D, 2D, or 3D AffineSubspace to slice along.
bounds – Plot bounds — passed directly to SubspaceSlicePlotter.plot().
grid_size – Samples per axis (passed to SubspaceSlicePlotter).
rtol – Oracle tolerance (passed to SubspaceSlicePlotter).
alpha – Fill transparency (passed to SubspaceSlicePlotter).
cmap – Colormap for 2D/3D plots.
color – Color string for 1D plots.
show_plot – Whether to call
plt.show().ax – Optional existing
Axes(orAxes3D) to draw into.backend – Rendering backend —
"auto"(default),"matplotlib", or"plotly"."auto"prefers Plotly for 3D when it is installed and warns then falls back to Matplotlib otherwise; 1D/2D always use Matplotlib.
- Returns:
(fig, ax, payload)— identical toSubspaceSlicePlotter.plot().payload semantics depend on set type and dimension:
Sampled path (non-
PolyhedralSet): boolean membership mask.1D: shape
(grid_size,)2D: shape
(grid_size, grid_size)3D: shape
(grid_size, grid_size, grid_size)—mask[i, j, k]isTruewhen the point at local parameter coordinates(u[i], v[j], w[k])lies inside the subset.
Exact path (
PolyhedralSet): vertex array in parameter coordinates.1D:
np.array([u_lo, u_hi])— interval endpoints2D: shape
(n_vertices, 2)— polygon vertices3D: shape
(n_vertices, 3)— polytope vertices
For 3D subspaces using
backend='matplotlib'(orbackend='auto'when Plotly is not installed),figis amatplotlib.figure.Figureandaxis anAxes3Dinstance. For 3D subspaces usingbackend='plotly'(orbackend='auto'when Plotly is installed),figis aplotly.graph_objects.FigureandaxisNone.- Raises:
TypeError – If
subset.domainis not anEuclideanSpace.ValueError – If bounds format is incompatible with the subspace dimension, or if
grid_size,rtol, oralphaare out of range.
- pygeoinf.sample_earthquakes(n_events: int, min_magnitude: float = 5.0) List[Tuple[float, float, float]][source]¶
Returns a random subsample of real earthquake locations.
If the local cache does not contain enough events to satisfy the request, it automatically fetches a larger catalog from the USGS to rebuild the cache.
- Parameters:
n_events – The exact number of earthquake locations to return.
min_magnitude – The minimum magnitude to use if a new download is required.
- Returns:
(Latitude, Longitude, Depth_in_km).
- Return type:
A list of tuples
- pygeoinf.white_noise_measure(domain: HilbertSpace) GaussianMeasure[source]¶
Creates a formal N(0, I) “white noise” measure on the given domain.
WARNING: Mathematically, the identity operator is not trace-class in infinite dimensions, meaning this does not define a valid Radon measure on the Hilbert space. It is a cylinder measure.
In this library, it is used strictly as a numerical tool to generate isotropic test vectors for randomized algorithms, ensuring that the sampling perfectly respects the domain’s inner product (e.g., mass matrices) without biasing the range approximation.