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.
Files changed (34) hide show
  1. ncpolopt-0.1.0/PKG-INFO +131 -0
  2. ncpolopt-0.1.0/README.md +91 -0
  3. ncpolopt-0.1.0/pyproject.toml +108 -0
  4. ncpolopt-0.1.0/pyproject.toml.orig +82 -0
  5. ncpolopt-0.1.0/src/ncpolopt/__init__.py +98 -0
  6. ncpolopt-0.1.0/src/ncpolopt/__main__.py +37 -0
  7. ncpolopt-0.1.0/src/ncpolopt/_logging.py +62 -0
  8. ncpolopt-0.1.0/src/ncpolopt/block_structure.py +304 -0
  9. ncpolopt-0.1.0/src/ncpolopt/chordal.py +256 -0
  10. ncpolopt-0.1.0/src/ncpolopt/equality_elimination.py +91 -0
  11. ncpolopt-0.1.0/src/ncpolopt/expressions.py +124 -0
  12. ncpolopt-0.1.0/src/ncpolopt/hierarchies/__init__.py +18 -0
  13. ncpolopt-0.1.0/src/ncpolopt/hierarchies/moroder.py +96 -0
  14. ncpolopt-0.1.0/src/ncpolopt/hierarchies/rdm.py +233 -0
  15. ncpolopt-0.1.0/src/ncpolopt/hierarchies/steering.py +245 -0
  16. ncpolopt-0.1.0/src/ncpolopt/moment.py +164 -0
  17. ncpolopt-0.1.0/src/ncpolopt/monomial_sets.py +103 -0
  18. ncpolopt-0.1.0/src/ncpolopt/monomials.py +172 -0
  19. ncpolopt-0.1.0/src/ncpolopt/physics.py +549 -0
  20. ncpolopt-0.1.0/src/ncpolopt/problem.py +154 -0
  21. ncpolopt-0.1.0/src/ncpolopt/relaxation.py +855 -0
  22. ncpolopt-0.1.0/src/ncpolopt/sdp_problem.py +352 -0
  23. ncpolopt-0.1.0/src/ncpolopt/sdpa_writer.py +187 -0
  24. ncpolopt-0.1.0/src/ncpolopt/solution.py +356 -0
  25. ncpolopt-0.1.0/src/ncpolopt/solvers/__init__.py +20 -0
  26. ncpolopt-0.1.0/src/ncpolopt/solvers/_common.py +57 -0
  27. ncpolopt-0.1.0/src/ncpolopt/solvers/base.py +103 -0
  28. ncpolopt-0.1.0/src/ncpolopt/solvers/cvxpy_solver.py +177 -0
  29. ncpolopt-0.1.0/src/ncpolopt/solvers/mosek_solver.py +242 -0
  30. ncpolopt-0.1.0/src/ncpolopt/solvers/picos_solver.py +234 -0
  31. ncpolopt-0.1.0/src/ncpolopt/solvers/registry.py +174 -0
  32. ncpolopt-0.1.0/src/ncpolopt/solvers/sdpa_solver.py +97 -0
  33. ncpolopt-0.1.0/src/ncpolopt/substitutions.py +481 -0
  34. ncpolopt-0.1.0/src/ncpolopt/variables.py +188 -0
@@ -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.
@@ -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)