DualPerspective Python Package
Python interface for DualPerspective.jl, a Julia package for solving Kullback-Leibler regularized least squares problems.
Seeing
juliacall.JuliaError: UndefVarError: reset! not defined? This affects every Julia release up to v0.1.4 and is fixed in v0.1.5. See UPGRADING.md for a workaround that needs no upgrade, and for upgrade instructions.
Installation
pip install DualPerspective
Julia itself is installed automatically on first use, via juliacall.
Versioning
The PyPI package and the Julia package version independently. Each wheel pins one exact
Julia release in juliapkg.json and is tested against it, so PyPI 0.2.0 shipping
DualPerspective.jl 0.1.5 is expected, not a mismatch.
import DualPerspective
DualPerspective.__version__ # the Python package
DualPerspective.version() # the Julia package it pins
Basic usage
import numpy as np
from DualPerspective import DPModel, solve
np.random.seed(42)
n, m = 200, 100 # solution dimension, number of measurements
x0 = np.pi * (tmp := np.random.rand(n)) / np.sum(tmp)
A = np.random.rand(m, n)
b = A @ x0 # measurements
model = DPModel(A, b, lam=1e-4)
x = solve(model)
print(f"sum of solution: {x.sum():.6f} (should be about {np.pi:.6f})")
solve returns a NumPy array. Pass full_output=True for the full result:
result = solve(model, full_output=True)
result.x # primal solution
result.status # 'optimal', 'max_iter', ...
result.iterations
result.optimality # final ‖∇d(y)‖, the quantity the stopping rule tests
result.residual
result.trace # per-iteration history (a list of dicts), when the solver records one
result.to_pandas() # the trace as a DataFrame, if pandas is installed
The model
DPModel(A, b, q=None, C=None, c=None, lam=None)
Minimizes (1/2λ)‖Ax - b‖²_{C⁻¹} + ⟨c, x⟩ + KL(x ‖ q).
| Argument | Shape | Meaning |
|---|---|---|
A |
(m, n) |
Forward operator |
b |
(m,) |
Measurements |
q |
(n,) |
Prior; defaults to uniform |
C |
(m, m) |
Covariance weighting the residual; defaults to the identity |
c |
(n,) |
Linear cost |
lam |
scalar | Regularization parameter (also accepted as λ) |
Cweights the residualb - Ax, so it is(m, m). Releases before 0.2.0 documented it incorrectly as(n, n).
Integer and single-precision arrays are accepted and converted to double precision. All arrays are copied into Julia, so mutating them afterwards does not change the model.
lam and scale are settable properties:
model.lam = 1e-4 # same as regularize(model, 1e-4)
model.scale = 2.0 # same as scale(model, 2.0)
Choosing a solver
solve(model, method="sequential", atol=1e-6, rtol=1e-6, logging=0, full_output=False)
method |
Algorithm |
|---|---|
"sequential" |
Sequential scaling (default) |
"trust-region" |
Trust-region Newton-CG |
"level-set" |
Level-set method |
"adaptive-level-set" |
Adaptive level-set method |
"self-scaled" |
Self-scaled Gauss-Newton, for unknown total mass |
The solver stops when ‖∇d(y)‖ < atol + rtol*‖b‖. Unrecognized keywords are passed straight
through to the Julia solver.
Diagnosing problems
python -m DualPerspective.doctor
Prints the Python, Julia and resolved Julia package versions, the relevant environment variables, and runs a small solve. Include its output in any bug report.
Julia errors surface as DualPerspectiveError, whose message is the first line of the Julia
exception; the full Julia backtrace is on .julia_traceback, and the original exception is
chained as __cause__.
Running on a cluster
- Put the Julia depot on fast local storage. Precompilation is very sensitive to
filesystem latency, and
~/.juliaon NFS is usually slow and quota-limited:export JULIA_DEPOT_PATH=/local/scratch/$USER/julia_depot
- Resolve before going offline. Import the package once on a login node with the same
JULIA_DEPOT_PATHbefore submitting jobs to nodes without network access. - Shared environments.
PYTHON_JULIACALL_PROJECTpoints juliacall at an existing Julia project, which must already have a matching PythonCall.jl. Do not mutate an admin-managed project. - Threads and signals.
PYTHON_JULIACALL_HANDLE_SIGNALS=yesavoids segfaults from Julia's garbage collector in multi-threaded programs, but interferes with Python's own signal handling (including Ctrl-C). It is not set by default; enable it only if you need it.
Local development
To run against a checkout of DualPerspective.jl rather than the pinned release:
export DUALPERSPECTIVE_JL_PATH=/path/to/DualPerspective.jl
Building and publishing
Remove stale artefacts first — twine upload dist/* will otherwise try to re-upload every
old build sitting in dist/:
cd pypi
rm -rf build dist *.egg-info
python -m build
unzip -l dist/*.whl | grep juliapkg.json # the pin must be in the wheel
twine check dist/*
Publish only after the pinned Julia version has been registered in the General registry; otherwise the wheel pins a version that cannot be resolved.
License
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dualperspective-0.2.0.tar.gz.
File metadata
- Download URL: dualperspective-0.2.0.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32908092489abdaa53e57516846e4aca0f2833fc4e2fb1bc89e5e074ef47b03c
|
|
| MD5 |
3fe2f697be3b1f8cf7d7d5d17376e02e
|
|
| BLAKE2b-256 |
120e6f392774e7c9ead8dac24df3ebd3513c62e51f2076c56a941e1f0f256739
|
Provenance
The following attestation bundles were made for dualperspective-0.2.0.tar.gz:
Publisher:
python-publish.yml on MPF-Optimization-Laboratory/DualPerspective.jl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dualperspective-0.2.0.tar.gz -
Subject digest:
32908092489abdaa53e57516846e4aca0f2833fc4e2fb1bc89e5e074ef47b03c - Sigstore transparency entry: 2387659708
- Sigstore integration time:
-
Permalink:
MPF-Optimization-Laboratory/DualPerspective.jl@30b26551a35e1bedf69af08e3976d208a15e88ab -
Branch / Tag:
refs/tags/py-v0.2.0 - Owner: https://github.com/MPF-Optimization-Laboratory
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@30b26551a35e1bedf69af08e3976d208a15e88ab -
Trigger Event:
push
-
Statement type:
File details
Details for the file dualperspective-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dualperspective-0.2.0-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a889b2f8056029b9b01173c7cd41cfd6b21d4f3a0fc764b3a7a1827ad74a711c
|
|
| MD5 |
e0005edd436c189a4aa0a1409282ed3c
|
|
| BLAKE2b-256 |
d3adb86c2010db7315b6ed1cbb0df3fdb3ba64a774cc189d819675b9ee011f61
|
Provenance
The following attestation bundles were made for dualperspective-0.2.0-py3-none-any.whl:
Publisher:
python-publish.yml on MPF-Optimization-Laboratory/DualPerspective.jl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dualperspective-0.2.0-py3-none-any.whl -
Subject digest:
a889b2f8056029b9b01173c7cd41cfd6b21d4f3a0fc764b3a7a1827ad74a711c - Sigstore transparency entry: 2387659718
- Sigstore integration time:
-
Permalink:
MPF-Optimization-Laboratory/DualPerspective.jl@30b26551a35e1bedf69af08e3976d208a15e88ab -
Branch / Tag:
refs/tags/py-v0.2.0 - Owner: https://github.com/MPF-Optimization-Laboratory
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@30b26551a35e1bedf69af08e3976d208a15e88ab -
Trigger Event:
push
-
Statement type: