ncpolopt 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ncpolopt-0.1.0/PKG-INFO +131 -0
- ncpolopt-0.1.0/README.md +91 -0
- ncpolopt-0.1.0/pyproject.toml +108 -0
- ncpolopt-0.1.0/pyproject.toml.orig +82 -0
- ncpolopt-0.1.0/src/ncpolopt/__init__.py +98 -0
- ncpolopt-0.1.0/src/ncpolopt/__main__.py +37 -0
- ncpolopt-0.1.0/src/ncpolopt/_logging.py +62 -0
- ncpolopt-0.1.0/src/ncpolopt/block_structure.py +304 -0
- ncpolopt-0.1.0/src/ncpolopt/chordal.py +256 -0
- ncpolopt-0.1.0/src/ncpolopt/equality_elimination.py +91 -0
- ncpolopt-0.1.0/src/ncpolopt/expressions.py +124 -0
- ncpolopt-0.1.0/src/ncpolopt/hierarchies/__init__.py +18 -0
- ncpolopt-0.1.0/src/ncpolopt/hierarchies/moroder.py +96 -0
- ncpolopt-0.1.0/src/ncpolopt/hierarchies/rdm.py +233 -0
- ncpolopt-0.1.0/src/ncpolopt/hierarchies/steering.py +245 -0
- ncpolopt-0.1.0/src/ncpolopt/moment.py +164 -0
- ncpolopt-0.1.0/src/ncpolopt/monomial_sets.py +103 -0
- ncpolopt-0.1.0/src/ncpolopt/monomials.py +172 -0
- ncpolopt-0.1.0/src/ncpolopt/physics.py +549 -0
- ncpolopt-0.1.0/src/ncpolopt/problem.py +154 -0
- ncpolopt-0.1.0/src/ncpolopt/relaxation.py +855 -0
- ncpolopt-0.1.0/src/ncpolopt/sdp_problem.py +352 -0
- ncpolopt-0.1.0/src/ncpolopt/sdpa_writer.py +187 -0
- ncpolopt-0.1.0/src/ncpolopt/solution.py +356 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/__init__.py +20 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/_common.py +57 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/base.py +103 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/cvxpy_solver.py +177 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/mosek_solver.py +242 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/picos_solver.py +234 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/registry.py +174 -0
- ncpolopt-0.1.0/src/ncpolopt/solvers/sdpa_solver.py +97 -0
- ncpolopt-0.1.0/src/ncpolopt/substitutions.py +481 -0
- ncpolopt-0.1.0/src/ncpolopt/variables.py +188 -0
ncpolopt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ncpolopt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Sparse SDP relaxations of polynomial optimization problems with noncommuting variables (NPA hierarchy)
|
|
5
|
+
Keywords: noncommutative,polynomial optimization,SDP,semidefinite programming,NPA hierarchy,quantum
|
|
6
|
+
Author: ChenXu
|
|
7
|
+
Author-email: ChenXu <chenxuhuang27@gmail.com>
|
|
8
|
+
License-Expression: GPL-3.0-only
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
+
Requires-Dist: numpy>=1.26
|
|
17
|
+
Requires-Dist: scipy>=1.11
|
|
18
|
+
Requires-Dist: sympy>=1.12
|
|
19
|
+
Requires-Dist: cvxpy>=1.5 ; extra == 'all'
|
|
20
|
+
Requires-Dist: mosek>=11 ; extra == 'all'
|
|
21
|
+
Requires-Dist: picos>=2.4 ; extra == 'all'
|
|
22
|
+
Requires-Dist: cvxopt>=1.3 ; extra == 'all'
|
|
23
|
+
Requires-Dist: chompack>=2.3 ; extra == 'all'
|
|
24
|
+
Requires-Dist: chompack>=2.3 ; extra == 'chordal'
|
|
25
|
+
Requires-Dist: cvxopt>=1.3 ; extra == 'chordal'
|
|
26
|
+
Requires-Dist: picos>=2.4 ; extra == 'cvxopt'
|
|
27
|
+
Requires-Dist: cvxopt>=1.3 ; extra == 'cvxopt'
|
|
28
|
+
Requires-Dist: cvxpy>=1.5 ; extra == 'cvxpy'
|
|
29
|
+
Requires-Dist: mosek>=11 ; extra == 'mosek'
|
|
30
|
+
Requires-Python: >=3.13
|
|
31
|
+
Project-URL: Homepage, https://github.com/ChenXu-Huang/ncpolopt
|
|
32
|
+
Project-URL: Repository, https://github.com/ChenXu-Huang/ncpolopt
|
|
33
|
+
Project-URL: Issues, https://github.com/ChenXu-Huang/ncpolopt/issues
|
|
34
|
+
Provides-Extra: all
|
|
35
|
+
Provides-Extra: chordal
|
|
36
|
+
Provides-Extra: cvxopt
|
|
37
|
+
Provides-Extra: cvxpy
|
|
38
|
+
Provides-Extra: mosek
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# ncpolopt
|
|
42
|
+
|
|
43
|
+
Sparse SDP relaxations of polynomial optimization problems with
|
|
44
|
+
noncommuting variables — the [NPA hierarchy](https://arxiv.org/abs/0803.4291)
|
|
45
|
+
and its relatives. `ncpolopt` is a modern rewrite of the GPL-3
|
|
46
|
+
[ncpol2sdpa](https://github.com/peterwittek/ncpol2sdpa) package: the same
|
|
47
|
+
hierarchies and the same four solver backends, behind a fresh, typed API
|
|
48
|
+
built on dataclasses and lazy solver discovery.
|
|
49
|
+
|
|
50
|
+
- **NPA hierarchy** for noncommutative operators, plus the
|
|
51
|
+
[Moroder](https://arxiv.org/abs/1305.2630) (PPT), steering, and RDM
|
|
52
|
+
(reduced density matrix) hierarchies.
|
|
53
|
+
- **Lasserre-style hierarchies** for commuting variables, with an optional
|
|
54
|
+
chordal sparsity extension (SparsePOP-style) that splits the relaxation
|
|
55
|
+
into independent moment blocks per clique.
|
|
56
|
+
- **Four solver backends**: [cvxpy](https://www.cvxpy.org/),
|
|
57
|
+
[MOSEK](https://www.mosek.com/), [PICOS/cvxopt](https://picos-api.gitlab.io/),
|
|
58
|
+
and the external [SDPA](https://sdpa.sourceforge.net/) binary — selected
|
|
59
|
+
by name or auto-detected.
|
|
60
|
+
- **Moment expressions** (`MomentEntry`) instead of a string DSL for
|
|
61
|
+
writing conditions on the moment matrix directly.
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
Requires Python 3.13+. The core package needs only numpy, scipy, and sympy;
|
|
66
|
+
install a solver extra to actually solve:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv pip install ncpolopt[cvxpy] # or: pip install ncpolopt[cvxpy]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Available extras: `cvxpy`, `mosek`, `cvxopt` (PICOS + cvxopt), `chordal`
|
|
73
|
+
(chompack, only needed for the chompack completion method), and `all`.
|
|
74
|
+
With no solver installed the package still imports and builds relaxations;
|
|
75
|
+
only solving raises a `SolverError` telling you which extra to install.
|
|
76
|
+
|
|
77
|
+
## Quickstart
|
|
78
|
+
|
|
79
|
+
A tiny noncommutative problem: two Hermitian operators `x0`, `x1`, minimize
|
|
80
|
+
the anticommutator `x0*x1 + x1*x0` under the constraint `x1 - x1² + ½ ≥ 0`
|
|
81
|
+
and the projection `x0² = x0`:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import ncpolopt as nc
|
|
85
|
+
|
|
86
|
+
X = nc.generate_operators("x", 2, hermitian=True)
|
|
87
|
+
problem = nc.Problem(
|
|
88
|
+
X,
|
|
89
|
+
objective=X[0] * X[1] + X[1] * X[0],
|
|
90
|
+
inequalities=[-X[1] ** 2 + X[1] + 0.5],
|
|
91
|
+
substitutions={X[0] ** 2: X[0]},
|
|
92
|
+
)
|
|
93
|
+
solution = problem.solve(level=2)
|
|
94
|
+
print(solution.primal) # -0.75
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Object model
|
|
98
|
+
|
|
99
|
+
Work flows through three layers, each a frozen dataclass:
|
|
100
|
+
|
|
101
|
+
1. **`Problem`** — the symbolic model: variables (a list of lists for
|
|
102
|
+
multipartite problems), objective, polynomial and moment constraints,
|
|
103
|
+
substitution rules. Reusable; building a relaxation never mutates it.
|
|
104
|
+
2. **`NpaRelaxation`** — the SDP at a hierarchy level, built by
|
|
105
|
+
`problem.relaxation(level)` or subclass hierarchies
|
|
106
|
+
`MoroderHierarchy`, `SteeringHierarchy`, `RdmHierarchy`. The assembled
|
|
107
|
+
SDP data (`relaxation.sdp`) is a frozen blockwise COO representation.
|
|
108
|
+
3. **`Solution`** — the immutable solve result (`primal`, `dual`,
|
|
109
|
+
`status`, `x_mat`, `y_mat`) with extraction helpers:
|
|
110
|
+
`monomial_value()`, `dual_value()`, `dual_block()`,
|
|
111
|
+
`sos_decomposition()`, `solution_ranks()`.
|
|
112
|
+
|
|
113
|
+
## Command line
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
ncpolopt # version, platform, detected solvers
|
|
117
|
+
ncpolopt --version
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
uv sync --group dev
|
|
124
|
+
uv run pytest
|
|
125
|
+
uv run ruff check .
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
GPL-3.0-only. This package is derived from ncpol2sdpa, which is
|
|
131
|
+
Copyright (C) 2012-2016 Peter Wittek and contributors.
|
ncpolopt-0.1.0/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ncpolopt
|
|
2
|
+
|
|
3
|
+
Sparse SDP relaxations of polynomial optimization problems with
|
|
4
|
+
noncommuting variables — the [NPA hierarchy](https://arxiv.org/abs/0803.4291)
|
|
5
|
+
and its relatives. `ncpolopt` is a modern rewrite of the GPL-3
|
|
6
|
+
[ncpol2sdpa](https://github.com/peterwittek/ncpol2sdpa) package: the same
|
|
7
|
+
hierarchies and the same four solver backends, behind a fresh, typed API
|
|
8
|
+
built on dataclasses and lazy solver discovery.
|
|
9
|
+
|
|
10
|
+
- **NPA hierarchy** for noncommutative operators, plus the
|
|
11
|
+
[Moroder](https://arxiv.org/abs/1305.2630) (PPT), steering, and RDM
|
|
12
|
+
(reduced density matrix) hierarchies.
|
|
13
|
+
- **Lasserre-style hierarchies** for commuting variables, with an optional
|
|
14
|
+
chordal sparsity extension (SparsePOP-style) that splits the relaxation
|
|
15
|
+
into independent moment blocks per clique.
|
|
16
|
+
- **Four solver backends**: [cvxpy](https://www.cvxpy.org/),
|
|
17
|
+
[MOSEK](https://www.mosek.com/), [PICOS/cvxopt](https://picos-api.gitlab.io/),
|
|
18
|
+
and the external [SDPA](https://sdpa.sourceforge.net/) binary — selected
|
|
19
|
+
by name or auto-detected.
|
|
20
|
+
- **Moment expressions** (`MomentEntry`) instead of a string DSL for
|
|
21
|
+
writing conditions on the moment matrix directly.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
Requires Python 3.13+. The core package needs only numpy, scipy, and sympy;
|
|
26
|
+
install a solver extra to actually solve:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv pip install ncpolopt[cvxpy] # or: pip install ncpolopt[cvxpy]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Available extras: `cvxpy`, `mosek`, `cvxopt` (PICOS + cvxopt), `chordal`
|
|
33
|
+
(chompack, only needed for the chompack completion method), and `all`.
|
|
34
|
+
With no solver installed the package still imports and builds relaxations;
|
|
35
|
+
only solving raises a `SolverError` telling you which extra to install.
|
|
36
|
+
|
|
37
|
+
## Quickstart
|
|
38
|
+
|
|
39
|
+
A tiny noncommutative problem: two Hermitian operators `x0`, `x1`, minimize
|
|
40
|
+
the anticommutator `x0*x1 + x1*x0` under the constraint `x1 - x1² + ½ ≥ 0`
|
|
41
|
+
and the projection `x0² = x0`:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import ncpolopt as nc
|
|
45
|
+
|
|
46
|
+
X = nc.generate_operators("x", 2, hermitian=True)
|
|
47
|
+
problem = nc.Problem(
|
|
48
|
+
X,
|
|
49
|
+
objective=X[0] * X[1] + X[1] * X[0],
|
|
50
|
+
inequalities=[-X[1] ** 2 + X[1] + 0.5],
|
|
51
|
+
substitutions={X[0] ** 2: X[0]},
|
|
52
|
+
)
|
|
53
|
+
solution = problem.solve(level=2)
|
|
54
|
+
print(solution.primal) # -0.75
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Object model
|
|
58
|
+
|
|
59
|
+
Work flows through three layers, each a frozen dataclass:
|
|
60
|
+
|
|
61
|
+
1. **`Problem`** — the symbolic model: variables (a list of lists for
|
|
62
|
+
multipartite problems), objective, polynomial and moment constraints,
|
|
63
|
+
substitution rules. Reusable; building a relaxation never mutates it.
|
|
64
|
+
2. **`NpaRelaxation`** — the SDP at a hierarchy level, built by
|
|
65
|
+
`problem.relaxation(level)` or subclass hierarchies
|
|
66
|
+
`MoroderHierarchy`, `SteeringHierarchy`, `RdmHierarchy`. The assembled
|
|
67
|
+
SDP data (`relaxation.sdp`) is a frozen blockwise COO representation.
|
|
68
|
+
3. **`Solution`** — the immutable solve result (`primal`, `dual`,
|
|
69
|
+
`status`, `x_mat`, `y_mat`) with extraction helpers:
|
|
70
|
+
`monomial_value()`, `dual_value()`, `dual_block()`,
|
|
71
|
+
`sos_decomposition()`, `solution_ranks()`.
|
|
72
|
+
|
|
73
|
+
## Command line
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
ncpolopt # version, platform, detected solvers
|
|
77
|
+
ncpolopt --version
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv sync --group dev
|
|
84
|
+
uv run pytest
|
|
85
|
+
uv run ruff check .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
GPL-3.0-only. This package is derived from ncpol2sdpa, which is
|
|
91
|
+
Copyright (C) 2012-2016 Peter Wittek and contributors.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ncpolopt"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Sparse SDP relaxations of polynomial optimization problems with noncommuting variables (NPA hierarchy)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
license = "GPL-3.0-only"
|
|
8
|
+
keywords = [
|
|
9
|
+
"noncommutative",
|
|
10
|
+
"polynomial optimization",
|
|
11
|
+
"SDP",
|
|
12
|
+
"semidefinite programming",
|
|
13
|
+
"NPA hierarchy",
|
|
14
|
+
"quantum",
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"numpy>=1.26",
|
|
27
|
+
"scipy>=1.11",
|
|
28
|
+
"sympy>=1.12",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[[project.authors]]
|
|
32
|
+
name = "ChenXu"
|
|
33
|
+
email = "chenxuhuang27@gmail.com"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/ChenXu-Huang/ncpolopt"
|
|
37
|
+
Repository = "https://github.com/ChenXu-Huang/ncpolopt"
|
|
38
|
+
Issues = "https://github.com/ChenXu-Huang/ncpolopt/issues"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
cvxpy = ["cvxpy>=1.5"]
|
|
42
|
+
mosek = ["mosek>=11"]
|
|
43
|
+
cvxopt = [
|
|
44
|
+
"picos>=2.4",
|
|
45
|
+
"cvxopt>=1.3",
|
|
46
|
+
]
|
|
47
|
+
chordal = [
|
|
48
|
+
"chompack>=2.3",
|
|
49
|
+
"cvxopt>=1.3",
|
|
50
|
+
]
|
|
51
|
+
all = [
|
|
52
|
+
"cvxpy>=1.5",
|
|
53
|
+
"mosek>=11",
|
|
54
|
+
"picos>=2.4",
|
|
55
|
+
"cvxopt>=1.3",
|
|
56
|
+
"chompack>=2.3",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[project.scripts]
|
|
60
|
+
ncpolopt = "ncpolopt.__main__:main"
|
|
61
|
+
|
|
62
|
+
[build-system]
|
|
63
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
64
|
+
build-backend = "uv_build"
|
|
65
|
+
|
|
66
|
+
[dependency-groups]
|
|
67
|
+
dev = [
|
|
68
|
+
"pytest>=8.3",
|
|
69
|
+
"pytest-cov>=5.0",
|
|
70
|
+
"ruff>=0.6",
|
|
71
|
+
"cvxpy>=1.5",
|
|
72
|
+
"mosek>=11",
|
|
73
|
+
"picos>=2.4",
|
|
74
|
+
"cvxopt>=1.3",
|
|
75
|
+
"chompack>=2.3",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[tool.uv]
|
|
79
|
+
package = true
|
|
80
|
+
|
|
81
|
+
[tool.ruff]
|
|
82
|
+
target-version = "py313"
|
|
83
|
+
line-length = 88
|
|
84
|
+
src = [
|
|
85
|
+
"src",
|
|
86
|
+
"tests",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[tool.ruff.lint]
|
|
90
|
+
select = [
|
|
91
|
+
"E",
|
|
92
|
+
"F",
|
|
93
|
+
"W",
|
|
94
|
+
"I",
|
|
95
|
+
"UP",
|
|
96
|
+
"B",
|
|
97
|
+
"SIM",
|
|
98
|
+
"C4",
|
|
99
|
+
"RUF",
|
|
100
|
+
]
|
|
101
|
+
ignore = ["E501"]
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint.per-file-ignores]
|
|
104
|
+
"tests/*" = ["S101"]
|
|
105
|
+
|
|
106
|
+
[tool.pytest.ini_options]
|
|
107
|
+
testpaths = ["tests"]
|
|
108
|
+
addopts = "-ra"
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ncpolopt"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Sparse SDP relaxations of polynomial optimization problems with noncommuting variables (NPA hierarchy)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
license = "GPL-3.0-only"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "ChenXu", email = "chenxuhuang27@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
keywords = [
|
|
12
|
+
"noncommutative",
|
|
13
|
+
"polynomial optimization",
|
|
14
|
+
"SDP",
|
|
15
|
+
"semidefinite programming",
|
|
16
|
+
"NPA hierarchy",
|
|
17
|
+
"quantum",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"numpy>=1.26",
|
|
30
|
+
"scipy>=1.11",
|
|
31
|
+
"sympy>=1.12",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/ChenXu-Huang/ncpolopt"
|
|
36
|
+
Repository = "https://github.com/ChenXu-Huang/ncpolopt"
|
|
37
|
+
Issues = "https://github.com/ChenXu-Huang/ncpolopt/issues"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
cvxpy = ["cvxpy>=1.5"]
|
|
41
|
+
mosek = ["mosek>=11"]
|
|
42
|
+
cvxopt = ["picos>=2.4", "cvxopt>=1.3"]
|
|
43
|
+
chordal = ["chompack>=2.3", "cvxopt>=1.3"]
|
|
44
|
+
all = ["cvxpy>=1.5", "mosek>=11", "picos>=2.4", "cvxopt>=1.3", "chompack>=2.3"]
|
|
45
|
+
|
|
46
|
+
[project.scripts]
|
|
47
|
+
ncpolopt = "ncpolopt.__main__:main"
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
51
|
+
build-backend = "uv_build"
|
|
52
|
+
|
|
53
|
+
[dependency-groups]
|
|
54
|
+
dev = [
|
|
55
|
+
"pytest>=8.3",
|
|
56
|
+
"pytest-cov>=5.0",
|
|
57
|
+
"ruff>=0.6",
|
|
58
|
+
"cvxpy>=1.5",
|
|
59
|
+
"mosek>=11",
|
|
60
|
+
"picos>=2.4",
|
|
61
|
+
"cvxopt>=1.3",
|
|
62
|
+
"chompack>=2.3",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[tool.uv]
|
|
66
|
+
package = true
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
target-version = "py313"
|
|
70
|
+
line-length = 88
|
|
71
|
+
src = ["src", "tests"]
|
|
72
|
+
|
|
73
|
+
[tool.ruff.lint]
|
|
74
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM", "C4", "RUF"]
|
|
75
|
+
ignore = ["E501"]
|
|
76
|
+
|
|
77
|
+
[tool.ruff.lint.per-file-ignores]
|
|
78
|
+
"tests/*" = ["S101"]
|
|
79
|
+
|
|
80
|
+
[tool.pytest.ini_options]
|
|
81
|
+
testpaths = ["tests"]
|
|
82
|
+
addopts = "-ra"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""ncpolopt: sparse SDP relaxations of polynomial optimization problems.
|
|
2
|
+
|
|
3
|
+
Builds semidefinite programming (SDP) relaxations -- the NPA hierarchy
|
|
4
|
+
for noncommuting operators, the Lasserre hierarchy for commuting
|
|
5
|
+
variables -- and solves them with pluggable backends (cvxpy, MOSEK,
|
|
6
|
+
cvxopt, SDPA).
|
|
7
|
+
|
|
8
|
+
The package models an optimization problem as a :class:`Problem` of
|
|
9
|
+
operators or variables, adds an objective and constraints, then builds a
|
|
10
|
+
:class:`~ncpolopt.relaxation.NpaRelaxation` at a chosen hierarchy level
|
|
11
|
+
and solves it to obtain an immutable :class:`~ncpolopt.solution.Solution`.
|
|
12
|
+
|
|
13
|
+
Quickstart (a small noncommutative problem, see the README for details)::
|
|
14
|
+
|
|
15
|
+
import ncpolopt as nc
|
|
16
|
+
|
|
17
|
+
X = nc.generate_operators("x", 2, hermitian=True)
|
|
18
|
+
problem = nc.Problem(
|
|
19
|
+
X,
|
|
20
|
+
objective=X[0] * X[1] + X[1] * X[0],
|
|
21
|
+
inequalities=[-X[1] ** 2 + X[1] + 0.5],
|
|
22
|
+
substitutions={X[0] ** 2: X[0]},
|
|
23
|
+
)
|
|
24
|
+
solution = problem.solve(level=2)
|
|
25
|
+
print(solution.primal) # -0.75
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
31
|
+
|
|
32
|
+
from ._logging import setup_logging
|
|
33
|
+
from .chordal import find_clique_index, find_variable_cliques, sliding_cliques
|
|
34
|
+
from .expressions import flatten
|
|
35
|
+
from .hierarchies import MoroderHierarchy, RdmHierarchy, SteeringHierarchy
|
|
36
|
+
from .moment import MomentEntry, MomentExpr
|
|
37
|
+
from .monomials import get_all_monomials, get_monomials
|
|
38
|
+
from .physics import (
|
|
39
|
+
Probability,
|
|
40
|
+
bosonic_constraints,
|
|
41
|
+
correlator,
|
|
42
|
+
define_objective_with_I,
|
|
43
|
+
fermionic_constraints,
|
|
44
|
+
generate_measurements,
|
|
45
|
+
get_neighbors,
|
|
46
|
+
get_next_neighbors,
|
|
47
|
+
maximum_violation,
|
|
48
|
+
pauli_constraints,
|
|
49
|
+
projective_measurement_constraints,
|
|
50
|
+
)
|
|
51
|
+
from .problem import Problem
|
|
52
|
+
from .relaxation import NpaRelaxation
|
|
53
|
+
from .sdpa_writer import read_sdpa_out, write_dat_s
|
|
54
|
+
from .solution import Solution
|
|
55
|
+
from .solvers.base import SolverKind, SolverSettings
|
|
56
|
+
from .variables import generate_operators, generate_variables, get_support
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
__version__ = version("ncpolopt")
|
|
60
|
+
except PackageNotFoundError: # pragma: no cover - editable installs always provide it
|
|
61
|
+
__version__ = "0.0.0"
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"MomentEntry",
|
|
65
|
+
"MomentExpr",
|
|
66
|
+
"MoroderHierarchy",
|
|
67
|
+
"NpaRelaxation",
|
|
68
|
+
"Probability",
|
|
69
|
+
"Problem",
|
|
70
|
+
"RdmHierarchy",
|
|
71
|
+
"Solution",
|
|
72
|
+
"SolverKind",
|
|
73
|
+
"SolverSettings",
|
|
74
|
+
"SteeringHierarchy",
|
|
75
|
+
"__version__",
|
|
76
|
+
"bosonic_constraints",
|
|
77
|
+
"correlator",
|
|
78
|
+
"define_objective_with_I",
|
|
79
|
+
"fermionic_constraints",
|
|
80
|
+
"find_clique_index",
|
|
81
|
+
"find_variable_cliques",
|
|
82
|
+
"flatten",
|
|
83
|
+
"generate_measurements",
|
|
84
|
+
"generate_operators",
|
|
85
|
+
"generate_variables",
|
|
86
|
+
"get_all_monomials",
|
|
87
|
+
"get_monomials",
|
|
88
|
+
"get_neighbors",
|
|
89
|
+
"get_next_neighbors",
|
|
90
|
+
"get_support",
|
|
91
|
+
"maximum_violation",
|
|
92
|
+
"pauli_constraints",
|
|
93
|
+
"projective_measurement_constraints",
|
|
94
|
+
"read_sdpa_out",
|
|
95
|
+
"setup_logging",
|
|
96
|
+
"sliding_cliques",
|
|
97
|
+
"write_dat_s",
|
|
98
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Command-line entry point for ncpolopt.
|
|
2
|
+
|
|
3
|
+
Prints the package version, the platform it runs on, and the SDP solvers
|
|
4
|
+
that are currently usable. The actual problem building happens through the
|
|
5
|
+
Python API; the CLI exists so ``pip install ncpolopt`` provides a useful
|
|
6
|
+
``ncpolopt`` command out of the box, and ``python -m ncpolopt`` works too.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import platform
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from . import __version__
|
|
16
|
+
from ._logging import setup_logging
|
|
17
|
+
from .solvers.registry import available_solvers
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main() -> None:
|
|
21
|
+
"""Run the CLI: report version, platform and available solvers."""
|
|
22
|
+
parser = argparse.ArgumentParser(prog="ncpolopt", description=__doc__)
|
|
23
|
+
parser.add_argument("--version", action="version", version=__version__)
|
|
24
|
+
args = parser.parse_args() # noqa: F841 - kept for future subcommands
|
|
25
|
+
setup_logging()
|
|
26
|
+
print(f"ncpolopt {__version__}")
|
|
27
|
+
print(f"Python {platform.python_version()} on {platform.platform()}")
|
|
28
|
+
solvers = available_solvers()
|
|
29
|
+
if solvers:
|
|
30
|
+
print("Available solvers: " + ", ".join(s.name for s in solvers))
|
|
31
|
+
else:
|
|
32
|
+
print("No SDP solver found. Install one, e.g. `pip install ncpolopt[cvxpy]`.")
|
|
33
|
+
sys.exit(0)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__":
|
|
37
|
+
main()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Logging helpers shared by all ncpolopt modules.
|
|
2
|
+
|
|
3
|
+
The package never prints to stdout directly; every module obtains a named
|
|
4
|
+
logger through :func:`module_logger` and exposes a user-facing ``verbose``
|
|
5
|
+
level that maps to standard logging severities.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
_LOG_LEVELS: dict[int, int] = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def module_logger(name: str) -> logging.Logger:
|
|
16
|
+
"""Return the logger for a module, quiet by default.
|
|
17
|
+
|
|
18
|
+
The returned logger inherits the root handler configuration; call
|
|
19
|
+
:func:`setup_logging` once from an entry point to enable output.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
name: The ``__name__`` of the calling module.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A logger that only emits warnings unless the package is configured
|
|
26
|
+
for verbose output.
|
|
27
|
+
"""
|
|
28
|
+
return logging.getLogger(name)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def verbosity_to_level(verbose: int) -> int:
|
|
32
|
+
"""Map the package's ``verbose`` integer to a logging severity.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
verbose: 0 (warnings only), 1 (info) or 2 (debug). Higher values
|
|
36
|
+
are clamped to debug.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The matching ``logging`` level constant.
|
|
40
|
+
"""
|
|
41
|
+
return _LOG_LEVELS.get(verbose, logging.DEBUG)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def setup_logging(level: int = logging.INFO) -> None:
|
|
45
|
+
"""Configure the root logger with a console handler.
|
|
46
|
+
|
|
47
|
+
Idempotent: calling it repeatedly does not stack duplicate handlers.
|
|
48
|
+
The handler carries the ``"ncpolopt"`` name so tests (and the function
|
|
49
|
+
itself) can recognize and detach it.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
level: The logging severity to emit, e.g. ``logging.INFO``.
|
|
53
|
+
"""
|
|
54
|
+
root = logging.getLogger()
|
|
55
|
+
root.setLevel(level)
|
|
56
|
+
for handler in root.handlers:
|
|
57
|
+
if getattr(handler, "name", None) == "ncpolopt":
|
|
58
|
+
return
|
|
59
|
+
handler = logging.StreamHandler()
|
|
60
|
+
handler.name = "ncpolopt"
|
|
61
|
+
handler.setFormatter(logging.Formatter("%(levelname)s:%(name)s: %(message)s"))
|
|
62
|
+
root.addHandler(handler)
|