eqc-models 0.14.5__tar.gz → 0.15.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.
- {eqc_models-0.14.5 → eqc_models-0.15.0}/PKG-INFO +1 -1
- eqc_models-0.15.0/eqc_models/algorithms/__init__.py +12 -0
- eqc_models-0.15.0/eqc_models/algorithms/alm.py +464 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/shortestpath.py +20 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/solvers/__init__.py +2 -2
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models.egg-info/PKG-INFO +1 -1
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models.egg-info/SOURCES.txt +3 -0
- eqc_models-0.15.0/scripts/ALM_pipeline.ipynb +418 -0
- eqc_models-0.15.0/test/testalm.py +393 -0
- eqc_models-0.14.5/eqc_models/algorithms/__init__.py +0 -4
- {eqc_models-0.14.5 → eqc_models-0.15.0}/.gitignore +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/.gitlab-ci.yml +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/LICENSE.txt +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/MANIFEST.in +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/README.md +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/compile_extensions.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/Makefile +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/basic.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/css/badge_only.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/css/theme.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/custom.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/file.png +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/minus.png +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/plus.png +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/pygments.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/build/html/_static/white_logo.png +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/make.bat +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/_static/custom.css +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/_static/white_logo.png +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/conf.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/dependencies.rst +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/eqc_models.rst +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/index.rst +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/modules.rst +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/docs/source/usage.rst +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/algorithms/base.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/algorithms/penaltymultiplier.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/allocation/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/allocation/allocation.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/allocation/portbase.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/allocation/portmomentum.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/assignment/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/assignment/qap.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/assignment/resource.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/assignment/setpartition.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/base.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/binaries.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/constraints.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/operators.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/polyeval.pyx +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/polynomial.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/quadratic.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/base/results.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/combinatorics/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/combinatorics/setcover.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/combinatorics/setpartition.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/decoding.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/base.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/hypergraph.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/maxcut.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/maxkcut.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/partition.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/graph/rcshortestpath.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/classifierbase.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/classifierqboost.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/classifierqsvm.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/clusteringbase.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/cvqboost_hamiltonian.pyx +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/cvqboost_hamiltonian_c_func.c +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/cvqboost_hamiltonian_c_func.h +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/decomposition.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/forecast.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/forecastbase.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/regressor.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/regressorbase.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/ml/reservoir.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/process/base.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/process/mpc.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/sequence/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/sequence/tsp.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/solvers/eqcdirect.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/solvers/mip.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/solvers/qciclient.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/solvers/responselog.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/utilities/__init__.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/utilities/fileio.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/utilities/general.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/utilities/polynomial.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models/utilities/qplib.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models.egg-info/dependency_links.txt +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models.egg-info/requires.txt +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/eqc_models.egg-info/top_level.txt +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/pyproject.toml +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/binary_job_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/binary_w_continuous_solver_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/c6h6_graph_clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/continuous_job_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/convert_to_json_problem.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/crew_assignment_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/graph_clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/graph_partitioning.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/hamiltonian_to_polynomial.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/hypergraph.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/integer_job_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/karate_graph_clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/lin_reg_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/mackey_glass_cell_production_series.csv +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/mip_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/pca_iris_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/port_opt_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qboost_iris_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qboost_iris_dirac3_weak_cls.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qplib_benchmark_config.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qplib_reader.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qplib_runner.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qsvm_dual_iris_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/qsvm_iris_dirac3.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/reservoir_forecast.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/results_example.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/rundoctests.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/test_shortestpath.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/scripts/utils.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/setup.cfg +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/doctest_base.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testallocationmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testconstraint.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testcvqboost.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testeqcdirectsolver.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testgraphpartitionmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testhypergraphmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testmaxcutmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testpolynomialmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testqapmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testqciclientsolver.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testquadraticmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testsetcovermodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testsetpartitionmodel.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testshortestpath.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test/testtsp.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/README.txt +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/run_tests.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/c6h6_graph_clustering/c6h6_graph_clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/clustering/clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/clustering/data/X.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/cvqboost_iris/cvqboost_iris.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/cvqboost_iris/data/X_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/cvqboost_iris/data/X_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/cvqboost_iris/data/y_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/cvqboost_iris/data/y_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/karate_graph_clustering/karate_graph_clustering.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/pca_iris/pca_iris.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1MJC/data/C_1MJC.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1MJC/data/J_1MJC.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1MJC/protein_design_1MJC.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1NXB/data/C_1NXB.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1NXB/data/J_1NXB.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1NXB/protein_design_1NXB.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1POH/data/C_1POH.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1POH/data/J_1POH.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/protein_design_1POH/protein_design_1POH.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_dual_iris/data/X_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_dual_iris/data/X_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_dual_iris/data/y_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_dual_iris/data/y_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_dual_iris/qsvm_dual_iris.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_primal_iris/data/X_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_primal_iris/data/X_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_primal_iris/data/y_test.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_primal_iris/data/y_train.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/qsvm_primal_iris/qsvm_primal_iris.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_100/data/C_8000000_100.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_100/data/J_8000000_100.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_100/synthetic_cls_100.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_300/data/C_8000000_300.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_300/data/J_8000000_300.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_300/synthetic_cls_300.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_500/data/C_8000000_500.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_500/data/J_8000000_500.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_500/synthetic_cls_500.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_700/data/C_8000000_700.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_700/data/J_8000000_700.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_700/synthetic_cls_700.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_900/data/C_8000000_900.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_900/data/J_8000000_900.npy +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_cases/synthetic_cls_900/synthetic_cls_900.py +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_suite_config.json +0 -0
- {eqc_models-0.14.5 → eqc_models-0.15.0}/test_suite/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eqc-models
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Optimization and ML modeling package targeting EQC devices
|
|
5
5
|
Author-email: "Quantum Computing Inc." <support@quantumcomputinginc.com>
|
|
6
6
|
Project-URL: Homepage, https://quantumcomputinginc.com
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2024.
|
|
2
|
+
from .penaltymultiplier import PenaltyMultiplierAlgorithm
|
|
3
|
+
from .alm import (
|
|
4
|
+
ALMAlgorithm,
|
|
5
|
+
ConstraintRegistry,
|
|
6
|
+
ALMConfig,
|
|
7
|
+
ALMConstraint,
|
|
8
|
+
ALMBlock
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = ["PenaltyMultiplierAlgorithm", "ALMAlgorithm", "ConstraintRegistry",
|
|
12
|
+
"ALMConfig", "ALMConstraint", "ALMBlock",]
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
# (C) Quantum Computing Inc., 2025.
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Callable, Dict, List, Tuple, Optional, Sequence, Union
|
|
4
|
+
import numpy as np
|
|
5
|
+
from eqc_models.base.polynomial import PolynomialModel
|
|
6
|
+
|
|
7
|
+
Array = np.ndarray
|
|
8
|
+
PolyTerm = Tuple[Tuple[int, ...], float]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class ALMConstraint:
|
|
13
|
+
"""One constraint family; fun returns a vector; jac returns its Jacobian."""
|
|
14
|
+
kind: str # "eq" or "ineq"
|
|
15
|
+
fun: Callable[[Array], Array] # h(x) or g(x)
|
|
16
|
+
jac: Optional[Callable[[Array], Array]] = None
|
|
17
|
+
name: str = ""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ALMBlock:
|
|
22
|
+
"""Lifted discrete variable block (optional)."""
|
|
23
|
+
idx: Sequence[int] # indices of block in the full x
|
|
24
|
+
levels: Array # (k,) level values (b_i)
|
|
25
|
+
enforce_sum_to_one: bool = True # register as equality via helper
|
|
26
|
+
enforce_one_hot: bool = True # ALM linearization with M = 11^T - I
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class ALMConfig:
|
|
31
|
+
# penalties
|
|
32
|
+
rho_h: float = 50.0 # equalities
|
|
33
|
+
rho_g: float = 50.0 # inequalities / one-hot
|
|
34
|
+
rho_min: float = 1e-3
|
|
35
|
+
rho_max: float = 1e3
|
|
36
|
+
# adaptation toggles
|
|
37
|
+
adapt: bool = True
|
|
38
|
+
tau_up_h: float = 0.90
|
|
39
|
+
tau_down_h: float = 0.50
|
|
40
|
+
tau_up_g: float = 0.90
|
|
41
|
+
tau_down_g: float = 0.50
|
|
42
|
+
gamma_up: float = 2.0
|
|
43
|
+
gamma_down: float = 1.0
|
|
44
|
+
# tolerances & loop
|
|
45
|
+
tol_h: float = 1e-6
|
|
46
|
+
tol_g: float = 1e-6
|
|
47
|
+
max_outer: int = 100
|
|
48
|
+
# stagnation safety net
|
|
49
|
+
use_stagnation_bump: bool = True
|
|
50
|
+
patience_h: int = 10
|
|
51
|
+
patience_g: int = 10
|
|
52
|
+
stagnation_factor: float = 1e-3
|
|
53
|
+
# smoothing (optional)
|
|
54
|
+
ema_alpha: float = 0.3
|
|
55
|
+
# finite diff (only used if jac=None)
|
|
56
|
+
fd_eps: float = 1e-6
|
|
57
|
+
# activation threshold for projected ALM
|
|
58
|
+
act_tol: float = 1e-10
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ConstraintRegistry:
|
|
62
|
+
"""
|
|
63
|
+
Holds constraints and block metadata; keeps ALMAlgorithm stateless. Register constraints and
|
|
64
|
+
(optional) lifted-discrete blocks here.
|
|
65
|
+
"""
|
|
66
|
+
def __init__(self):
|
|
67
|
+
self.constraints: List[ALMConstraint] = []
|
|
68
|
+
self.blocks: List[ALMBlock] = []
|
|
69
|
+
|
|
70
|
+
def add_equality(self, fun, jac=None, name=""):
|
|
71
|
+
self.constraints.append(ALMConstraint("eq", fun, jac, name))
|
|
72
|
+
|
|
73
|
+
def add_inequality(self, fun, jac=None, name=""):
|
|
74
|
+
self.constraints.append(ALMConstraint("ineq", fun, jac, name))
|
|
75
|
+
|
|
76
|
+
def add_block(self, idx: Sequence[int], levels: Array, sum_to_one=True, one_hot=True):
|
|
77
|
+
self.blocks.append(ALMBlock(list(idx), np.asarray(levels, float), sum_to_one, one_hot))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class ALMAlgorithm:
|
|
81
|
+
"""Stateless ALM outer loop. Call `run(model, registry, core, cfg, **core_kwargs)`."""
|
|
82
|
+
|
|
83
|
+
# ---- helpers (static) ----
|
|
84
|
+
@staticmethod
|
|
85
|
+
def _finite_diff_jac(fun: Callable[[Array], Array], x: Array, eps: float) -> Array:
|
|
86
|
+
y0 = fun(x)
|
|
87
|
+
m = int(np.prod(y0.shape))
|
|
88
|
+
y0 = y0.reshape(-1)
|
|
89
|
+
n = x.size
|
|
90
|
+
J = np.zeros((m, n), dtype=float)
|
|
91
|
+
for j in range(n):
|
|
92
|
+
xp = x.copy()
|
|
93
|
+
xp[j] += eps
|
|
94
|
+
J[:, j] = (fun(xp).reshape(-1) - y0) / eps
|
|
95
|
+
return J
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def _pairwise_M(k: int) -> Array:
|
|
99
|
+
return np.ones((k, k), dtype=float) - np.eye(k, dtype=float)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def _sum_to_one_selector(n: int, idx: Sequence[int]) -> Array:
|
|
103
|
+
S = np.zeros((1, n), dtype=float)
|
|
104
|
+
S[0, np.array(list(idx), int)] = 1.0
|
|
105
|
+
return S
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def _make_sum1_fun(S):
|
|
109
|
+
return lambda x: S @ x - np.array([1.0])
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _make_sum1_jac(S):
|
|
113
|
+
return lambda x: S
|
|
114
|
+
|
|
115
|
+
@staticmethod
|
|
116
|
+
def _make_onehot_fun(sl, M):
|
|
117
|
+
sl = np.array(sl, int)
|
|
118
|
+
|
|
119
|
+
def _f(x):
|
|
120
|
+
s = x[sl]
|
|
121
|
+
return np.array([float(s @ (M @ s))]) # shape (1,)
|
|
122
|
+
|
|
123
|
+
return _f
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def _make_onehot_jac(sl, M, n):
|
|
127
|
+
sl = np.array(sl, int)
|
|
128
|
+
|
|
129
|
+
def _J(x):
|
|
130
|
+
s = x[sl]
|
|
131
|
+
grad_blk = 2.0 * (M @ s) # (k,)
|
|
132
|
+
J = np.zeros((1, n), dtype=float) # shape (1, n)
|
|
133
|
+
J[0, sl] = grad_blk
|
|
134
|
+
return J
|
|
135
|
+
|
|
136
|
+
return _J
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _poly_value(poly_terms: List[PolyTerm], x: Array) -> float:
|
|
140
|
+
val = 0.0
|
|
141
|
+
for inds, coeff in poly_terms:
|
|
142
|
+
prod = 1.0
|
|
143
|
+
for j in inds:
|
|
144
|
+
if j == 0:
|
|
145
|
+
continue
|
|
146
|
+
else:
|
|
147
|
+
prod *= x[j - 1]
|
|
148
|
+
val += coeff * prod
|
|
149
|
+
return float(val)
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def _merge_poly(poly_terms: Optional[List[PolyTerm]], Q_aug: Optional[Array],
|
|
153
|
+
c_aug: Optional[Array]) -> List[PolyTerm]:
|
|
154
|
+
"""
|
|
155
|
+
Merge ALM's quadratic/linear increments (Q_aug, c_aug) into the base polynomial term list `poly_terms`.
|
|
156
|
+
If 'poly_terms' is None, then turn x^T Q_aug x + c_aug^T x into polynomial monomials.
|
|
157
|
+
Terms are of the form:
|
|
158
|
+
((0, i), w) for linear, ((i, j), w) for quadratic.
|
|
159
|
+
"""
|
|
160
|
+
merged = list(poly_terms) if poly_terms is not None else []
|
|
161
|
+
|
|
162
|
+
if Q_aug is not None:
|
|
163
|
+
Qs = 0.5 * (Q_aug + Q_aug.T)
|
|
164
|
+
n = Qs.shape[0]
|
|
165
|
+
for i in range(n):
|
|
166
|
+
# diagonal contributes Qii * x_i^2
|
|
167
|
+
if Qs[i, i] != 0.0:
|
|
168
|
+
merged.append(((i + 1, i + 1), float(Qs[i, i])))
|
|
169
|
+
for j in range(i + 1, n):
|
|
170
|
+
q = 2.0 * Qs[i, j] # x^T Q x -> sum_{i<j} 2*Q_ij x_i x_j
|
|
171
|
+
if q != 0.0:
|
|
172
|
+
merged.append(((i + 1, j + 1), float(q)))
|
|
173
|
+
if c_aug is not None:
|
|
174
|
+
for i, ci in enumerate(c_aug):
|
|
175
|
+
if ci != 0.0:
|
|
176
|
+
merged.append(((0, i + 1), float(ci)))
|
|
177
|
+
return merged
|
|
178
|
+
|
|
179
|
+
# ---- main entrypoint ----
|
|
180
|
+
@staticmethod
|
|
181
|
+
def run(
|
|
182
|
+
model: PolynomialModel,
|
|
183
|
+
registry: ConstraintRegistry,
|
|
184
|
+
solver,
|
|
185
|
+
cfg: ALMConfig = ALMConfig(),
|
|
186
|
+
x0: Optional[Array] = None,
|
|
187
|
+
*,
|
|
188
|
+
parse_output=None,
|
|
189
|
+
verbose: bool = True,
|
|
190
|
+
**solver_kwargs,
|
|
191
|
+
) -> Dict[str, Union[Array, Dict[int, float], Dict]]:
|
|
192
|
+
"""
|
|
193
|
+
Solve with ALM. Keep all ALM state local to this call (no global side-effects).
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
{
|
|
197
|
+
"x": final iterate,
|
|
198
|
+
"decoded": {start_idx_of_block: level_value, ...} for lifted blocks,
|
|
199
|
+
"hist": { "eq_inf": [...], "ineq_inf": [...], "obj": [...], "x": [...] }
|
|
200
|
+
}
|
|
201
|
+
"""
|
|
202
|
+
n = int(getattr(model, "n", len(getattr(model, "upper_bound", [])) or 0))
|
|
203
|
+
x = (np.asarray(x0, float).copy() if x0 is not None else
|
|
204
|
+
np.zeros(n, float))
|
|
205
|
+
lb = getattr(model, "lower_bound", None)
|
|
206
|
+
ub = getattr(model, "upper_bound", None)
|
|
207
|
+
|
|
208
|
+
# ---- collect constraints ----
|
|
209
|
+
problem_eqs = [c for c in registry.constraints if c.kind == "eq"]
|
|
210
|
+
problem_ineqs = [c for c in registry.constraints if c.kind == "ineq"]
|
|
211
|
+
|
|
212
|
+
# auto-install sum-to-one and one-hot as equalities
|
|
213
|
+
# (One-hot: s^T (11^T - I) s = 0))
|
|
214
|
+
def _install_block_equalities() -> List[ALMConstraint]:
|
|
215
|
+
eqs: List[ALMConstraint] = []
|
|
216
|
+
for blk in registry.blocks:
|
|
217
|
+
if blk.enforce_sum_to_one:
|
|
218
|
+
S = ALMAlgorithm._sum_to_one_selector(n, blk.idx)
|
|
219
|
+
eqs.append(ALMConstraint(
|
|
220
|
+
"eq",
|
|
221
|
+
fun=ALMAlgorithm._make_sum1_fun(S),
|
|
222
|
+
jac=ALMAlgorithm._make_sum1_jac(S),
|
|
223
|
+
name=f"sum_to_one_block_{blk.idx[0]}",
|
|
224
|
+
))
|
|
225
|
+
if blk.enforce_one_hot:
|
|
226
|
+
k = len(blk.idx)
|
|
227
|
+
M = ALMAlgorithm._pairwise_M(k)
|
|
228
|
+
eqs.append(ALMConstraint(
|
|
229
|
+
"eq",
|
|
230
|
+
fun=ALMAlgorithm._make_onehot_fun(blk.idx, M),
|
|
231
|
+
jac=ALMAlgorithm._make_onehot_jac(blk.idx, M, n),
|
|
232
|
+
name=f"onehot_block_{blk.idx[0]}",
|
|
233
|
+
))
|
|
234
|
+
return eqs
|
|
235
|
+
|
|
236
|
+
block_eqs = _install_block_equalities()
|
|
237
|
+
|
|
238
|
+
# Unified equality list (order is fixed for whole run)
|
|
239
|
+
full_eqs = problem_eqs + block_eqs
|
|
240
|
+
|
|
241
|
+
# Allocate multipliers for every equality in full_eqs
|
|
242
|
+
lam_eq = []
|
|
243
|
+
for csp in full_eqs:
|
|
244
|
+
r0 = csp.fun(x).reshape(-1)
|
|
245
|
+
lam_eq.append(np.zeros_like(r0, dtype=float))
|
|
246
|
+
|
|
247
|
+
# Inequality multipliers per user inequality
|
|
248
|
+
mu_ineq = []
|
|
249
|
+
for csp in problem_ineqs:
|
|
250
|
+
r0 = csp.fun(x).reshape(-1)
|
|
251
|
+
mu_ineq.append(np.zeros_like(r0, dtype=float))
|
|
252
|
+
|
|
253
|
+
# -------- running stats for adaptive penalties --------
|
|
254
|
+
rho_h, rho_g = cfg.rho_h, cfg.rho_g
|
|
255
|
+
best_eq, best_ineq = np.inf, np.inf
|
|
256
|
+
no_imp_eq = no_imp_ineq = 0
|
|
257
|
+
prev_eq_inf, prev_ineq_inf = np.inf, np.inf
|
|
258
|
+
eps = 1e-12
|
|
259
|
+
|
|
260
|
+
hist = {"eq_inf": [], "ineq_inf": [], "obj": [], "x": [],
|
|
261
|
+
# per-iteration logs for parameters/multipliers
|
|
262
|
+
"rho_h": [], "rho_g": [],
|
|
263
|
+
}
|
|
264
|
+
for k_idx, csp in enumerate(full_eqs):
|
|
265
|
+
if csp.kind != "eq":
|
|
266
|
+
continue
|
|
267
|
+
hist[f"lam_eq_max_idx{k_idx}"] = []
|
|
268
|
+
hist[f"lam_eq_min_idx{k_idx}"] = []
|
|
269
|
+
for k_idx, csp in enumerate(problem_ineqs):
|
|
270
|
+
if csp.kind != "ineq":
|
|
271
|
+
continue
|
|
272
|
+
hist[f"mu_ineq_max_idx{k_idx}"] = []
|
|
273
|
+
hist[f"mu_ineq_min_idx{k_idx}"] = []
|
|
274
|
+
|
|
275
|
+
for it in range(cfg.max_outer):
|
|
276
|
+
# -------- base polynomial (does not include fixed penalties here) --------
|
|
277
|
+
# base_terms: List[PolyTerm] = list(getattr(model, "polynomial"))
|
|
278
|
+
base_terms: List[PolyTerm] = list(zip(model.polynomial.indices, model.polynomial.coefficients))
|
|
279
|
+
|
|
280
|
+
# -------- ALM quadratic/linear pieces (assembled here, kept separate) --------
|
|
281
|
+
Q_aug = np.zeros((n, n), dtype=float)
|
|
282
|
+
c_aug = np.zeros(n, dtype=float)
|
|
283
|
+
have_aug = False
|
|
284
|
+
|
|
285
|
+
# (A) Equalities: linearize h near x^t => (rho/2)||A x - b||^2 + lam^T(Ax - b)
|
|
286
|
+
for k_idx, csp in enumerate(full_eqs):
|
|
287
|
+
if csp.kind != "eq":
|
|
288
|
+
continue
|
|
289
|
+
h = csp.fun(x).reshape(-1)
|
|
290
|
+
A = csp.jac(x) if csp.jac is not None else ALMAlgorithm._finite_diff_jac(csp.fun, x, cfg.fd_eps)
|
|
291
|
+
A = np.atleast_2d(A)
|
|
292
|
+
assert A.shape[1] == n, f"A has {A.shape[1]} cols, expected {n}"
|
|
293
|
+
# linearization about current x: residual model r(x) = A x - b, with b = A x - h
|
|
294
|
+
b = A @ x - h
|
|
295
|
+
Qk = 0.5 * rho_h * (A.T @ A)
|
|
296
|
+
ck = (A.T @ lam_eq[k_idx]) - rho_h * (A.T @ b)
|
|
297
|
+
Q_aug += Qk
|
|
298
|
+
c_aug += ck
|
|
299
|
+
have_aug = True
|
|
300
|
+
|
|
301
|
+
# (B) Inequalities: projected ALM. Linearize g near x^t.
|
|
302
|
+
for k_idx, csp in enumerate(problem_ineqs):
|
|
303
|
+
if csp.kind != "ineq":
|
|
304
|
+
continue
|
|
305
|
+
g = csp.fun(x).reshape(-1)
|
|
306
|
+
G = csp.jac(x) if csp.jac is not None else ALMAlgorithm._finite_diff_jac(csp.fun, x, cfg.fd_eps)
|
|
307
|
+
G = np.atleast_2d(G)
|
|
308
|
+
assert G.shape[1] == n, f"G has {G.shape[1]} cols, expected {n}"
|
|
309
|
+
d = G @ x - g
|
|
310
|
+
# Activation measure at current iterate; meaning, the current violating inequality components:
|
|
311
|
+
# g(x) + mu/rho; Powell-Hestenes-Rockafellar shifted residual
|
|
312
|
+
y = G @ x - d + mu_ineq[k_idx] / rho_g
|
|
313
|
+
active = (y > cfg.act_tol)
|
|
314
|
+
if np.any(active):
|
|
315
|
+
GA = G[active, :]
|
|
316
|
+
muA = mu_ineq[k_idx][active]
|
|
317
|
+
gA = g[active]
|
|
318
|
+
# Q += (rho/2) * GA^T GA
|
|
319
|
+
Qk = 0.5 * rho_g * (GA.T @ GA)
|
|
320
|
+
# c += GA^T mu - rho * GA^T (GA x - gA); where GA x - gA is active measures of d = G @ x - g
|
|
321
|
+
ck = (GA.T @ muA) - rho_g * (GA.T @ (GA @ x - gA))
|
|
322
|
+
Q_aug += Qk
|
|
323
|
+
c_aug += ck
|
|
324
|
+
have_aug = True
|
|
325
|
+
|
|
326
|
+
# -------- build merged polynomial for the core solver --------
|
|
327
|
+
all_terms = ALMAlgorithm._merge_poly(base_terms, Q_aug if have_aug else None,
|
|
328
|
+
c_aug if have_aug else None)
|
|
329
|
+
idxs, coeffs = zip(*[(inds, w) for (inds, w) in all_terms]) if all_terms else ([], [])
|
|
330
|
+
poly_model = PolynomialModel(list(coeffs), list(idxs))
|
|
331
|
+
if lb is not None and hasattr(poly_model, "lower_bound"):
|
|
332
|
+
poly_model.lower_bound = np.asarray(lb, float)
|
|
333
|
+
if ub is not None and hasattr(poly_model, "upper_bound"):
|
|
334
|
+
poly_model.upper_bound = np.asarray(ub, float)
|
|
335
|
+
|
|
336
|
+
x_ws = x.copy()
|
|
337
|
+
|
|
338
|
+
# Convention: many cores look for one of these fields if present.
|
|
339
|
+
# Use one or more to be future-proof; harmless if ignored.
|
|
340
|
+
setattr(poly_model, "initial_guess", x_ws)
|
|
341
|
+
setattr(poly_model, "warm_start", x_ws)
|
|
342
|
+
setattr(poly_model, "x0", x_ws)
|
|
343
|
+
|
|
344
|
+
# -------- inner solve --------
|
|
345
|
+
out = solver.solve(poly_model, **solver_kwargs)
|
|
346
|
+
|
|
347
|
+
# -------- parse --------
|
|
348
|
+
if parse_output:
|
|
349
|
+
x = parse_output(out)
|
|
350
|
+
else:
|
|
351
|
+
# default: support (value, x) or `.x` or raw x
|
|
352
|
+
if isinstance(out, tuple) and len(out) == 2:
|
|
353
|
+
_, x = out
|
|
354
|
+
elif isinstance(out, dict) and "results" in out and "solutions" in out["results"]:
|
|
355
|
+
x = out["results"]["solutions"][0]
|
|
356
|
+
elif isinstance(out, dict) and "x" in out:
|
|
357
|
+
x = out["x"]
|
|
358
|
+
else:
|
|
359
|
+
x = getattr(out, "x", out)
|
|
360
|
+
x = np.asarray(x, float)
|
|
361
|
+
|
|
362
|
+
# -------- residuals + multiplier updates --------
|
|
363
|
+
eq_infs = []
|
|
364
|
+
for k_idx, csp in enumerate(full_eqs):
|
|
365
|
+
if csp.kind != "eq": continue
|
|
366
|
+
r = csp.fun(x).reshape(-1)
|
|
367
|
+
lam_eq[k_idx] = lam_eq[k_idx] + rho_h * r
|
|
368
|
+
if r.size:
|
|
369
|
+
eq_infs.append(np.max(np.abs(r)))
|
|
370
|
+
eq_inf = float(np.max(eq_infs)) if eq_infs else 0.0
|
|
371
|
+
|
|
372
|
+
ineq_infs = []
|
|
373
|
+
for k_idx, csp in enumerate(problem_ineqs):
|
|
374
|
+
if csp.kind != "ineq": continue
|
|
375
|
+
r = csp.fun(x).reshape(-1)
|
|
376
|
+
mu_ineq[k_idx] = np.maximum(0.0, mu_ineq[k_idx] + rho_g * r)
|
|
377
|
+
if r.size:
|
|
378
|
+
ineq_infs.append(np.max(np.maximum(0.0, r)))
|
|
379
|
+
ineq_inf = float(np.max(ineq_infs)) if ineq_infs else 0.0
|
|
380
|
+
|
|
381
|
+
assert len(lam_eq) == len(full_eqs)
|
|
382
|
+
assert len(mu_ineq) == len(problem_ineqs)
|
|
383
|
+
|
|
384
|
+
# evaluate base polynomial only (ca add aug value if want to track full L_A)
|
|
385
|
+
f_val = ALMAlgorithm._poly_value(base_terms, x)
|
|
386
|
+
|
|
387
|
+
hist["eq_inf"].append(eq_inf); hist["ineq_inf"].append(ineq_inf)
|
|
388
|
+
hist["obj"].append(float(f_val)); hist["x"].append(x.copy())
|
|
389
|
+
# parameter & multiplier tracking
|
|
390
|
+
hist["rho_h"].append(float(rho_h)); hist["rho_g"].append(float(rho_g))
|
|
391
|
+
for k_idx, csp in enumerate(full_eqs):
|
|
392
|
+
if csp.kind != "eq": continue
|
|
393
|
+
hist[f"lam_eq_max_idx{k_idx}"].append(float(np.max(lam_eq[k_idx])))
|
|
394
|
+
hist[f"lam_eq_min_idx{k_idx}"].append(float(np.min(lam_eq[k_idx])))
|
|
395
|
+
for k_idx, csp in enumerate(problem_ineqs):
|
|
396
|
+
if csp.kind != "ineq": continue
|
|
397
|
+
hist[f"mu_ineq_max_idx{k_idx}"].append(float(np.max(mu_ineq[k_idx])))
|
|
398
|
+
hist[f"mu_ineq_min_idx{k_idx}"].append(float(np.min(mu_ineq[k_idx])))
|
|
399
|
+
|
|
400
|
+
if verbose:
|
|
401
|
+
print(f"[ALM {it:02d}] f={f_val:.6g} | eq_inf={eq_inf:.2e} | ineq_inf={ineq_inf:.2e} "
|
|
402
|
+
f"| rho_h={rho_h:.2e} | rho_g={rho_g:.2e}")
|
|
403
|
+
|
|
404
|
+
# stopping
|
|
405
|
+
if eq_inf <= cfg.tol_h and ineq_inf <= cfg.tol_g:
|
|
406
|
+
if verbose:
|
|
407
|
+
print(f"[ALM] converged at iter {it}")
|
|
408
|
+
break
|
|
409
|
+
|
|
410
|
+
# EMA smoothing to reduce jitter
|
|
411
|
+
if it == 0:
|
|
412
|
+
eq_inf_smooth = eq_inf
|
|
413
|
+
ineq_inf_smooth = ineq_inf
|
|
414
|
+
else:
|
|
415
|
+
eq_inf_smooth = cfg.ema_alpha * eq_inf + (1 - cfg.ema_alpha) * eq_inf_smooth
|
|
416
|
+
ineq_inf_smooth = cfg.ema_alpha * ineq_inf + (1 - cfg.ema_alpha) * ineq_inf_smooth
|
|
417
|
+
|
|
418
|
+
# -------- Residual-ratio controller --------
|
|
419
|
+
if cfg.adapt and it > 0:
|
|
420
|
+
# Equality group
|
|
421
|
+
if eq_inf_smooth > cfg.tau_up_h * max(prev_eq_inf, eps): # stalled or not shrinking
|
|
422
|
+
rho_h = min(cfg.gamma_up * rho_h, cfg.rho_max)
|
|
423
|
+
elif eq_inf_smooth < cfg.tau_down_h * max(prev_eq_inf, eps): # fast progress, allow relaxation
|
|
424
|
+
rho_h = max(cfg.gamma_down * rho_h, cfg.rho_min)
|
|
425
|
+
|
|
426
|
+
# Inequality group
|
|
427
|
+
if ineq_inf_smooth > cfg.tau_up_g * max(prev_ineq_inf, eps):
|
|
428
|
+
rho_g = min(cfg.gamma_up * rho_g, cfg.rho_max)
|
|
429
|
+
elif ineq_inf_smooth < cfg.tau_down_g * max(prev_ineq_inf, eps):
|
|
430
|
+
rho_g = max(cfg.gamma_down * rho_g, cfg.rho_min)
|
|
431
|
+
|
|
432
|
+
# -------- Stagnation bump (safety net) --------
|
|
433
|
+
if cfg.use_stagnation_bump:
|
|
434
|
+
# Equality stagnation
|
|
435
|
+
if eq_inf <= best_eq * (1 - cfg.stagnation_factor):
|
|
436
|
+
best_eq = eq_inf; no_imp_eq = 0
|
|
437
|
+
else:
|
|
438
|
+
no_imp_eq += 1
|
|
439
|
+
if no_imp_eq >= cfg.patience_h:
|
|
440
|
+
rho_h = min(2.0 * rho_h, cfg.rho_max); no_imp_eq = 0
|
|
441
|
+
|
|
442
|
+
# Inequality stagnation
|
|
443
|
+
if ineq_inf <= best_ineq * (1 - cfg.stagnation_factor):
|
|
444
|
+
best_ineq = ineq_inf; no_imp_ineq = 0
|
|
445
|
+
else:
|
|
446
|
+
no_imp_ineq += 1
|
|
447
|
+
if no_imp_ineq >= cfg.patience_g:
|
|
448
|
+
rho_g = min(2.0 * rho_g, cfg.rho_max); no_imp_ineq = 0
|
|
449
|
+
|
|
450
|
+
# -------- finalize for next iteration --------
|
|
451
|
+
prev_eq_inf = max(eq_inf_smooth, eps)
|
|
452
|
+
prev_ineq_inf = max(ineq_inf_smooth, eps)
|
|
453
|
+
|
|
454
|
+
# optional decoding for lifted blocks
|
|
455
|
+
decoded: Dict[int, Union[int, float]] = {}
|
|
456
|
+
for blk in registry.blocks:
|
|
457
|
+
sl = np.array(blk.idx, int)
|
|
458
|
+
if len(sl) == 0:
|
|
459
|
+
continue
|
|
460
|
+
s = x[sl]
|
|
461
|
+
j = int(np.argmax(s))
|
|
462
|
+
decoded[sl[0]] = float(blk.levels[j])
|
|
463
|
+
|
|
464
|
+
return {"x": x, "decoded": decoded, "hist": hist}
|
|
@@ -125,6 +125,26 @@ class ShortestPathModel(EdgeMixin, ConstrainedQuadraticModel):
|
|
|
125
125
|
J = np.zeros((n, n))
|
|
126
126
|
return np.array(_obj), J
|
|
127
127
|
|
|
128
|
+
@property
|
|
129
|
+
def penalties(self):
|
|
130
|
+
Pl, Pq = super(ShortestPathModel, self).penalties
|
|
131
|
+
# increment the quadratic penalties by 1 for each pair of incoming edges and again for outgoing edges
|
|
132
|
+
G = self.G
|
|
133
|
+
for u in G.nodes:
|
|
134
|
+
for u1, v1 in G.out_edges(nbunch=u):
|
|
135
|
+
idx1 = self.variables.index((u1, v1))
|
|
136
|
+
for u2, v2 in G.out_edges(nbunch=u):
|
|
137
|
+
if v1 != v2:
|
|
138
|
+
idx2 = self.variables.index((u2, v2))
|
|
139
|
+
Pq[idx1, idx2] += 0.5
|
|
140
|
+
for u1, v1 in G.in_edges(nbunch=u):
|
|
141
|
+
idx1 = self.variables.index((u1, v1))
|
|
142
|
+
for u2, v2 in G.in_edges(nbunch=u):
|
|
143
|
+
if v1 != v2:
|
|
144
|
+
idx2 = self.variables.index((u2, v2))
|
|
145
|
+
Pq[idx1, idx2] += 0.5
|
|
146
|
+
return Pl, Pq
|
|
147
|
+
|
|
128
148
|
def decode(self, solution : np.ndarray, weight="weight") -> Dict:
|
|
129
149
|
"""
|
|
130
150
|
Convert a solution to this model into a path, which is
|
|
@@ -11,6 +11,6 @@ class Dirac3MIPDirectSolver(MIPMixin, Dirac3DirectSolver):
|
|
|
11
11
|
pass
|
|
12
12
|
|
|
13
13
|
__all__ = ["Dirac3DirectSolver", "Dirac1CloudSolver", "Dirac3CloudSolver",
|
|
14
|
-
"
|
|
14
|
+
"QciClientSolver", "Dirac3IntegerCloudSolver",
|
|
15
15
|
"Dirac3ContinuousCloudSolver", "MIPMixin",
|
|
16
|
-
"Dirac3MIPCloudSolver", "Dirac3MIPDirectSolver"]
|
|
16
|
+
"Dirac3MIPCloudSolver", "Dirac3MIPDirectSolver",]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eqc-models
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: Optimization and ML modeling package targeting EQC devices
|
|
5
5
|
Author-email: "Quantum Computing Inc." <support@quantumcomputinginc.com>
|
|
6
6
|
Project-URL: Homepage, https://quantumcomputinginc.com
|
|
@@ -32,6 +32,7 @@ eqc_models.egg-info/dependency_links.txt
|
|
|
32
32
|
eqc_models.egg-info/requires.txt
|
|
33
33
|
eqc_models.egg-info/top_level.txt
|
|
34
34
|
eqc_models/algorithms/__init__.py
|
|
35
|
+
eqc_models/algorithms/alm.py
|
|
35
36
|
eqc_models/algorithms/base.py
|
|
36
37
|
eqc_models/algorithms/penaltymultiplier.py
|
|
37
38
|
eqc_models/allocation/__init__.py
|
|
@@ -91,6 +92,7 @@ eqc_models/utilities/fileio.py
|
|
|
91
92
|
eqc_models/utilities/general.py
|
|
92
93
|
eqc_models/utilities/polynomial.py
|
|
93
94
|
eqc_models/utilities/qplib.py
|
|
95
|
+
scripts/ALM_pipeline.ipynb
|
|
94
96
|
scripts/binary_job_example.py
|
|
95
97
|
scripts/binary_w_continuous_solver_example.py
|
|
96
98
|
scripts/c6h6_graph_clustering.py
|
|
@@ -123,6 +125,7 @@ scripts/test_shortestpath.py
|
|
|
123
125
|
scripts/utils.py
|
|
124
126
|
test/doctest_base.py
|
|
125
127
|
test/testallocationmodel.py
|
|
128
|
+
test/testalm.py
|
|
126
129
|
test/testconstraint.py
|
|
127
130
|
test/testcvqboost.py
|
|
128
131
|
test/testeqcdirectsolver.py
|