Solve for
| Index | ||||
|---|---|---|---|---|
| What does it number? | shot | photon energy bin | observed property | interested property |
| Example 0 | shot | photon energy bin | kinetic energy | kinetic energy |
| Example 1 | shot | photon energy bin | projected momentum | coefficient on a basis function |
G is an optional linear operator from a function of the interested property (discretized by index G=None, G accommodates a linear operation that's not identity mapping, the two linear inversions are solved in a single step.
With mode='raw', pass in matrix mode='contracted', pass in matrix loadG.
The key advantages of this package are
- Efficient optimization: Contraction over shots is decoupled from optimization. It is recommended to input precontracted results when instantiating, or to save the caches using method
save_prectrof a solver created with raw inputs. Once instantiated, the precontracted results are cached to be reused every time solving with a different hyperparameter. Seespook.contraction_utils.adaptive_contraction. - Support dimension reduction on the dependent variable B, through basis functions in G. In that case, it is also recommended to contract (B,G) over the dependent variable space (index q) prior to instantiating a spook solver.
- Support multiple combinations of regularizations. See Solvers .
- Support time-dependent measurement (Beta): when each entry in the raw input A is a pair of (photon spectrum, delay bin), index w is the flattened axis of (
$\omega, \tau$ ). In this case, the third smoothness hyperparameter is for the delay axis.
At the very bottom level, this package depends on either OSQP to solve a quadratic programming or LAPACK gesv through numpy.linalg.solve .
The stable version is on PyPI. Unfortunately in a different name.
pip install FDGIDifferent combinations of regularizations can lead to different forms of objective function. Solvers in package always formalize the specific problem into either a Quadratic Programming or a linear equation. Examples can be found in unit tests
| Nonnegativity | Sparsity | Smoothness | Solver | Notes |
|---|---|---|---|---|
| True | L1 | Quadratic | SpookPosL1 |
This solver can serve tasks like in Li et al |
| True | L2 squared | Quadratic | SpookPosL2 |
|
| False | L2 squared | Quadratic | SpookLinSolve |
This solver is so far the work-horse for SpookVMI |
| False | L1 | Quadratic | SpookL1 |
A family tree of solvers is in docs/figs/famtree.svg.
For cases where it can be formalized into a Quadratic Programming , OSQP is the weight-lifter. The root numerical method is the alternating direction method of multipliers (ADMM). Looking into the solver settings of OSQP is always encouraged, but the default settings usually work fine for spook . If one needs to pass in settings, use spk._prob.update_settings(**osqp_kwargs) on your solver instance spk.
A rare case that it can be formalized into a linear equation is the third line in the table above: no nonnegativity constraint, and the sparsity is L2 norm squared. This is implemented in SpookLinSolve , which calls numpy.linalg.solve or scipy.sparse.linalg.spsolve .
Common regularizations are the following three types, all of which optional, depending on what a prior knowledge one wants to enforce on the problem solving.
- Nonnegativity: To constrain
$X\geq 0$ everywhere - Sparsity: To penalize on
$|X|_1$ or$|X|_2$ - Smoothness: To penalize on roughness of X , along the two dimensions indexed by
$w$ and$b$ independently. For the dimension indexed by$w$ , the form is fixed to the laplacian-square$|(L\otimes I) X|^2_2$ where$L$ is the laplacian. Roughness along the second dimension of X is customizable with input parameterBsmoother, which by default is laplacian squared too.
Sparsity and Smoothness are enforced through penalties in the total obejctive function, and the penalties are weighted by hyperparameters lsparse and lsmooth. lsmooth is a 2-tuple that weight roughness penalty along the two axes of X respectively. The hyperparameters can be passed in during instantiation and also updated afterwards. It is recommended to call method getXopt with the hyperparameter(s) to be updated, because it will update, solve, and return the optimal X in one step. Calling solve with the hyperparameter(s) to be updated and then calling getXopt() without input is effectively the same, and the problem will be solved once as long as there is no update.
| Term | Method | Notes |
|---|---|---|
residueL2 |
For full docstring, check help(spk.residueL2), where spk is a solver instance. |
|
smoothness |
By default, dim. For full docstring, check help(spk.smoothness). |
|
|
|
sparsity |
Depends on solver class. |
- Method
residueL2is based on functionutils.calcL2fromContracted. This function evaluates the residual term from the precontracted results. Also seeXValidation.calc_residualdefined inxval.py. - Function
utils.calcL2fromContractedis also used in the cross-validation classXValidationto evaluate the residual on validation sets. Seexval.pyfor more details.
The entries in
where AGscale. To normalize or not is controlled by parameter normalize in creating a solver.
By default normalize=True, i.e. self._AtA =$A^TA/s_a^2$, self._GtG =$G^TG/s_g^2$, and self._Bcontracted = self.res is scaled as getXopt method returns the unscaled result of normalize='inplace' in creating a solver.
With this normalization convention, the hyperparmeters whose associated regularization function is not quadratic in
Please cite Wang et al 2023 when using this package in your publishable work. If SpookPosL1, SpookPosL2 or SpookL1 is used, we also strongly recommend to cite the original OSQP paper as suggested here.
unittest/testPosL1.pyis a good example to play withSpookPosL1.unittest/testL1L2.ipynbincludes good examples to play withSpookPosL1,SpookPosL2, andSpookL1.unittest/test_resid_reg_eval.pyshowcases how to evaluate the residual and regularization terms of the objective function.
pip installation should manage the dependencies automatically. If not, check requirements.txt .
This work was supported by the U.S. Department of Energy (DOE), Office of Science, Office of Basic Energy Sciences (BES), Chemical Sciences, Geosciences, and Biosciences Division (CSGB).
Full documentation is here. Alternatively, clone this repo, switch to gh-pages, and open docs/index.html in a browser.