qilisdk 0.1.8__cp311-cp311-manylinux_2_28_x86_64.whl
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.
- include/eigen3/Eigen/Cholesky +45 -0
- include/eigen3/Eigen/CholmodSupport +48 -0
- include/eigen3/Eigen/Core +384 -0
- include/eigen3/Eigen/Dense +7 -0
- include/eigen3/Eigen/Eigen +2 -0
- include/eigen3/Eigen/Eigenvalues +60 -0
- include/eigen3/Eigen/Geometry +59 -0
- include/eigen3/Eigen/Householder +29 -0
- include/eigen3/Eigen/IterativeLinearSolvers +48 -0
- include/eigen3/Eigen/Jacobi +32 -0
- include/eigen3/Eigen/KLUSupport +41 -0
- include/eigen3/Eigen/LU +47 -0
- include/eigen3/Eigen/MetisSupport +35 -0
- include/eigen3/Eigen/OrderingMethods +70 -0
- include/eigen3/Eigen/PaStiXSupport +49 -0
- include/eigen3/Eigen/PardisoSupport +35 -0
- include/eigen3/Eigen/QR +50 -0
- include/eigen3/Eigen/QtAlignedMalloc +39 -0
- include/eigen3/Eigen/SPQRSupport +34 -0
- include/eigen3/Eigen/SVD +50 -0
- include/eigen3/Eigen/Sparse +34 -0
- include/eigen3/Eigen/SparseCholesky +37 -0
- include/eigen3/Eigen/SparseCore +69 -0
- include/eigen3/Eigen/SparseLU +50 -0
- include/eigen3/Eigen/SparseQR +36 -0
- include/eigen3/Eigen/StdDeque +27 -0
- include/eigen3/Eigen/StdList +26 -0
- include/eigen3/Eigen/StdVector +27 -0
- include/eigen3/Eigen/SuperLUSupport +64 -0
- include/eigen3/Eigen/UmfPackSupport +40 -0
- include/eigen3/Eigen/src/Cholesky/LDLT.h +688 -0
- include/eigen3/Eigen/src/Cholesky/LLT.h +558 -0
- include/eigen3/Eigen/src/Cholesky/LLT_LAPACKE.h +99 -0
- include/eigen3/Eigen/src/CholmodSupport/CholmodSupport.h +682 -0
- include/eigen3/Eigen/src/Core/ArithmeticSequence.h +413 -0
- include/eigen3/Eigen/src/Core/Array.h +417 -0
- include/eigen3/Eigen/src/Core/ArrayBase.h +226 -0
- include/eigen3/Eigen/src/Core/ArrayWrapper.h +209 -0
- include/eigen3/Eigen/src/Core/Assign.h +90 -0
- include/eigen3/Eigen/src/Core/AssignEvaluator.h +1010 -0
- include/eigen3/Eigen/src/Core/Assign_MKL.h +178 -0
- include/eigen3/Eigen/src/Core/BandMatrix.h +353 -0
- include/eigen3/Eigen/src/Core/Block.h +448 -0
- include/eigen3/Eigen/src/Core/BooleanRedux.h +162 -0
- include/eigen3/Eigen/src/Core/CommaInitializer.h +164 -0
- include/eigen3/Eigen/src/Core/ConditionEstimator.h +175 -0
- include/eigen3/Eigen/src/Core/CoreEvaluators.h +1741 -0
- include/eigen3/Eigen/src/Core/CoreIterators.h +132 -0
- include/eigen3/Eigen/src/Core/CwiseBinaryOp.h +183 -0
- include/eigen3/Eigen/src/Core/CwiseNullaryOp.h +1001 -0
- include/eigen3/Eigen/src/Core/CwiseTernaryOp.h +197 -0
- include/eigen3/Eigen/src/Core/CwiseUnaryOp.h +103 -0
- include/eigen3/Eigen/src/Core/CwiseUnaryView.h +132 -0
- include/eigen3/Eigen/src/Core/DenseBase.h +701 -0
- include/eigen3/Eigen/src/Core/DenseCoeffsBase.h +685 -0
- include/eigen3/Eigen/src/Core/DenseStorage.h +652 -0
- include/eigen3/Eigen/src/Core/Diagonal.h +258 -0
- include/eigen3/Eigen/src/Core/DiagonalMatrix.h +391 -0
- include/eigen3/Eigen/src/Core/DiagonalProduct.h +28 -0
- include/eigen3/Eigen/src/Core/Dot.h +318 -0
- include/eigen3/Eigen/src/Core/EigenBase.h +160 -0
- include/eigen3/Eigen/src/Core/ForceAlignedAccess.h +150 -0
- include/eigen3/Eigen/src/Core/Fuzzy.h +155 -0
- include/eigen3/Eigen/src/Core/GeneralProduct.h +465 -0
- include/eigen3/Eigen/src/Core/GenericPacketMath.h +1040 -0
- include/eigen3/Eigen/src/Core/GlobalFunctions.h +194 -0
- include/eigen3/Eigen/src/Core/IO.h +258 -0
- include/eigen3/Eigen/src/Core/IndexedView.h +237 -0
- include/eigen3/Eigen/src/Core/Inverse.h +117 -0
- include/eigen3/Eigen/src/Core/Map.h +171 -0
- include/eigen3/Eigen/src/Core/MapBase.h +310 -0
- include/eigen3/Eigen/src/Core/MathFunctions.h +2057 -0
- include/eigen3/Eigen/src/Core/MathFunctionsImpl.h +200 -0
- include/eigen3/Eigen/src/Core/Matrix.h +565 -0
- include/eigen3/Eigen/src/Core/MatrixBase.h +547 -0
- include/eigen3/Eigen/src/Core/NestByValue.h +85 -0
- include/eigen3/Eigen/src/Core/NoAlias.h +109 -0
- include/eigen3/Eigen/src/Core/NumTraits.h +335 -0
- include/eigen3/Eigen/src/Core/PartialReduxEvaluator.h +232 -0
- include/eigen3/Eigen/src/Core/PermutationMatrix.h +605 -0
- include/eigen3/Eigen/src/Core/PlainObjectBase.h +1128 -0
- include/eigen3/Eigen/src/Core/Product.h +191 -0
- include/eigen3/Eigen/src/Core/ProductEvaluators.h +1179 -0
- include/eigen3/Eigen/src/Core/Random.h +218 -0
- include/eigen3/Eigen/src/Core/Redux.h +515 -0
- include/eigen3/Eigen/src/Core/Ref.h +381 -0
- include/eigen3/Eigen/src/Core/Replicate.h +142 -0
- include/eigen3/Eigen/src/Core/Reshaped.h +454 -0
- include/eigen3/Eigen/src/Core/ReturnByValue.h +119 -0
- include/eigen3/Eigen/src/Core/Reverse.h +217 -0
- include/eigen3/Eigen/src/Core/Select.h +164 -0
- include/eigen3/Eigen/src/Core/SelfAdjointView.h +365 -0
- include/eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h +47 -0
- include/eigen3/Eigen/src/Core/Solve.h +188 -0
- include/eigen3/Eigen/src/Core/SolveTriangular.h +235 -0
- include/eigen3/Eigen/src/Core/SolverBase.h +168 -0
- include/eigen3/Eigen/src/Core/StableNorm.h +251 -0
- include/eigen3/Eigen/src/Core/StlIterators.h +463 -0
- include/eigen3/Eigen/src/Core/Stride.h +116 -0
- include/eigen3/Eigen/src/Core/Swap.h +68 -0
- include/eigen3/Eigen/src/Core/Transpose.h +464 -0
- include/eigen3/Eigen/src/Core/Transpositions.h +386 -0
- include/eigen3/Eigen/src/Core/TriangularMatrix.h +1001 -0
- include/eigen3/Eigen/src/Core/VectorBlock.h +96 -0
- include/eigen3/Eigen/src/Core/VectorwiseOp.h +784 -0
- include/eigen3/Eigen/src/Core/Visitor.h +381 -0
- include/eigen3/Eigen/src/Core/arch/AVX/Complex.h +372 -0
- include/eigen3/Eigen/src/Core/arch/AVX/MathFunctions.h +228 -0
- include/eigen3/Eigen/src/Core/arch/AVX/PacketMath.h +1574 -0
- include/eigen3/Eigen/src/Core/arch/AVX/TypeCasting.h +115 -0
- include/eigen3/Eigen/src/Core/arch/AVX512/Complex.h +422 -0
- include/eigen3/Eigen/src/Core/arch/AVX512/MathFunctions.h +362 -0
- include/eigen3/Eigen/src/Core/arch/AVX512/PacketMath.h +2303 -0
- include/eigen3/Eigen/src/Core/arch/AVX512/TypeCasting.h +89 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/Complex.h +417 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/MathFunctions.h +90 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/MatrixProduct.h +2937 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/MatrixProductCommon.h +221 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/MatrixProductMMA.h +629 -0
- include/eigen3/Eigen/src/Core/arch/AltiVec/PacketMath.h +2711 -0
- include/eigen3/Eigen/src/Core/arch/CUDA/Complex.h +258 -0
- include/eigen3/Eigen/src/Core/arch/Default/BFloat16.h +700 -0
- include/eigen3/Eigen/src/Core/arch/Default/ConjHelper.h +117 -0
- include/eigen3/Eigen/src/Core/arch/Default/GenericPacketMathFunctions.h +1649 -0
- include/eigen3/Eigen/src/Core/arch/Default/GenericPacketMathFunctionsFwd.h +110 -0
- include/eigen3/Eigen/src/Core/arch/Default/Half.h +942 -0
- include/eigen3/Eigen/src/Core/arch/Default/Settings.h +49 -0
- include/eigen3/Eigen/src/Core/arch/Default/TypeCasting.h +120 -0
- include/eigen3/Eigen/src/Core/arch/GPU/MathFunctions.h +103 -0
- include/eigen3/Eigen/src/Core/arch/GPU/PacketMath.h +1685 -0
- include/eigen3/Eigen/src/Core/arch/GPU/TypeCasting.h +80 -0
- include/eigen3/Eigen/src/Core/arch/HIP/hcc/math_constants.h +23 -0
- include/eigen3/Eigen/src/Core/arch/MSA/Complex.h +648 -0
- include/eigen3/Eigen/src/Core/arch/MSA/MathFunctions.h +387 -0
- include/eigen3/Eigen/src/Core/arch/MSA/PacketMath.h +1233 -0
- include/eigen3/Eigen/src/Core/arch/NEON/Complex.h +584 -0
- include/eigen3/Eigen/src/Core/arch/NEON/GeneralBlockPanelKernel.h +183 -0
- include/eigen3/Eigen/src/Core/arch/NEON/MathFunctions.h +75 -0
- include/eigen3/Eigen/src/Core/arch/NEON/PacketMath.h +4587 -0
- include/eigen3/Eigen/src/Core/arch/NEON/TypeCasting.h +1419 -0
- include/eigen3/Eigen/src/Core/arch/SSE/Complex.h +351 -0
- include/eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h +199 -0
- include/eigen3/Eigen/src/Core/arch/SSE/PacketMath.h +1505 -0
- include/eigen3/Eigen/src/Core/arch/SSE/TypeCasting.h +142 -0
- include/eigen3/Eigen/src/Core/arch/SVE/MathFunctions.h +44 -0
- include/eigen3/Eigen/src/Core/arch/SVE/PacketMath.h +752 -0
- include/eigen3/Eigen/src/Core/arch/SVE/TypeCasting.h +49 -0
- include/eigen3/Eigen/src/Core/arch/SYCL/InteropHeaders.h +232 -0
- include/eigen3/Eigen/src/Core/arch/SYCL/MathFunctions.h +301 -0
- include/eigen3/Eigen/src/Core/arch/SYCL/PacketMath.h +670 -0
- include/eigen3/Eigen/src/Core/arch/SYCL/SyclMemoryModel.h +694 -0
- include/eigen3/Eigen/src/Core/arch/SYCL/TypeCasting.h +85 -0
- include/eigen3/Eigen/src/Core/arch/ZVector/Complex.h +426 -0
- include/eigen3/Eigen/src/Core/arch/ZVector/MathFunctions.h +233 -0
- include/eigen3/Eigen/src/Core/arch/ZVector/PacketMath.h +1060 -0
- include/eigen3/Eigen/src/Core/functors/AssignmentFunctors.h +177 -0
- include/eigen3/Eigen/src/Core/functors/BinaryFunctors.h +541 -0
- include/eigen3/Eigen/src/Core/functors/NullaryFunctors.h +189 -0
- include/eigen3/Eigen/src/Core/functors/StlFunctors.h +166 -0
- include/eigen3/Eigen/src/Core/functors/TernaryFunctors.h +25 -0
- include/eigen3/Eigen/src/Core/functors/UnaryFunctors.h +1131 -0
- include/eigen3/Eigen/src/Core/products/GeneralBlockPanelKernel.h +2645 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h +517 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular.h +317 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixMatrixTriangular_BLAS.h +145 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixMatrix_BLAS.h +124 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixVector.h +518 -0
- include/eigen3/Eigen/src/Core/products/GeneralMatrixVector_BLAS.h +136 -0
- include/eigen3/Eigen/src/Core/products/Parallelizer.h +180 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix.h +544 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointMatrixMatrix_BLAS.h +295 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector.h +262 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointMatrixVector_BLAS.h +118 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointProduct.h +133 -0
- include/eigen3/Eigen/src/Core/products/SelfadjointRank2Update.h +94 -0
- include/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix.h +472 -0
- include/eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_BLAS.h +317 -0
- include/eigen3/Eigen/src/Core/products/TriangularMatrixVector.h +350 -0
- include/eigen3/Eigen/src/Core/products/TriangularMatrixVector_BLAS.h +255 -0
- include/eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h +337 -0
- include/eigen3/Eigen/src/Core/products/TriangularSolverMatrix_BLAS.h +167 -0
- include/eigen3/Eigen/src/Core/products/TriangularSolverVector.h +148 -0
- include/eigen3/Eigen/src/Core/util/BlasUtil.h +583 -0
- include/eigen3/Eigen/src/Core/util/ConfigureVectorization.h +512 -0
- include/eigen3/Eigen/src/Core/util/Constants.h +563 -0
- include/eigen3/Eigen/src/Core/util/DisableStupidWarnings.h +106 -0
- include/eigen3/Eigen/src/Core/util/ForwardDeclarations.h +322 -0
- include/eigen3/Eigen/src/Core/util/IndexedViewHelper.h +186 -0
- include/eigen3/Eigen/src/Core/util/IntegralConstant.h +272 -0
- include/eigen3/Eigen/src/Core/util/MKL_support.h +137 -0
- include/eigen3/Eigen/src/Core/util/Macros.h +1464 -0
- include/eigen3/Eigen/src/Core/util/Memory.h +1163 -0
- include/eigen3/Eigen/src/Core/util/Meta.h +812 -0
- include/eigen3/Eigen/src/Core/util/NonMPL2.h +3 -0
- include/eigen3/Eigen/src/Core/util/ReenableStupidWarnings.h +31 -0
- include/eigen3/Eigen/src/Core/util/ReshapedHelper.h +51 -0
- include/eigen3/Eigen/src/Core/util/StaticAssert.h +221 -0
- include/eigen3/Eigen/src/Core/util/SymbolicIndex.h +293 -0
- include/eigen3/Eigen/src/Core/util/XprHelper.h +856 -0
- include/eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h +346 -0
- include/eigen3/Eigen/src/Eigenvalues/ComplexSchur.h +462 -0
- include/eigen3/Eigen/src/Eigenvalues/ComplexSchur_LAPACKE.h +91 -0
- include/eigen3/Eigen/src/Eigenvalues/EigenSolver.h +622 -0
- include/eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +418 -0
- include/eigen3/Eigen/src/Eigenvalues/GeneralizedSelfAdjointEigenSolver.h +226 -0
- include/eigen3/Eigen/src/Eigenvalues/HessenbergDecomposition.h +374 -0
- include/eigen3/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +158 -0
- include/eigen3/Eigen/src/Eigenvalues/RealQZ.h +657 -0
- include/eigen3/Eigen/src/Eigenvalues/RealSchur.h +558 -0
- include/eigen3/Eigen/src/Eigenvalues/RealSchur_LAPACKE.h +77 -0
- include/eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +904 -0
- include/eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h +87 -0
- include/eigen3/Eigen/src/Eigenvalues/Tridiagonalization.h +561 -0
- include/eigen3/Eigen/src/Geometry/AlignedBox.h +486 -0
- include/eigen3/Eigen/src/Geometry/AngleAxis.h +247 -0
- include/eigen3/Eigen/src/Geometry/EulerAngles.h +114 -0
- include/eigen3/Eigen/src/Geometry/Homogeneous.h +501 -0
- include/eigen3/Eigen/src/Geometry/Hyperplane.h +282 -0
- include/eigen3/Eigen/src/Geometry/OrthoMethods.h +235 -0
- include/eigen3/Eigen/src/Geometry/ParametrizedLine.h +232 -0
- include/eigen3/Eigen/src/Geometry/Quaternion.h +870 -0
- include/eigen3/Eigen/src/Geometry/Rotation2D.h +199 -0
- include/eigen3/Eigen/src/Geometry/RotationBase.h +206 -0
- include/eigen3/Eigen/src/Geometry/Scaling.h +188 -0
- include/eigen3/Eigen/src/Geometry/Transform.h +1563 -0
- include/eigen3/Eigen/src/Geometry/Translation.h +202 -0
- include/eigen3/Eigen/src/Geometry/Umeyama.h +166 -0
- include/eigen3/Eigen/src/Geometry/arch/Geometry_SIMD.h +168 -0
- include/eigen3/Eigen/src/Householder/BlockHouseholder.h +110 -0
- include/eigen3/Eigen/src/Householder/Householder.h +176 -0
- include/eigen3/Eigen/src/Householder/HouseholderSequence.h +545 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +226 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +212 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +229 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/IncompleteCholesky.h +394 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +453 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +444 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/LeastSquareConjugateGradient.h +198 -0
- include/eigen3/Eigen/src/IterativeLinearSolvers/SolveWithGuess.h +117 -0
- include/eigen3/Eigen/src/Jacobi/Jacobi.h +483 -0
- include/eigen3/Eigen/src/KLUSupport/KLUSupport.h +358 -0
- include/eigen3/Eigen/src/LU/Determinant.h +117 -0
- include/eigen3/Eigen/src/LU/FullPivLU.h +877 -0
- include/eigen3/Eigen/src/LU/InverseImpl.h +432 -0
- include/eigen3/Eigen/src/LU/PartialPivLU.h +624 -0
- include/eigen3/Eigen/src/LU/PartialPivLU_LAPACKE.h +83 -0
- include/eigen3/Eigen/src/LU/arch/InverseSize4.h +351 -0
- include/eigen3/Eigen/src/MetisSupport/MetisSupport.h +137 -0
- include/eigen3/Eigen/src/OrderingMethods/Amd.h +435 -0
- include/eigen3/Eigen/src/OrderingMethods/Eigen_Colamd.h +1863 -0
- include/eigen3/Eigen/src/OrderingMethods/Ordering.h +153 -0
- include/eigen3/Eigen/src/PaStiXSupport/PaStiXSupport.h +678 -0
- include/eigen3/Eigen/src/PardisoSupport/PardisoSupport.h +545 -0
- include/eigen3/Eigen/src/QR/ColPivHouseholderQR.h +674 -0
- include/eigen3/Eigen/src/QR/ColPivHouseholderQR_LAPACKE.h +97 -0
- include/eigen3/Eigen/src/QR/CompleteOrthogonalDecomposition.h +635 -0
- include/eigen3/Eigen/src/QR/FullPivHouseholderQR.h +713 -0
- include/eigen3/Eigen/src/QR/HouseholderQR.h +434 -0
- include/eigen3/Eigen/src/QR/HouseholderQR_LAPACKE.h +68 -0
- include/eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +335 -0
- include/eigen3/Eigen/src/SVD/BDCSVD.h +1366 -0
- include/eigen3/Eigen/src/SVD/JacobiSVD.h +812 -0
- include/eigen3/Eigen/src/SVD/JacobiSVD_LAPACKE.h +91 -0
- include/eigen3/Eigen/src/SVD/SVDBase.h +376 -0
- include/eigen3/Eigen/src/SVD/UpperBidiagonalization.h +414 -0
- include/eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h +697 -0
- include/eigen3/Eigen/src/SparseCholesky/SimplicialCholesky_impl.h +174 -0
- include/eigen3/Eigen/src/SparseCore/AmbiVector.h +378 -0
- include/eigen3/Eigen/src/SparseCore/CompressedStorage.h +274 -0
- include/eigen3/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +352 -0
- include/eigen3/Eigen/src/SparseCore/MappedSparseMatrix.h +67 -0
- include/eigen3/Eigen/src/SparseCore/SparseAssign.h +270 -0
- include/eigen3/Eigen/src/SparseCore/SparseBlock.h +571 -0
- include/eigen3/Eigen/src/SparseCore/SparseColEtree.h +206 -0
- include/eigen3/Eigen/src/SparseCore/SparseCompressedBase.h +370 -0
- include/eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +722 -0
- include/eigen3/Eigen/src/SparseCore/SparseCwiseUnaryOp.h +150 -0
- include/eigen3/Eigen/src/SparseCore/SparseDenseProduct.h +342 -0
- include/eigen3/Eigen/src/SparseCore/SparseDiagonalProduct.h +138 -0
- include/eigen3/Eigen/src/SparseCore/SparseDot.h +98 -0
- include/eigen3/Eigen/src/SparseCore/SparseFuzzy.h +29 -0
- include/eigen3/Eigen/src/SparseCore/SparseMap.h +305 -0
- include/eigen3/Eigen/src/SparseCore/SparseMatrix.h +1518 -0
- include/eigen3/Eigen/src/SparseCore/SparseMatrixBase.h +398 -0
- include/eigen3/Eigen/src/SparseCore/SparsePermutation.h +178 -0
- include/eigen3/Eigen/src/SparseCore/SparseProduct.h +181 -0
- include/eigen3/Eigen/src/SparseCore/SparseRedux.h +49 -0
- include/eigen3/Eigen/src/SparseCore/SparseRef.h +397 -0
- include/eigen3/Eigen/src/SparseCore/SparseSelfAdjointView.h +659 -0
- include/eigen3/Eigen/src/SparseCore/SparseSolverBase.h +124 -0
- include/eigen3/Eigen/src/SparseCore/SparseSparseProductWithPruning.h +198 -0
- include/eigen3/Eigen/src/SparseCore/SparseTranspose.h +92 -0
- include/eigen3/Eigen/src/SparseCore/SparseTriangularView.h +189 -0
- include/eigen3/Eigen/src/SparseCore/SparseUtil.h +186 -0
- include/eigen3/Eigen/src/SparseCore/SparseVector.h +478 -0
- include/eigen3/Eigen/src/SparseCore/SparseView.h +254 -0
- include/eigen3/Eigen/src/SparseCore/TriangularSolver.h +315 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU.h +923 -0
- include/eigen3/Eigen/src/SparseLU/SparseLUImpl.h +66 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_Memory.h +226 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_Structs.h +110 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +375 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_Utils.h +80 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h +181 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_column_dfs.h +179 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_copy_to_ucol.h +107 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_gemm_kernel.h +280 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_heap_relax_snode.h +126 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +130 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h +223 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_panel_dfs.h +258 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h +137 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_pruneL.h +136 -0
- include/eigen3/Eigen/src/SparseLU/SparseLU_relax_snode.h +83 -0
- include/eigen3/Eigen/src/SparseQR/SparseQR.h +758 -0
- include/eigen3/Eigen/src/StlSupport/StdDeque.h +116 -0
- include/eigen3/Eigen/src/StlSupport/StdList.h +106 -0
- include/eigen3/Eigen/src/StlSupport/StdVector.h +131 -0
- include/eigen3/Eigen/src/StlSupport/details.h +84 -0
- include/eigen3/Eigen/src/SuperLUSupport/SuperLUSupport.h +1025 -0
- include/eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h +642 -0
- include/eigen3/Eigen/src/misc/Image.h +82 -0
- include/eigen3/Eigen/src/misc/Kernel.h +79 -0
- include/eigen3/Eigen/src/misc/RealSvd2x2.h +55 -0
- include/eigen3/Eigen/src/misc/blas.h +440 -0
- include/eigen3/Eigen/src/misc/lapack.h +152 -0
- include/eigen3/Eigen/src/misc/lapacke.h +16292 -0
- include/eigen3/Eigen/src/misc/lapacke_mangling.h +17 -0
- include/eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h +358 -0
- include/eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h +696 -0
- include/eigen3/Eigen/src/plugins/BlockMethods.h +1442 -0
- include/eigen3/Eigen/src/plugins/CommonCwiseBinaryOps.h +115 -0
- include/eigen3/Eigen/src/plugins/CommonCwiseUnaryOps.h +177 -0
- include/eigen3/Eigen/src/plugins/IndexedViewMethods.h +262 -0
- include/eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h +152 -0
- include/eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h +95 -0
- include/eigen3/Eigen/src/plugins/ReshapedMethods.h +149 -0
- include/eigen3/signature_of_eigen3_matrix_library +1 -0
- include/eigen3/unsupported/Eigen/AdolcForward +159 -0
- include/eigen3/unsupported/Eigen/AlignedVector3 +234 -0
- include/eigen3/unsupported/Eigen/ArpackSupport +30 -0
- include/eigen3/unsupported/Eigen/AutoDiff +46 -0
- include/eigen3/unsupported/Eigen/BVH +95 -0
- include/eigen3/unsupported/Eigen/CXX11/Tensor +137 -0
- include/eigen3/unsupported/Eigen/CXX11/TensorSymmetry +42 -0
- include/eigen3/unsupported/Eigen/CXX11/ThreadPool +74 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/Tensor.h +554 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorArgMax.h +329 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorAssign.h +247 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorBase.h +1176 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorBlock.h +1559 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorBroadcasting.h +1093 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorChipping.h +518 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorConcatenation.h +377 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContraction.h +1023 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionBlocking.h +73 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionCuda.h +6 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionGpu.h +1413 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionMapper.h +575 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionSycl.h +1650 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorContractionThreadPool.h +1679 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorConversion.h +456 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorConvolution.h +1132 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorConvolutionSycl.h +544 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorCostModel.h +214 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorCustomOp.h +347 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDevice.h +137 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceCuda.h +6 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceDefault.h +104 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceGpu.h +389 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceSycl.h +1048 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDeviceThreadPool.h +409 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDimensionList.h +236 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorDimensions.h +490 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorEvalTo.h +236 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorEvaluator.h +983 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorExecutor.h +703 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorExpr.h +388 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorFFT.h +669 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorFixedSize.h +379 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorForcedEval.h +237 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorForwardDeclarations.h +191 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorFunctors.h +488 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorGenerator.h +302 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorGlobalFunctions.h +33 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorGpuHipCudaDefines.h +99 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorGpuHipCudaUndefines.h +44 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorIO.h +79 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorImagePatch.h +603 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorIndexList.h +738 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInflation.h +247 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorInitializer.h +82 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorIntDiv.h +263 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorLayoutSwap.h +216 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorMacros.h +98 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorMap.h +327 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorMeta.h +311 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorMorphing.h +1102 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorPadding.h +708 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorPatch.h +291 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorRandom.h +322 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorReduction.h +998 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorReductionCuda.h +6 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorReductionGpu.h +966 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorReductionSycl.h +582 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorRef.h +454 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorReverse.h +465 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorScan.h +528 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorScanSycl.h +513 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorShuffling.h +471 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorStorage.h +161 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorStriding.h +346 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorTrace.h +303 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorTraits.h +264 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorUInt128.h +249 -0
- include/eigen3/unsupported/Eigen/CXX11/src/Tensor/TensorVolumePatch.h +629 -0
- include/eigen3/unsupported/Eigen/CXX11/src/TensorSymmetry/DynamicSymmetry.h +293 -0
- include/eigen3/unsupported/Eigen/CXX11/src/TensorSymmetry/StaticSymmetry.h +236 -0
- include/eigen3/unsupported/Eigen/CXX11/src/TensorSymmetry/Symmetry.h +338 -0
- include/eigen3/unsupported/Eigen/CXX11/src/TensorSymmetry/util/TemplateGroupTheory.h +669 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/Barrier.h +67 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/EventCount.h +249 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/NonBlockingThreadPool.h +486 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/RunQueue.h +236 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/ThreadCancel.h +23 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/ThreadEnvironment.h +40 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/ThreadLocal.h +301 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/ThreadPoolInterface.h +48 -0
- include/eigen3/unsupported/Eigen/CXX11/src/ThreadPool/ThreadYield.h +20 -0
- include/eigen3/unsupported/Eigen/CXX11/src/util/CXX11Meta.h +537 -0
- include/eigen3/unsupported/Eigen/CXX11/src/util/CXX11Workarounds.h +88 -0
- include/eigen3/unsupported/Eigen/CXX11/src/util/EmulateArray.h +261 -0
- include/eigen3/unsupported/Eigen/CXX11/src/util/MaxSizeVector.h +158 -0
- include/eigen3/unsupported/Eigen/EulerAngles +43 -0
- include/eigen3/unsupported/Eigen/FFT +419 -0
- include/eigen3/unsupported/Eigen/IterativeSolvers +51 -0
- include/eigen3/unsupported/Eigen/KroneckerProduct +36 -0
- include/eigen3/unsupported/Eigen/LevenbergMarquardt +49 -0
- include/eigen3/unsupported/Eigen/MPRealSupport +213 -0
- include/eigen3/unsupported/Eigen/MatrixFunctions +504 -0
- include/eigen3/unsupported/Eigen/MoreVectorization +24 -0
- include/eigen3/unsupported/Eigen/NonLinearOptimization +140 -0
- include/eigen3/unsupported/Eigen/NumericalDiff +56 -0
- include/eigen3/unsupported/Eigen/OpenGLSupport +322 -0
- include/eigen3/unsupported/Eigen/Polynomials +137 -0
- include/eigen3/unsupported/Eigen/Skyline +39 -0
- include/eigen3/unsupported/Eigen/SparseExtra +54 -0
- include/eigen3/unsupported/Eigen/SpecialFunctions +103 -0
- include/eigen3/unsupported/Eigen/Splines +35 -0
- include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h +108 -0
- include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h +730 -0
- include/eigen3/unsupported/Eigen/src/AutoDiff/AutoDiffVector.h +220 -0
- include/eigen3/unsupported/Eigen/src/BVH/BVAlgorithms.h +293 -0
- include/eigen3/unsupported/Eigen/src/BVH/KdBVH.h +223 -0
- include/eigen3/unsupported/Eigen/src/Eigenvalues/ArpackSelfAdjointEigenSolver.h +790 -0
- include/eigen3/unsupported/Eigen/src/EulerAngles/EulerAngles.h +355 -0
- include/eigen3/unsupported/Eigen/src/EulerAngles/EulerSystem.h +305 -0
- include/eigen3/unsupported/Eigen/src/FFT/ei_fftw_impl.h +261 -0
- include/eigen3/unsupported/Eigen/src/FFT/ei_kissfft_impl.h +449 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/ConstrainedConjGrad.h +187 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/DGMRES.h +511 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/GMRES.h +335 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/IDRS.h +436 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/IncompleteLU.h +90 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/IterationController.h +154 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/MINRES.h +267 -0
- include/eigen3/unsupported/Eigen/src/IterativeSolvers/Scaling.h +193 -0
- include/eigen3/unsupported/Eigen/src/KroneckerProduct/KroneckerTensorProduct.h +305 -0
- include/eigen3/unsupported/Eigen/src/LevenbergMarquardt/LMcovar.h +84 -0
- include/eigen3/unsupported/Eigen/src/LevenbergMarquardt/LMonestep.h +202 -0
- include/eigen3/unsupported/Eigen/src/LevenbergMarquardt/LMpar.h +160 -0
- include/eigen3/unsupported/Eigen/src/LevenbergMarquardt/LMqrsolv.h +188 -0
- include/eigen3/unsupported/Eigen/src/LevenbergMarquardt/LevenbergMarquardt.h +396 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +441 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +569 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/MatrixLogarithm.h +373 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h +705 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/MatrixSquareRoot.h +368 -0
- include/eigen3/unsupported/Eigen/src/MatrixFunctions/StemFunction.h +117 -0
- include/eigen3/unsupported/Eigen/src/MoreVectorization/MathFunctions.h +95 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +601 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +657 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/chkder.h +66 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/covar.h +70 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/dogleg.h +107 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/fdjac1.h +79 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/lmpar.h +298 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +91 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/r1mpyq.h +30 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/r1updt.h +99 -0
- include/eigen3/unsupported/Eigen/src/NonLinearOptimization/rwupdt.h +49 -0
- include/eigen3/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h +130 -0
- include/eigen3/unsupported/Eigen/src/Polynomials/Companion.h +280 -0
- include/eigen3/unsupported/Eigen/src/Polynomials/PolynomialSolver.h +428 -0
- include/eigen3/unsupported/Eigen/src/Polynomials/PolynomialUtils.h +143 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineInplaceLU.h +352 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineMatrix.h +862 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineMatrixBase.h +212 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineProduct.h +295 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineStorage.h +259 -0
- include/eigen3/unsupported/Eigen/src/Skyline/SkylineUtil.h +89 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/BlockOfDynamicSparseMatrix.h +122 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/BlockSparseMatrix.h +1079 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/DynamicSparseMatrix.h +404 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/MarketIO.h +282 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/MatrixMarketIterator.h +247 -0
- include/eigen3/unsupported/Eigen/src/SparseExtra/RandomSetter.h +349 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsArrayAPI.h +286 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsBFloat16.h +68 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsFunctors.h +357 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsHalf.h +66 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsImpl.h +1959 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/BesselFunctionsPacketMath.h +118 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/HipVectorCompatibility.h +67 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsArrayAPI.h +167 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsBFloat16.h +58 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsFunctors.h +330 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsHalf.h +58 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsImpl.h +2045 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/SpecialFunctionsPacketMath.h +79 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/AVX/BesselFunctions.h +46 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/AVX/SpecialFunctions.h +16 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/AVX512/BesselFunctions.h +46 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/AVX512/SpecialFunctions.h +16 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/GPU/SpecialFunctions.h +369 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/NEON/BesselFunctions.h +54 -0
- include/eigen3/unsupported/Eigen/src/SpecialFunctions/arch/NEON/SpecialFunctions.h +34 -0
- include/eigen3/unsupported/Eigen/src/Splines/Spline.h +507 -0
- include/eigen3/unsupported/Eigen/src/Splines/SplineFitting.h +431 -0
- include/eigen3/unsupported/Eigen/src/Splines/SplineFwd.h +93 -0
- qilisdk/__init__.py +26 -0
- qilisdk/__init__.pyi +16 -0
- qilisdk/_logging.py +135 -0
- qilisdk/_optionals.py +137 -0
- qilisdk/analog/__init__.py +18 -0
- qilisdk/analog/exceptions.py +17 -0
- qilisdk/analog/hamiltonian.py +1068 -0
- qilisdk/analog/schedule.py +483 -0
- qilisdk/backends/__init__.py +46 -0
- qilisdk/backends/__init__.pyi +18 -0
- qilisdk/backends/backend.py +132 -0
- qilisdk/backends/cuda_backend.py +752 -0
- qilisdk/backends/qilisim.py +148 -0
- qilisdk/backends/qutip_backend.py +504 -0
- qilisdk/core/__init__.py +70 -0
- qilisdk/core/exceptions.py +29 -0
- qilisdk/core/interpolator.py +640 -0
- qilisdk/core/model.py +1012 -0
- qilisdk/core/parameterizable.py +133 -0
- qilisdk/core/qtensor.py +684 -0
- qilisdk/core/result.py +18 -0
- qilisdk/core/types.py +49 -0
- qilisdk/core/variables.py +2035 -0
- qilisdk/cost_functions/__init__.py +18 -0
- qilisdk/cost_functions/cost_function.py +77 -0
- qilisdk/cost_functions/model_cost_function.py +152 -0
- qilisdk/cost_functions/observable_cost_function.py +112 -0
- qilisdk/digital/__init__.py +67 -0
- qilisdk/digital/ansatz.py +382 -0
- qilisdk/digital/circuit.py +371 -0
- qilisdk/digital/circuit_transpiler.py +46 -0
- qilisdk/digital/circuit_transpiler_passes/__init__.py +18 -0
- qilisdk/digital/circuit_transpiler_passes/circuit_transpiler_pass.py +36 -0
- qilisdk/digital/circuit_transpiler_passes/decompose_multi_controlled_gates_pass.py +220 -0
- qilisdk/digital/circuit_transpiler_passes/numeric_helpers.py +82 -0
- qilisdk/digital/exceptions.py +37 -0
- qilisdk/digital/gates.py +1308 -0
- qilisdk/experiments/__init__.py +36 -0
- qilisdk/experiments/experiment_functional.py +212 -0
- qilisdk/experiments/experiment_result.py +247 -0
- qilisdk/functionals/__init__.py +29 -0
- qilisdk/functionals/functional.py +39 -0
- qilisdk/functionals/functional_result.py +18 -0
- qilisdk/functionals/sampling.py +89 -0
- qilisdk/functionals/sampling_result.py +92 -0
- qilisdk/functionals/time_evolution.py +111 -0
- qilisdk/functionals/time_evolution_result.py +91 -0
- qilisdk/functionals/variational_program.py +138 -0
- qilisdk/functionals/variational_program_result.py +69 -0
- qilisdk/logging_config.yaml +16 -0
- qilisdk/noise/__init__.py +56 -0
- qilisdk/noise/amplitude_damping.py +71 -0
- qilisdk/noise/bit_flip.py +45 -0
- qilisdk/noise/dephasing.py +69 -0
- qilisdk/noise/depolarizing.py +44 -0
- qilisdk/noise/gaussian_perturbation.py +69 -0
- qilisdk/noise/noise.py +20 -0
- qilisdk/noise/noise_abc.py +31 -0
- qilisdk/noise/noise_config.py +77 -0
- qilisdk/noise/noise_model.py +259 -0
- qilisdk/noise/offset_perturbation.py +39 -0
- qilisdk/noise/parameter_perturbation.py +45 -0
- qilisdk/noise/pauli_channel.py +115 -0
- qilisdk/noise/phase_flip.py +45 -0
- qilisdk/noise/protocols.py +107 -0
- qilisdk/noise/readout_assignment.py +60 -0
- qilisdk/noise/representations.py +149 -0
- qilisdk/noise/utils.py +90 -0
- qilisdk/optimizers/__init__.py +17 -0
- qilisdk/optimizers/optimizer.py +39 -0
- qilisdk/optimizers/optimizer_result.py +101 -0
- qilisdk/optimizers/scipy_optimizer.py +118 -0
- qilisdk/py.typed +0 -0
- qilisdk/settings.py +103 -0
- qilisdk/speqtrum/__init__.py +41 -0
- qilisdk/speqtrum/__init__.pyi +18 -0
- qilisdk/speqtrum/keyring.py +58 -0
- qilisdk/speqtrum/speqtrum.py +817 -0
- qilisdk/speqtrum/speqtrum_models.py +560 -0
- qilisdk/utils/__init__.py +13 -0
- qilisdk/utils/openfermion/__init__.py +38 -0
- qilisdk/utils/openfermion/__init__.pyi +17 -0
- qilisdk/utils/openfermion/openfermion.py +45 -0
- qilisdk/utils/openqasm2.py +215 -0
- qilisdk/utils/serialization.py +128 -0
- qilisdk/utils/trotterization/__init__.py +18 -0
- qilisdk/utils/trotterization/trotterization.py +127 -0
- qilisdk/utils/visualization/PlusJakartaSans-SemiBold.ttf +0 -0
- qilisdk/utils/visualization/__init__.py +24 -0
- qilisdk/utils/visualization/circuit_renderers.py +781 -0
- qilisdk/utils/visualization/schedule_renderers.py +175 -0
- qilisdk/utils/visualization/style.py +154 -0
- qilisdk/utils/visualization/themes.py +76 -0
- qilisdk/yaml.py +260 -0
- qilisdk-0.1.8.dist-info/METADATA +657 -0
- qilisdk-0.1.8.dist-info/RECORD +635 -0
- qilisdk-0.1.8.dist-info/WHEEL +5 -0
- qilisdk-0.1.8.dist-info/licenses/LICENCE +201 -0
- qilisdk.libs/libgomp-24e2ab19.so.1.0.0 +0 -0
- qilisim_module.cpython-311-x86_64-linux-gnu.so +0 -0
- share/eigen3/cmake/Eigen3Config.cmake +37 -0
- share/eigen3/cmake/Eigen3ConfigVersion.cmake +65 -0
- share/eigen3/cmake/Eigen3Targets.cmake +106 -0
- share/eigen3/cmake/UseEigen3.cmake +6 -0
- share/pkgconfig/eigen3.pc +9 -0
|
@@ -0,0 +1,2035 @@
|
|
|
1
|
+
# Copyright 2025 Qilimanjaro Quantum Tech
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import copy
|
|
18
|
+
import re
|
|
19
|
+
from abc import ABC, abstractmethod
|
|
20
|
+
from typing import Iterator, Mapping, Sequence, TypeVar, cast, overload
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
from loguru import logger
|
|
24
|
+
|
|
25
|
+
from qilisdk.core.exceptions import EvaluationError, InvalidBoundsError, NotSupportedOperation, OutOfBoundsException
|
|
26
|
+
from qilisdk.settings import get_settings
|
|
27
|
+
from qilisdk.yaml import yaml
|
|
28
|
+
|
|
29
|
+
from .types import Number, QiliEnum, RealNumber
|
|
30
|
+
|
|
31
|
+
GenericVar = TypeVar("GenericVar", bound="Variable")
|
|
32
|
+
CONST_KEY = "_const_"
|
|
33
|
+
MAX_INT = np.iinfo(np.int64).max
|
|
34
|
+
MIN_INT = np.iinfo(np.int64).min
|
|
35
|
+
LARGE_BOUND = 100
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def LT(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
39
|
+
"""'Less Than' mathematical operation
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
43
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
ComparisonTerm: a comparison term with the structure lhs < rhs.
|
|
47
|
+
"""
|
|
48
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.LT)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
LessThan = LT
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def LEQ(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
55
|
+
"""'Less Than or equal to' mathematical operation
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
59
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
ComparisonTerm: a comparison term with the structure lhs <= rhs.
|
|
63
|
+
"""
|
|
64
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.LEQ)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
LessThanOrEqual = LEQ
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def EQ(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
71
|
+
"""'Equal to' mathematical operation
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
75
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
ComparisonTerm: a comparison term with the structure lhs == rhs.
|
|
79
|
+
"""
|
|
80
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.EQ)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
Equal = EQ
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def NEQ(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
87
|
+
"""'Not Equal to' mathematical operation
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
91
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
ComparisonTerm: a comparison term with the structure lhs != rhs.
|
|
95
|
+
"""
|
|
96
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.NEQ)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
NotEqual = NEQ
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def GT(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
103
|
+
"""'Greater Than' mathematical operation
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
107
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
ComparisonTerm: a comparison term with the structure lhs > rhs.
|
|
111
|
+
"""
|
|
112
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.GT)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
GreaterThan = GT
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def GEQ(lhs: RealNumber | BaseVariable | Term, rhs: RealNumber | BaseVariable | Term) -> ComparisonTerm:
|
|
119
|
+
"""'Greater Than or equal to' mathematical operation
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
123
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
ComparisonTerm: a comparison term with the structure lhs >= rhs.
|
|
127
|
+
"""
|
|
128
|
+
return ComparisonTerm(lhs=lhs, rhs=rhs, operation=ComparisonOperation.GEQ)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
GreaterThanOrEqual = GEQ
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _extract_number(label: str) -> int:
|
|
135
|
+
"""
|
|
136
|
+
Extracts the number from the variable's label.
|
|
137
|
+
Note that this only matches positive integers.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
label (str): variable label that follows the format <label>(<number>).
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
int: the number in the label.
|
|
144
|
+
"""
|
|
145
|
+
pattern = re.compile(r"\((\d+)\)$")
|
|
146
|
+
matches = pattern.search(label)
|
|
147
|
+
if matches is not None:
|
|
148
|
+
return int(matches.group(1))
|
|
149
|
+
return 0
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _float_if_real(value: Number) -> Number:
|
|
153
|
+
if isinstance(value, RealNumber):
|
|
154
|
+
return value
|
|
155
|
+
if isinstance(value, complex) and abs(value.imag) < get_settings().atol:
|
|
156
|
+
return value.real
|
|
157
|
+
return value
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _assert_real(value: Number) -> RealNumber:
|
|
161
|
+
_value = _float_if_real(value)
|
|
162
|
+
if isinstance(_value, RealNumber):
|
|
163
|
+
return _value
|
|
164
|
+
raise ValueError(f"Only Real values are allowed but {_value} was provided.")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@yaml.register_class(shared=True)
|
|
168
|
+
class Domain(QiliEnum):
|
|
169
|
+
INTEGER = "Integer Domain"
|
|
170
|
+
POSITIVE_INTEGER = "Positive Integer Domain"
|
|
171
|
+
REAL = "Real Domain"
|
|
172
|
+
BINARY = "Binary Domain"
|
|
173
|
+
SPIN = "Spin Domain"
|
|
174
|
+
|
|
175
|
+
def check_value(self, value: Number) -> bool:
|
|
176
|
+
"""checks if the provided value is valid for a given domain
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
value (int | float): the value to be evaluated.
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
bool: True if the value provided is valid, False otherwise.
|
|
183
|
+
"""
|
|
184
|
+
if self == Domain.BINARY:
|
|
185
|
+
return isinstance(value, Number) and value in {0, 1}
|
|
186
|
+
if self == Domain.SPIN:
|
|
187
|
+
return isinstance(value, Number) and value in {-1, 1}
|
|
188
|
+
if self == Domain.REAL:
|
|
189
|
+
return isinstance(value, (int, float))
|
|
190
|
+
if self == Domain.INTEGER:
|
|
191
|
+
return isinstance(value, int)
|
|
192
|
+
if self == Domain.POSITIVE_INTEGER:
|
|
193
|
+
return isinstance(value, int) and value >= 0
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
def min(self) -> float:
|
|
197
|
+
"""
|
|
198
|
+
Returns:
|
|
199
|
+
float: the minimum value allowed of a given domain.
|
|
200
|
+
"""
|
|
201
|
+
if self in {Domain.BINARY, Domain.POSITIVE_INTEGER}:
|
|
202
|
+
return 0
|
|
203
|
+
if self == Domain.SPIN:
|
|
204
|
+
return -1
|
|
205
|
+
if self == Domain.INTEGER:
|
|
206
|
+
return MIN_INT
|
|
207
|
+
return -1e30
|
|
208
|
+
|
|
209
|
+
def max(self) -> float:
|
|
210
|
+
"""
|
|
211
|
+
Returns:
|
|
212
|
+
float: the maximum value allowed for a given domain.
|
|
213
|
+
"""
|
|
214
|
+
if self in {Domain.BINARY, Domain.SPIN}:
|
|
215
|
+
return 1
|
|
216
|
+
if self in {Domain.POSITIVE_INTEGER, Domain.INTEGER}:
|
|
217
|
+
return MAX_INT
|
|
218
|
+
return 1e30
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
@yaml.register_class
|
|
222
|
+
class Operation(QiliEnum):
|
|
223
|
+
MUL = "*"
|
|
224
|
+
ADD = "+"
|
|
225
|
+
DIV = "/"
|
|
226
|
+
SUB = "-"
|
|
227
|
+
MATH_MAP = "mathematical_map"
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@yaml.register_class
|
|
231
|
+
class ComparisonOperation(QiliEnum):
|
|
232
|
+
LT = "<"
|
|
233
|
+
LEQ = "<="
|
|
234
|
+
EQ = "=="
|
|
235
|
+
NEQ = "!="
|
|
236
|
+
GT = ">"
|
|
237
|
+
GEQ = ">="
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@yaml.register_class
|
|
241
|
+
class Encoding(ABC):
|
|
242
|
+
"""Represents an abstract variable encoding class.
|
|
243
|
+
|
|
244
|
+
The Encoding is defined on the variable bases, and it defines how the continuous variables are encoded into binary
|
|
245
|
+
variables.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
@abstractmethod
|
|
250
|
+
def name(self) -> str:
|
|
251
|
+
"""Encoding's name
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
str: The name of the encoding.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
@staticmethod
|
|
258
|
+
@abstractmethod
|
|
259
|
+
def encode(var: Variable, precision: float = 1e-2) -> Term:
|
|
260
|
+
"""Given a continuous variable return a Term that only consists of
|
|
261
|
+
binary variables that represent the continuous variable in the given encoding.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
var (ContinuousVar): The continuous variable to be encoded
|
|
265
|
+
precision (int): the precision to be considered for real variables (Only applies if
|
|
266
|
+
the variable domain is Domain.Real)
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Term: a term that only contains binary variables
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
@staticmethod
|
|
273
|
+
@abstractmethod
|
|
274
|
+
def encoding_constraint(var: Variable, precision: float = 1e-2) -> ComparisonTerm:
|
|
275
|
+
"""Given a continuous variable return a Constraint Term that ensures that the encoding is respected.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
var (ContinuousVar): The continuous variable to be encoded
|
|
279
|
+
precision (float): the precision to be considered for real variables (Only applies if
|
|
280
|
+
the variable domain is Domain.Real)
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
Constraint Term: a constraint term that ensures the encoding is respected.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
@staticmethod
|
|
287
|
+
@abstractmethod
|
|
288
|
+
def evaluate(var: Variable, value: list[int] | int, precision: float = 1e-2) -> float:
|
|
289
|
+
"""Given a binary string, evaluate the value of the continuous variable in the given encoding.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
var (ContinuousVar): the variable to be evaluated
|
|
293
|
+
value (list[int] | int): a list of binary values or an integer value.
|
|
294
|
+
precision (float): the precision to be considered for real variables (Only applies if
|
|
295
|
+
the variable domain is Domain.Real)
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
float: the value of the continuous variable given the specified binary values.
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
@staticmethod
|
|
302
|
+
@abstractmethod
|
|
303
|
+
def num_binary_equivalent(var: "Variable", precision: float = 1e-2) -> int:
|
|
304
|
+
"""Give a continuous variable return the number of binary variables needed to encode it.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
var (ContinuousVar): the continuous variable.
|
|
308
|
+
precision (float): the precision to be considered for real variables (Only applies if
|
|
309
|
+
the variable domain is Domain.Real)
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
int: the number of binary variables needed to encode it.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
@staticmethod
|
|
316
|
+
@abstractmethod
|
|
317
|
+
def check_valid(value: list[int] | int) -> tuple[bool, int]:
|
|
318
|
+
"""checks if the binary list sample is a valid sample in this encoding.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
value (list[int] | int): a list of binary values or an integer value.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
tuple[bool, int]: the boolean is True if the sample is a valid encoding,
|
|
325
|
+
while the int is the error in the encoding.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _check_output(var: Variable, output: Number) -> RealNumber:
|
|
330
|
+
"""Parse the output of an eval, converting it to a real number if possible and ensuring it is within the variable's domain.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
var (Variable): The variable for which the output is being parsed.
|
|
334
|
+
output (Number): The number to be parsed.
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
Number: The output as a valid number within the variable's domain.
|
|
338
|
+
|
|
339
|
+
Raises:
|
|
340
|
+
ValueError: If the output is not a valid real number.
|
|
341
|
+
"""
|
|
342
|
+
if isinstance(output, RealNumber):
|
|
343
|
+
out = float(output)
|
|
344
|
+
elif isinstance(output, complex) and abs(output.imag) < get_settings().atol:
|
|
345
|
+
out = float(output.real)
|
|
346
|
+
else:
|
|
347
|
+
raise ValueError(f"Evaluation answer ({output}) is outside the variable domain ({var.domain}).")
|
|
348
|
+
|
|
349
|
+
out = int(out) if var.domain in {Domain.INTEGER, Domain.POSITIVE_INTEGER} else out
|
|
350
|
+
|
|
351
|
+
if not var.domain.check_value(out):
|
|
352
|
+
raise ValueError(f"The value {out} violates the domain {var.domain.__class__.__name__} of the variable {var}")
|
|
353
|
+
|
|
354
|
+
return out
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@yaml.register_class
|
|
358
|
+
class Bitwise(Encoding):
|
|
359
|
+
"""Represents a Bitwise variable encoding class."""
|
|
360
|
+
|
|
361
|
+
name = "Bitwise"
|
|
362
|
+
|
|
363
|
+
@staticmethod
|
|
364
|
+
def _bitwise_encode(x: int, N: int) -> list[int]:
|
|
365
|
+
"""encode the integer x in Bitwise encoding.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
x (int): the integer to be encoded.
|
|
369
|
+
N (int): the number of bits to encode x.
|
|
370
|
+
|
|
371
|
+
Returns:
|
|
372
|
+
list[int]: a binary list representing the Bitwise encoding of the integer x.
|
|
373
|
+
"""
|
|
374
|
+
return list(reversed([int(b) for b in format(x, f"0{N}b")]))
|
|
375
|
+
|
|
376
|
+
@staticmethod
|
|
377
|
+
def encode(var: Variable, precision: float = 1e-2) -> Term:
|
|
378
|
+
bounds = var.bounds
|
|
379
|
+
if var.domain is Domain.REAL:
|
|
380
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
381
|
+
|
|
382
|
+
abs_bound = np.abs(bounds[1] - bounds[0])
|
|
383
|
+
n_binary = int(np.floor(np.log2(abs_bound if abs_bound != 0 else 1)))
|
|
384
|
+
binary_vars = [BinaryVariable(var.label + f"({i})") for i in range(n_binary + 1)]
|
|
385
|
+
|
|
386
|
+
term = sum(2**i * binary_vars[i] for i in range(n_binary))
|
|
387
|
+
term += (np.abs(bounds[1] - bounds[0]) + 1 - 2**n_binary) * binary_vars[-1]
|
|
388
|
+
term += bounds[0]
|
|
389
|
+
return term * var.precision if var.domain is Domain.REAL else term
|
|
390
|
+
|
|
391
|
+
@staticmethod
|
|
392
|
+
def evaluate(var: Variable, value: list[int] | int, precision: float = 1e-2) -> float:
|
|
393
|
+
term = Bitwise.encode(var, precision)
|
|
394
|
+
binary_var = sorted(
|
|
395
|
+
term.variables(),
|
|
396
|
+
key=lambda x: _extract_number(x.label),
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
binary_list = Bitwise._bitwise_encode(value, len(binary_var)) if isinstance(value, Number) else value
|
|
400
|
+
|
|
401
|
+
if not Bitwise.check_valid(binary_list)[0]:
|
|
402
|
+
raise ValueError(
|
|
403
|
+
f"invalid binary string {binary_list} with the Bitwise encoding."
|
|
404
|
+
) # can not be reached in the case of Bitwise encoding.
|
|
405
|
+
|
|
406
|
+
if len(binary_list) < len(binary_var):
|
|
407
|
+
for _ in range(len(binary_var) - len(binary_list)):
|
|
408
|
+
binary_list.append(0)
|
|
409
|
+
elif len(binary_list) != len(binary_var):
|
|
410
|
+
raise ValueError(f"expected {len(binary_var)} variables but received {len(binary_list)}")
|
|
411
|
+
|
|
412
|
+
binary_dict: dict[BaseVariable, list[int]] = {binary_var[i]: [binary_list[i]] for i in range(len(binary_list))}
|
|
413
|
+
|
|
414
|
+
_out = term.evaluate(binary_dict)
|
|
415
|
+
out = _check_output(var, _out)
|
|
416
|
+
|
|
417
|
+
return out
|
|
418
|
+
|
|
419
|
+
@staticmethod
|
|
420
|
+
def encoding_constraint(var: Variable, precision: float = 1e-2) -> ComparisonTerm:
|
|
421
|
+
raise NotImplementedError("Bitwise encoding constraints are not supported at the moment")
|
|
422
|
+
|
|
423
|
+
@staticmethod
|
|
424
|
+
def num_binary_equivalent(var: "Variable", precision: float = 1e-2) -> int:
|
|
425
|
+
bounds = var.bounds
|
|
426
|
+
if var.domain is Domain.REAL:
|
|
427
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
428
|
+
|
|
429
|
+
n_binary = int(np.floor(np.log2(np.abs(bounds[1] - bounds[0]))))
|
|
430
|
+
|
|
431
|
+
return n_binary + 1
|
|
432
|
+
|
|
433
|
+
@staticmethod
|
|
434
|
+
def check_valid(value: list[int] | int) -> tuple[bool, int]:
|
|
435
|
+
return True, 0
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
@yaml.register_class
|
|
439
|
+
class OneHot(Encoding):
|
|
440
|
+
"""Represents a One-Hot variable encoding class."""
|
|
441
|
+
|
|
442
|
+
name = "One-Hot"
|
|
443
|
+
|
|
444
|
+
@staticmethod
|
|
445
|
+
def _one_hot_encode(x: int, N: int) -> list[int]:
|
|
446
|
+
"""One-hot encode integer x in range [0, N-1].
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
x (int): the value to be encoded
|
|
450
|
+
N (int): the number of bits to encode x.
|
|
451
|
+
|
|
452
|
+
Raises:
|
|
453
|
+
ValueError: if x is larger than N or less than 0
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
list[int]: a binary list representing the one hot encoding of the integer x.
|
|
457
|
+
"""
|
|
458
|
+
if not (0 <= x < N):
|
|
459
|
+
raise ValueError(f"the input value ({x}) must be in range [0, {N - 1}]")
|
|
460
|
+
return [1 if i == x else 0 for i in range(N)]
|
|
461
|
+
|
|
462
|
+
@staticmethod
|
|
463
|
+
def _find_zero(var: Variable) -> int:
|
|
464
|
+
binary_var = var.bin_vars
|
|
465
|
+
term = var.term
|
|
466
|
+
for i in range(var.num_binary_equivalent()):
|
|
467
|
+
if binary_var[i] not in term:
|
|
468
|
+
return i
|
|
469
|
+
return 0
|
|
470
|
+
|
|
471
|
+
@staticmethod
|
|
472
|
+
def encode(var: Variable, precision: float = 1e-2) -> Term:
|
|
473
|
+
bounds = var.bounds
|
|
474
|
+
if var.domain is Domain.REAL:
|
|
475
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
476
|
+
|
|
477
|
+
n_binary = int(np.abs(bounds[1] - bounds[0])) + 1
|
|
478
|
+
|
|
479
|
+
binary_vars = [BinaryVariable(var.label + f"({i})") for i in range(n_binary)]
|
|
480
|
+
|
|
481
|
+
term = Term([(bounds[0] + i) * binary_vars[i] for i in range(n_binary)], Operation.ADD)
|
|
482
|
+
|
|
483
|
+
return term * var.precision if var.domain is Domain.REAL else term
|
|
484
|
+
|
|
485
|
+
@staticmethod
|
|
486
|
+
def evaluate(var: Variable, value: list[int] | int, precision: float = 1e-2) -> float:
|
|
487
|
+
term = OneHot.encode(var, precision)
|
|
488
|
+
binary_var = sorted(
|
|
489
|
+
term.variables(),
|
|
490
|
+
key=lambda x: _extract_number(x.label),
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
binary_list = OneHot._one_hot_encode(value, len(binary_var) + 1) if isinstance(value, int) else value
|
|
494
|
+
|
|
495
|
+
if not OneHot.check_valid(binary_list)[0]:
|
|
496
|
+
raise ValueError(f"invalid binary string {binary_list} with the one hot encoding.")
|
|
497
|
+
|
|
498
|
+
# after encoding we will have one less variable than the binary list, because the first variable is multiplied
|
|
499
|
+
# by 0 so it is removed from the term.
|
|
500
|
+
if len(binary_list) < len(binary_var) + 1:
|
|
501
|
+
for _ in range(len(binary_var) - len(binary_list) + 1):
|
|
502
|
+
binary_list.append(0)
|
|
503
|
+
elif len(binary_list) != len(binary_var) + 1:
|
|
504
|
+
raise ValueError(f"expected {len(binary_var) + 1} variables but received {len(binary_list)}")
|
|
505
|
+
|
|
506
|
+
zero_index = OneHot._find_zero(var)
|
|
507
|
+
binary_dict: dict[BaseVariable, list[int]] = {}
|
|
508
|
+
for i in range(var.num_binary_equivalent()):
|
|
509
|
+
if i < zero_index:
|
|
510
|
+
binary_dict[binary_var[i]] = [binary_list[i]]
|
|
511
|
+
if i > zero_index:
|
|
512
|
+
binary_dict[binary_var[i - 1]] = [binary_list[i]]
|
|
513
|
+
|
|
514
|
+
_out = term.evaluate(binary_dict)
|
|
515
|
+
out = _check_output(var, _out)
|
|
516
|
+
|
|
517
|
+
return out
|
|
518
|
+
|
|
519
|
+
@staticmethod
|
|
520
|
+
def encoding_constraint(var: Variable, precision: float = 1e-2) -> ComparisonTerm:
|
|
521
|
+
bounds = var.bounds
|
|
522
|
+
if var.domain is Domain.REAL:
|
|
523
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
524
|
+
|
|
525
|
+
n_binary = int(np.abs(bounds[1] - bounds[0])) + 1
|
|
526
|
+
|
|
527
|
+
binary_vars = [BinaryVariable(var.label + f"({i})") for i in range(n_binary)]
|
|
528
|
+
return ComparisonTerm(lhs=sum(binary_vars), rhs=1, operation=ComparisonOperation.EQ)
|
|
529
|
+
|
|
530
|
+
@staticmethod
|
|
531
|
+
def num_binary_equivalent(var: Variable, precision: float = 1e-2) -> int:
|
|
532
|
+
bounds = var.bounds
|
|
533
|
+
if var.domain is Domain.REAL:
|
|
534
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
535
|
+
|
|
536
|
+
n_binary = int(np.abs(bounds[1] - bounds[0])) + 1
|
|
537
|
+
|
|
538
|
+
return n_binary
|
|
539
|
+
|
|
540
|
+
@staticmethod
|
|
541
|
+
def check_valid(value: list[int] | int) -> tuple[bool, int]:
|
|
542
|
+
binary_list = OneHot._one_hot_encode(value, value) if isinstance(value, int) else value
|
|
543
|
+
num_ones = binary_list.count(1)
|
|
544
|
+
return num_ones == 1, (num_ones - 1) ** 2
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
@yaml.register_class
|
|
548
|
+
class DomainWall(Encoding):
|
|
549
|
+
"""Represents a Domain-wall variable encoding class."""
|
|
550
|
+
|
|
551
|
+
name = "Domain Wall"
|
|
552
|
+
|
|
553
|
+
@staticmethod
|
|
554
|
+
def _domain_wall_encode(x: int, N: int) -> list[int]:
|
|
555
|
+
"""domain wall encode integer x in range [0, N-1].
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
x (int): the value to be encoded
|
|
559
|
+
N (int): the number of bits to encode x.
|
|
560
|
+
|
|
561
|
+
Raises:
|
|
562
|
+
ValueError: if x is larger than N or less than 0
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
list[int]: a binary list representing the domain wall encoding of the integer x.
|
|
566
|
+
"""
|
|
567
|
+
if not (0 <= x <= N):
|
|
568
|
+
raise ValueError(f"the input value ({x}) must be in range [0, {N}]")
|
|
569
|
+
return [1] * x + [0] * (N - x)
|
|
570
|
+
|
|
571
|
+
@staticmethod
|
|
572
|
+
def encode(var: Variable, precision: float = 1e-2) -> Term:
|
|
573
|
+
bounds = var.bounds
|
|
574
|
+
if var.domain is Domain.REAL:
|
|
575
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
576
|
+
|
|
577
|
+
n_binary = int(np.abs(bounds[1] - bounds[0]))
|
|
578
|
+
|
|
579
|
+
binary_vars = [BinaryVariable(var.label + f"({i})") for i in range(n_binary)]
|
|
580
|
+
|
|
581
|
+
term = Term([0], Operation.ADD)
|
|
582
|
+
for i in range(n_binary):
|
|
583
|
+
term += binary_vars[i]
|
|
584
|
+
|
|
585
|
+
term += bounds[0]
|
|
586
|
+
|
|
587
|
+
return term * var.precision if var.domain is Domain.REAL else term
|
|
588
|
+
|
|
589
|
+
@staticmethod
|
|
590
|
+
def evaluate(var: Variable, value: list[int] | int, precision: float = 1e-2) -> float:
|
|
591
|
+
term = DomainWall.encode(var, precision)
|
|
592
|
+
binary_var = term.variables()
|
|
593
|
+
binary_var = sorted(
|
|
594
|
+
term.variables(),
|
|
595
|
+
key=lambda x: _extract_number(x.label),
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
binary_list: list[int] = (
|
|
599
|
+
DomainWall._domain_wall_encode(value, len(binary_var)) if isinstance(value, RealNumber) else value
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
if not DomainWall.check_valid(binary_list)[0]:
|
|
603
|
+
raise ValueError(f"invalid binary string {binary_list} with the domain wall encoding.")
|
|
604
|
+
|
|
605
|
+
if len(binary_list) < len(binary_var):
|
|
606
|
+
for _ in range(len(binary_var) - len(binary_list)):
|
|
607
|
+
binary_list.append(0)
|
|
608
|
+
elif len(binary_list) != len(binary_var):
|
|
609
|
+
raise ValueError(f"expected {len(binary_var)} variables but received {len(binary_list)}")
|
|
610
|
+
|
|
611
|
+
binary_dict: dict[BaseVariable, list[int]] = {binary_var[i]: [binary_list[i]] for i in range(len(binary_list))}
|
|
612
|
+
|
|
613
|
+
_out = term.evaluate(binary_dict)
|
|
614
|
+
out = _check_output(var, _out)
|
|
615
|
+
|
|
616
|
+
return out
|
|
617
|
+
|
|
618
|
+
@staticmethod
|
|
619
|
+
def encoding_constraint(var: Variable, precision: float = 1e-2) -> ComparisonTerm:
|
|
620
|
+
bounds = var.bounds
|
|
621
|
+
if var.domain is Domain.REAL:
|
|
622
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
623
|
+
|
|
624
|
+
n_binary = int(np.abs(bounds[1] - bounds[0]))
|
|
625
|
+
|
|
626
|
+
binary_vars = [BinaryVariable(var.label + f"({i})") for i in range(n_binary)]
|
|
627
|
+
return ComparisonTerm(
|
|
628
|
+
lhs=sum(binary_vars[i + 1] * (1 - binary_vars[i]) for i in range(len(binary_vars) - 1)),
|
|
629
|
+
rhs=0,
|
|
630
|
+
operation=ComparisonOperation.EQ,
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
@staticmethod
|
|
634
|
+
def num_binary_equivalent(var: Variable, precision: float = 1e-2) -> int:
|
|
635
|
+
bounds = var.bounds
|
|
636
|
+
if var.domain is Domain.REAL:
|
|
637
|
+
bounds = (bounds[0] / precision, bounds[1] / precision)
|
|
638
|
+
|
|
639
|
+
n_binary = int(np.abs(bounds[1] - bounds[0]))
|
|
640
|
+
|
|
641
|
+
return n_binary
|
|
642
|
+
|
|
643
|
+
@staticmethod
|
|
644
|
+
def check_valid(value: list[int] | int) -> tuple[bool, int]:
|
|
645
|
+
binary_list = DomainWall._domain_wall_encode(value, value) if isinstance(value, int) else value
|
|
646
|
+
value = sum(binary_list[i + 1] * (1 - binary_list[i]) for i in range(len(binary_list) - 1))
|
|
647
|
+
return value == 0, value
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
# Variables ###
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
class BaseVariable(ABC):
|
|
654
|
+
"""
|
|
655
|
+
Abstract base class for symbolic decision variables.
|
|
656
|
+
"""
|
|
657
|
+
|
|
658
|
+
TOL = get_settings().atol
|
|
659
|
+
|
|
660
|
+
def __init__(self, label: str, domain: Domain, bounds: tuple[float | None, float | None] = (None, None)) -> None:
|
|
661
|
+
"""initialize a new Variable object
|
|
662
|
+
|
|
663
|
+
Args:
|
|
664
|
+
label (str): The name of the variable.
|
|
665
|
+
domain (Domain): The domain of the values this variable can take.
|
|
666
|
+
bounds (tuple[float | None, float | None], optional): the bounds on the variable's values.
|
|
667
|
+
The bounds follow the structure (lower_bound, Upper_bound) both
|
|
668
|
+
included. Defaults to (None, None).
|
|
669
|
+
Note: if None is selected then the lowest/highest possible value of the
|
|
670
|
+
variable's domain is chosen.
|
|
671
|
+
|
|
672
|
+
Raises:
|
|
673
|
+
OutOfBoundsException: the lower bound or the upper bound don't correspond to the variable domain.
|
|
674
|
+
InvalidBoundsError: the lower bound is higher than the upper bound.
|
|
675
|
+
"""
|
|
676
|
+
self._label = label
|
|
677
|
+
self._domain = domain
|
|
678
|
+
|
|
679
|
+
lower_bound, upper_bound = bounds
|
|
680
|
+
if lower_bound is None:
|
|
681
|
+
lower_bound = domain.min()
|
|
682
|
+
if upper_bound is None:
|
|
683
|
+
upper_bound = domain.max()
|
|
684
|
+
|
|
685
|
+
if not self.domain.check_value(upper_bound):
|
|
686
|
+
raise OutOfBoundsException(
|
|
687
|
+
f"the upper bound ({upper_bound}) does not respect the domain of the variable ({self.domain})"
|
|
688
|
+
)
|
|
689
|
+
if not self.domain.check_value(lower_bound):
|
|
690
|
+
raise OutOfBoundsException(
|
|
691
|
+
f"the lower bound ({lower_bound}) does not respect the domain of the variable ({self.domain})"
|
|
692
|
+
)
|
|
693
|
+
if lower_bound > upper_bound:
|
|
694
|
+
raise InvalidBoundsError("lower bound can't be larger than the upper bound.")
|
|
695
|
+
self._bounds = (lower_bound, upper_bound)
|
|
696
|
+
self._hash_cache: int | None = None
|
|
697
|
+
|
|
698
|
+
@property
|
|
699
|
+
def bounds(self) -> tuple[float, float]:
|
|
700
|
+
"""Property that stores a tuple representing the bounds of the values a variable is allowed to take.º
|
|
701
|
+
|
|
702
|
+
Returns:
|
|
703
|
+
tuple(float, float): The lower and upper bound of the variable.
|
|
704
|
+
"""
|
|
705
|
+
return self._bounds
|
|
706
|
+
|
|
707
|
+
@property
|
|
708
|
+
def lower_bound(self) -> float:
|
|
709
|
+
"""The lower bound of the variable.
|
|
710
|
+
|
|
711
|
+
Returns:
|
|
712
|
+
float: the value of the lower bound.
|
|
713
|
+
"""
|
|
714
|
+
return self._bounds[0]
|
|
715
|
+
|
|
716
|
+
@property
|
|
717
|
+
def upper_bound(self) -> float:
|
|
718
|
+
"""The upper bound of the variable.
|
|
719
|
+
|
|
720
|
+
Returns:
|
|
721
|
+
float: the value of the upper bound.
|
|
722
|
+
"""
|
|
723
|
+
return self._bounds[1]
|
|
724
|
+
|
|
725
|
+
@property
|
|
726
|
+
def label(self) -> str:
|
|
727
|
+
"""the label (name) of the variable.
|
|
728
|
+
|
|
729
|
+
Returns:
|
|
730
|
+
string: the name of the variable.
|
|
731
|
+
"""
|
|
732
|
+
return self._label
|
|
733
|
+
|
|
734
|
+
@property
|
|
735
|
+
def domain(self) -> Domain:
|
|
736
|
+
"""The domain of values that the variable is allowed to take.
|
|
737
|
+
|
|
738
|
+
Returns:
|
|
739
|
+
Domain: The domain of the values the variable can take.
|
|
740
|
+
"""
|
|
741
|
+
return self._domain
|
|
742
|
+
|
|
743
|
+
def set_bounds(self, lower_bound: float | None, upper_bound: float | None) -> None:
|
|
744
|
+
"""set the bounds of the variable.
|
|
745
|
+
|
|
746
|
+
Args:
|
|
747
|
+
lower_bound (float | None): The lower bound (if None the lowest allowed bound in the variable domain is
|
|
748
|
+
selected). Defaults to None.
|
|
749
|
+
upper_bound (float | None): The upper bound (if None the highest allowed bound in the variable domain is
|
|
750
|
+
selected). Defaults to None.
|
|
751
|
+
Raises:
|
|
752
|
+
OutOfBoundsException: the lower bound or the upper bound don't correspond to the variable domain.
|
|
753
|
+
InvalidBoundsError: the lower bound is higher than the upper bound.
|
|
754
|
+
"""
|
|
755
|
+
self._hash_cache = None
|
|
756
|
+
if lower_bound is None:
|
|
757
|
+
lower_bound = self._domain.min()
|
|
758
|
+
if upper_bound is None:
|
|
759
|
+
upper_bound = self._domain.max()
|
|
760
|
+
if not self.domain.check_value(lower_bound):
|
|
761
|
+
raise OutOfBoundsException(
|
|
762
|
+
f"the lower bound ({lower_bound}) does not respect the domain of the variable ({self.domain})"
|
|
763
|
+
)
|
|
764
|
+
if not self.domain.check_value(upper_bound):
|
|
765
|
+
raise OutOfBoundsException(
|
|
766
|
+
f"the upper bound ({upper_bound}) does not respect the domain of the variable ({self.domain})"
|
|
767
|
+
)
|
|
768
|
+
if lower_bound > upper_bound:
|
|
769
|
+
raise InvalidBoundsError(
|
|
770
|
+
f"the lower bound ({lower_bound}) should not be greater than the upper bound ({upper_bound})"
|
|
771
|
+
)
|
|
772
|
+
self._bounds = (lower_bound, upper_bound)
|
|
773
|
+
|
|
774
|
+
@abstractmethod
|
|
775
|
+
def num_binary_equivalent(self) -> int:
|
|
776
|
+
"""
|
|
777
|
+
Returns:
|
|
778
|
+
int: the number of binary variables that are needed to represent this variable in the given encoding.
|
|
779
|
+
"""
|
|
780
|
+
|
|
781
|
+
@abstractmethod
|
|
782
|
+
def evaluate(self, value: list[int] | RealNumber) -> RealNumber:
|
|
783
|
+
"""Evaluates the value of the variable given a binary string or a number.
|
|
784
|
+
|
|
785
|
+
Args:
|
|
786
|
+
value (list[int] | int | float): the value used to evaluate the variable.
|
|
787
|
+
If the value provided is binary list (list[int]) then the value of the variable is evaluated based on
|
|
788
|
+
its binary representation. This representation is constructed using the encoding, bounds and domain
|
|
789
|
+
of the variable. To check the binary representation of a variable you can check the method `to_binary()`
|
|
790
|
+
|
|
791
|
+
Returns:
|
|
792
|
+
int | float | complex: the evaluated vale of the variable.
|
|
793
|
+
"""
|
|
794
|
+
|
|
795
|
+
def update_variable(self, domain: Domain, bounds: tuple[float | None, float | None] = (None, None)) -> None:
|
|
796
|
+
"""Replaces the information of the variable with those coming from the dictionary
|
|
797
|
+
if the variable label is in the dictionary
|
|
798
|
+
|
|
799
|
+
Args:
|
|
800
|
+
domain (Domain): The updated domain of the variable.
|
|
801
|
+
bounds (tuple[float | None, float | None]): The updated bounds of the variable. Defaults to (None, None)
|
|
802
|
+
"""
|
|
803
|
+
self._hash_cache = None
|
|
804
|
+
self._domain = domain
|
|
805
|
+
self.set_bounds(bounds[0], bounds[1])
|
|
806
|
+
|
|
807
|
+
@abstractmethod
|
|
808
|
+
def to_binary(self) -> Term:
|
|
809
|
+
"""Returns the binary representation of a variable.
|
|
810
|
+
|
|
811
|
+
Returns:
|
|
812
|
+
Term: the binary representation of a variable.
|
|
813
|
+
"""
|
|
814
|
+
|
|
815
|
+
def __repr__(self) -> str:
|
|
816
|
+
return f"{self._label}"
|
|
817
|
+
|
|
818
|
+
def __str__(self) -> str:
|
|
819
|
+
return f"{self._label}"
|
|
820
|
+
|
|
821
|
+
def __add__(self, other: Number | BaseVariable | Term) -> Term:
|
|
822
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
823
|
+
return NotImplemented
|
|
824
|
+
if isinstance(other, Term):
|
|
825
|
+
return other + self
|
|
826
|
+
|
|
827
|
+
if isinstance(other, np.generic):
|
|
828
|
+
other = cast("Number", other.item())
|
|
829
|
+
|
|
830
|
+
return Term(elements=[self, other], operation=Operation.ADD)
|
|
831
|
+
|
|
832
|
+
__radd__ = __add__
|
|
833
|
+
__iadd__ = __add__
|
|
834
|
+
|
|
835
|
+
def __mul__(self, other: Number | BaseVariable | Term) -> Term:
|
|
836
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
837
|
+
return NotImplemented
|
|
838
|
+
if isinstance(other, Term):
|
|
839
|
+
return other * self
|
|
840
|
+
|
|
841
|
+
if isinstance(other, np.generic):
|
|
842
|
+
other = cast("Number", other.item())
|
|
843
|
+
|
|
844
|
+
return Term(elements=[self, other], operation=Operation.MUL)
|
|
845
|
+
|
|
846
|
+
def __rmul__(self, other: Number | BaseVariable | Term) -> Term:
|
|
847
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
848
|
+
return NotImplemented
|
|
849
|
+
if isinstance(other, Term):
|
|
850
|
+
return other * self
|
|
851
|
+
|
|
852
|
+
if isinstance(other, np.generic):
|
|
853
|
+
other = cast("Number", other.item())
|
|
854
|
+
|
|
855
|
+
return Term(elements=[other, self], operation=Operation.MUL)
|
|
856
|
+
|
|
857
|
+
__imul__ = __mul__
|
|
858
|
+
|
|
859
|
+
def __sub__(self, other: Number | BaseVariable | Term) -> Term:
|
|
860
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
861
|
+
return NotImplemented
|
|
862
|
+
|
|
863
|
+
if isinstance(other, np.generic):
|
|
864
|
+
other = cast("Number", other.item())
|
|
865
|
+
|
|
866
|
+
return self + -1 * other
|
|
867
|
+
|
|
868
|
+
def __rsub__(self, other: Number | BaseVariable | Term) -> Term:
|
|
869
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
870
|
+
return NotImplemented
|
|
871
|
+
|
|
872
|
+
if isinstance(other, np.generic):
|
|
873
|
+
other = cast("Number", other.item())
|
|
874
|
+
|
|
875
|
+
return -1 * self + other
|
|
876
|
+
|
|
877
|
+
__isub__ = __sub__
|
|
878
|
+
|
|
879
|
+
def __neg__(self) -> Term:
|
|
880
|
+
return -1 * self
|
|
881
|
+
|
|
882
|
+
def __truediv__(self, other: RealNumber) -> Term:
|
|
883
|
+
if not isinstance(other, RealNumber):
|
|
884
|
+
raise NotImplementedError("Only division by real numbers is currently supported")
|
|
885
|
+
|
|
886
|
+
if abs(other) < self.TOL:
|
|
887
|
+
raise ValueError("Division by zero is not allowed")
|
|
888
|
+
|
|
889
|
+
if isinstance(other, np.generic):
|
|
890
|
+
other = cast("RealNumber", other.item())
|
|
891
|
+
other = 1 / other
|
|
892
|
+
return self * other
|
|
893
|
+
|
|
894
|
+
__itruediv__ = __truediv__
|
|
895
|
+
|
|
896
|
+
def __rtruediv__(self, other: Number | BaseVariable | Term) -> Term:
|
|
897
|
+
raise NotSupportedOperation("Only division by numbers is currently supported")
|
|
898
|
+
|
|
899
|
+
def __rfloordiv__(self, other: Number | BaseVariable | Term) -> Term:
|
|
900
|
+
raise NotSupportedOperation("Only division by numbers is currently supported")
|
|
901
|
+
|
|
902
|
+
def __pow__(self, a: int) -> Term:
|
|
903
|
+
out: BaseVariable | Term = copy.copy(self)
|
|
904
|
+
|
|
905
|
+
if a < 0:
|
|
906
|
+
raise NotImplementedError("Negative Power is not Supported.")
|
|
907
|
+
|
|
908
|
+
if a == 0:
|
|
909
|
+
return Term(elements=[1], operation=Operation.ADD)
|
|
910
|
+
|
|
911
|
+
for _ in range(a - 1):
|
|
912
|
+
out *= copy.copy(self)
|
|
913
|
+
|
|
914
|
+
if isinstance(out, BaseVariable):
|
|
915
|
+
out = Term(elements=[out], operation=Operation.ADD)
|
|
916
|
+
return out
|
|
917
|
+
|
|
918
|
+
def __hash__(self) -> int:
|
|
919
|
+
if self._hash_cache is None:
|
|
920
|
+
self._hash_cache = hash((self._label, self._domain.value, self._bounds))
|
|
921
|
+
return self._hash_cache
|
|
922
|
+
|
|
923
|
+
def __eq__(self, other: object) -> bool:
|
|
924
|
+
if not isinstance(other, BaseVariable):
|
|
925
|
+
return False
|
|
926
|
+
return hash(self) == hash(other)
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
@yaml.register_class
|
|
930
|
+
class BinaryVariable(BaseVariable):
|
|
931
|
+
"""
|
|
932
|
+
Binary decision variable restricted to the set ``{0, 1}``.
|
|
933
|
+
|
|
934
|
+
Example:
|
|
935
|
+
.. code-block:: python
|
|
936
|
+
|
|
937
|
+
from qilisdk.core.variables import BinaryVariable
|
|
938
|
+
|
|
939
|
+
x = BinaryVariable("x")
|
|
940
|
+
"""
|
|
941
|
+
|
|
942
|
+
def __init__(self, label: str) -> None:
|
|
943
|
+
super().__init__(label=label, domain=Domain.BINARY)
|
|
944
|
+
|
|
945
|
+
def num_binary_equivalent(self) -> int: # noqa: PLR6301
|
|
946
|
+
return 1
|
|
947
|
+
|
|
948
|
+
def evaluate(self, value: list[int] | RealNumber) -> RealNumber:
|
|
949
|
+
if isinstance(value, int | float):
|
|
950
|
+
if value in {1.0, 0.0}:
|
|
951
|
+
return int(value)
|
|
952
|
+
if not self.domain.check_value(value):
|
|
953
|
+
raise EvaluationError(f"Evaluating a Binary variable with a value {value} that is outside the domain.")
|
|
954
|
+
return value # I don't think this line is reachable
|
|
955
|
+
if len(value) != 1:
|
|
956
|
+
raise EvaluationError("Evaluating a Binary variable with a binary list of more than one item.")
|
|
957
|
+
return value[0]
|
|
958
|
+
|
|
959
|
+
def update_variable(self, domain: Domain, bounds: tuple[float | None, float | None] = (None, None)) -> None:
|
|
960
|
+
raise NotImplementedError
|
|
961
|
+
|
|
962
|
+
def to_binary(self) -> Term:
|
|
963
|
+
return Term([self], Operation.ADD)
|
|
964
|
+
|
|
965
|
+
def __copy__(self) -> BinaryVariable:
|
|
966
|
+
return BinaryVariable(label=self.label)
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
@yaml.register_class
|
|
970
|
+
class SpinVariable(BaseVariable):
|
|
971
|
+
"""Represents Spin Variable structure."""
|
|
972
|
+
|
|
973
|
+
def __init__(self, label: str) -> None:
|
|
974
|
+
super().__init__(label=label, domain=Domain.SPIN, bounds=(-1, 1))
|
|
975
|
+
|
|
976
|
+
def num_binary_equivalent(self) -> int: # noqa: PLR6301
|
|
977
|
+
return 1
|
|
978
|
+
|
|
979
|
+
def update_variable(self, domain: Domain, bounds: tuple[float | None, float | None] = (None, None)) -> None:
|
|
980
|
+
raise NotImplementedError
|
|
981
|
+
|
|
982
|
+
def evaluate(self, value: list[int] | RealNumber) -> RealNumber:
|
|
983
|
+
if isinstance(value, Number):
|
|
984
|
+
if not self.domain.check_value(value) and value != 0:
|
|
985
|
+
raise EvaluationError(f"Evaluating a Spin variable with a value {value} that is outside the domain.")
|
|
986
|
+
return -1 if value in {0, -1} else 1
|
|
987
|
+
if len(value) != 1:
|
|
988
|
+
raise EvaluationError("Evaluating a Spin variable with a list of more than one item.")
|
|
989
|
+
return -1 if value[0] in {0, -1} else 1
|
|
990
|
+
|
|
991
|
+
def to_binary(self) -> Term:
|
|
992
|
+
return Term([self], Operation.ADD)
|
|
993
|
+
|
|
994
|
+
def __copy__(self) -> SpinVariable:
|
|
995
|
+
return SpinVariable(label=self.label)
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
@yaml.register_class
|
|
999
|
+
class Variable(BaseVariable):
|
|
1000
|
+
"""
|
|
1001
|
+
Generic (possibly continuous) optimization variable with configurable encoding.
|
|
1002
|
+
|
|
1003
|
+
Example:
|
|
1004
|
+
.. code-block:: python
|
|
1005
|
+
|
|
1006
|
+
from qilisdk.core.variables import Domain, Variable
|
|
1007
|
+
|
|
1008
|
+
price = Variable("price", domain=Domain.REAL, bounds=(0, 10))
|
|
1009
|
+
binary_term = price.to_binary()
|
|
1010
|
+
"""
|
|
1011
|
+
|
|
1012
|
+
def __init__(
|
|
1013
|
+
self,
|
|
1014
|
+
label: str,
|
|
1015
|
+
domain: Domain,
|
|
1016
|
+
bounds: tuple[float | None, float | None] = (None, None),
|
|
1017
|
+
encoding: type[Encoding] = Bitwise,
|
|
1018
|
+
precision: float = 1e-2,
|
|
1019
|
+
) -> None:
|
|
1020
|
+
"""
|
|
1021
|
+
|
|
1022
|
+
Args:
|
|
1023
|
+
label (str): The name of the variable.
|
|
1024
|
+
domain (Domain): The domain of the values this variable can take.
|
|
1025
|
+
bounds (tuple[float | None, float | None], optional): the bounds on the values of the variable The bounds
|
|
1026
|
+
have the structure (lower_bound, Upper_bound) both values included. Defaults to (None, None).
|
|
1027
|
+
Note: if None is selected then the lowest/highest possible value of the variable's domain is chosen.
|
|
1028
|
+
encoding (type[Encoding], optional): _description_. Defaults to Bitwise.
|
|
1029
|
+
precision (float, optional): The floating point precision for REAL variables. Defaults to 1e-2.
|
|
1030
|
+
"""
|
|
1031
|
+
super().__init__(label=label, domain=domain, bounds=bounds)
|
|
1032
|
+
self._encoding = encoding
|
|
1033
|
+
self._precision = 1e-2
|
|
1034
|
+
self._term: Term | None = None
|
|
1035
|
+
self._bin_vars: list[BaseVariable] = []
|
|
1036
|
+
self._precision = precision
|
|
1037
|
+
|
|
1038
|
+
@property
|
|
1039
|
+
def encoding(self) -> type[Encoding]:
|
|
1040
|
+
return self._encoding
|
|
1041
|
+
|
|
1042
|
+
@property
|
|
1043
|
+
def precision(self) -> float:
|
|
1044
|
+
return self._precision
|
|
1045
|
+
|
|
1046
|
+
@property
|
|
1047
|
+
def term(self) -> Term:
|
|
1048
|
+
if self._term is None:
|
|
1049
|
+
if self.bounds[1] > LARGE_BOUND or self.bounds[0] < -LARGE_BOUND:
|
|
1050
|
+
logger.warning(
|
|
1051
|
+
f"Encoding variable {self.label} which has the bounds {self.bounds}"
|
|
1052
|
+
+ "is very expensive and may take a very long time."
|
|
1053
|
+
)
|
|
1054
|
+
self._term = self.to_binary()
|
|
1055
|
+
return self._term
|
|
1056
|
+
|
|
1057
|
+
@property
|
|
1058
|
+
def bin_vars(self) -> list[BaseVariable]:
|
|
1059
|
+
if self._term is None:
|
|
1060
|
+
self.to_binary()
|
|
1061
|
+
return self._bin_vars
|
|
1062
|
+
|
|
1063
|
+
def set_precision(self, precision: float) -> None:
|
|
1064
|
+
self._precision = precision
|
|
1065
|
+
self._term = None
|
|
1066
|
+
|
|
1067
|
+
def __copy__(self) -> Variable:
|
|
1068
|
+
return Variable(label=self.label, domain=self.domain, bounds=self.bounds, encoding=self._encoding)
|
|
1069
|
+
|
|
1070
|
+
def __getitem__(self, item: int) -> BaseVariable:
|
|
1071
|
+
if self._term is None:
|
|
1072
|
+
self.to_binary()
|
|
1073
|
+
return self._bin_vars[item]
|
|
1074
|
+
|
|
1075
|
+
def update_variable(
|
|
1076
|
+
self,
|
|
1077
|
+
domain: Domain,
|
|
1078
|
+
bounds: tuple[float | None, float | None] = (None, None),
|
|
1079
|
+
encoding: type[Encoding] | None = None,
|
|
1080
|
+
) -> None:
|
|
1081
|
+
self._encoding = encoding if encoding is not None else self._encoding
|
|
1082
|
+
self._term = None
|
|
1083
|
+
return super().update_variable(domain, bounds)
|
|
1084
|
+
|
|
1085
|
+
def evaluate(self, value: list[int] | RealNumber) -> RealNumber:
|
|
1086
|
+
if not isinstance(value, (list, RealNumber)):
|
|
1087
|
+
raise ValueError("Invalid Value Provided to evaluate a Variable.")
|
|
1088
|
+
if isinstance(value, int | float):
|
|
1089
|
+
if not self.domain.check_value(value):
|
|
1090
|
+
raise ValueError(f"The value {value} is invalid for the domain {self.domain.value}")
|
|
1091
|
+
if value < self.lower_bound or value > self.upper_bound:
|
|
1092
|
+
raise ValueError(f"The value {value} is outside the defined bounds {self.bounds}")
|
|
1093
|
+
return value
|
|
1094
|
+
return self.encoding.evaluate(self, value, self._precision)
|
|
1095
|
+
|
|
1096
|
+
def to_binary(self) -> Term:
|
|
1097
|
+
if self._term is None:
|
|
1098
|
+
term = self.encoding.encode(self, precision=self._precision)
|
|
1099
|
+
self._term = copy.copy(term)
|
|
1100
|
+
self._bin_vars = [BinaryVariable(f"{self.label}({i})") for i in range(self.num_binary_equivalent())]
|
|
1101
|
+
self._bin_vars = sorted(
|
|
1102
|
+
self._bin_vars,
|
|
1103
|
+
key=lambda x: _extract_number(x.label),
|
|
1104
|
+
)
|
|
1105
|
+
return self._term
|
|
1106
|
+
|
|
1107
|
+
def num_binary_equivalent(self) -> int:
|
|
1108
|
+
"""
|
|
1109
|
+
Returns:
|
|
1110
|
+
int: the number of binary variables needed to encode the continuous variable.
|
|
1111
|
+
"""
|
|
1112
|
+
return self.encoding.num_binary_equivalent(self, precision=self._precision)
|
|
1113
|
+
|
|
1114
|
+
def check_valid(self, binary_list: list[int]) -> tuple[bool, int]:
|
|
1115
|
+
"""checks if the binary list sample is a valid sample in the variable's encoding.
|
|
1116
|
+
|
|
1117
|
+
Args:
|
|
1118
|
+
binary_list (list[int] | int): a list of binary values or an integer value.
|
|
1119
|
+
|
|
1120
|
+
Returns:
|
|
1121
|
+
tuple[bool, int]: the boolean is True if the sample is a valid encoding,
|
|
1122
|
+
and the integer is the error in the encoding.
|
|
1123
|
+
"""
|
|
1124
|
+
return self.encoding.check_valid(binary_list)
|
|
1125
|
+
|
|
1126
|
+
def encoding_constraint(self) -> ComparisonTerm:
|
|
1127
|
+
"""Given a continuous variable return a Comparison Term that ensures that the encoding is respected.
|
|
1128
|
+
|
|
1129
|
+
Returns:
|
|
1130
|
+
ComparisonTerm: a Comparison Term that ensures the encoding is respected.
|
|
1131
|
+
"""
|
|
1132
|
+
return self.encoding.encoding_constraint(self, precision=self._precision)
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
@yaml.register_class(shared=True)
|
|
1136
|
+
class Parameter(BaseVariable):
|
|
1137
|
+
"""
|
|
1138
|
+
Symbolic scalar used to parametrize expressions while remaining differentiable.
|
|
1139
|
+
|
|
1140
|
+
Example:
|
|
1141
|
+
.. code-block:: python
|
|
1142
|
+
|
|
1143
|
+
from qilisdk.core.variables import Parameter
|
|
1144
|
+
|
|
1145
|
+
theta = Parameter("theta", value=0.5)
|
|
1146
|
+
theta.set_value(0.75)
|
|
1147
|
+
"""
|
|
1148
|
+
|
|
1149
|
+
def __init__(
|
|
1150
|
+
self,
|
|
1151
|
+
label: str,
|
|
1152
|
+
value: RealNumber,
|
|
1153
|
+
domain: Domain = Domain.REAL,
|
|
1154
|
+
bounds: tuple[float | None, float | None] = (None, None),
|
|
1155
|
+
) -> None:
|
|
1156
|
+
super().__init__(label=label, domain=domain, bounds=bounds)
|
|
1157
|
+
|
|
1158
|
+
if not self.domain.check_value(value):
|
|
1159
|
+
raise ValueError(
|
|
1160
|
+
f"Parameter value provided ({value}) doesn't correspond to the parameter's domain ({self.domain.name})"
|
|
1161
|
+
)
|
|
1162
|
+
self._value = value
|
|
1163
|
+
self.set_bounds(bounds[0], bounds[1])
|
|
1164
|
+
|
|
1165
|
+
@property
|
|
1166
|
+
def value(self) -> RealNumber:
|
|
1167
|
+
return self._value
|
|
1168
|
+
|
|
1169
|
+
def check_value(self, value: RealNumber) -> None:
|
|
1170
|
+
if not self.domain.check_value(value):
|
|
1171
|
+
raise ValueError(
|
|
1172
|
+
f"Parameter value provided ({value}) doesn't correspond to the parameter's domain ({self.domain.name})"
|
|
1173
|
+
)
|
|
1174
|
+
if value > self.bounds[1] or value < self.bounds[0]:
|
|
1175
|
+
raise ValueError(f"The value provided ({value}) is outside the bound of the parameter {self.bounds}")
|
|
1176
|
+
|
|
1177
|
+
def set_value(self, value: RealNumber) -> None:
|
|
1178
|
+
self.check_value(value)
|
|
1179
|
+
|
|
1180
|
+
if isinstance(value, np.generic):
|
|
1181
|
+
value = cast("RealNumber", value.item())
|
|
1182
|
+
self._value = value
|
|
1183
|
+
|
|
1184
|
+
def num_binary_equivalent(self) -> int: # noqa: PLR6301
|
|
1185
|
+
"""
|
|
1186
|
+
Returns:
|
|
1187
|
+
int: the number of binary variables that are needed to represent this variable in the given encoding.
|
|
1188
|
+
"""
|
|
1189
|
+
return 0
|
|
1190
|
+
|
|
1191
|
+
def evaluate(self, value: list[int] | RealNumber | None = None) -> RealNumber:
|
|
1192
|
+
"""Evaluates the value of the variable given a binary string or a number.
|
|
1193
|
+
|
|
1194
|
+
Args:
|
|
1195
|
+
value (list[int] | int | float): the value used to evaluate the variable.
|
|
1196
|
+
If the value provided is binary list (list[int]) then the value of the variable is evaluated based on
|
|
1197
|
+
its binary representation. This representation is constructed using the encoding, bounds and domain
|
|
1198
|
+
of the variable. To check the binary representation of a variable you can check the method `to_binary()`
|
|
1199
|
+
|
|
1200
|
+
Returns:
|
|
1201
|
+
float: the evaluated vale of the variable.
|
|
1202
|
+
"""
|
|
1203
|
+
if value is not None:
|
|
1204
|
+
if isinstance(value, RealNumber):
|
|
1205
|
+
self.check_value(value)
|
|
1206
|
+
return value
|
|
1207
|
+
raise NotImplementedError("Evaluating the value of a parameter with a list is not supported.")
|
|
1208
|
+
return self.value
|
|
1209
|
+
|
|
1210
|
+
def to_binary(self) -> Term:
|
|
1211
|
+
"""Returns the binary representation of a variable.
|
|
1212
|
+
|
|
1213
|
+
Returns:
|
|
1214
|
+
Term: the binary representation of a variable.
|
|
1215
|
+
"""
|
|
1216
|
+
return Term([self.value], operation=Operation.ADD)
|
|
1217
|
+
|
|
1218
|
+
def set_bounds(self, lower_bound: float | None, upper_bound: float | None) -> None:
|
|
1219
|
+
upper_bound = upper_bound if upper_bound is not None else self.domain.max()
|
|
1220
|
+
lower_bound = lower_bound if lower_bound is not None else self.domain.min()
|
|
1221
|
+
if self.value > upper_bound or self.value < lower_bound:
|
|
1222
|
+
raise ValueError(
|
|
1223
|
+
f"The current value of the parameter ({self.value}) is outside the bounds ({lower_bound}, {upper_bound})"
|
|
1224
|
+
)
|
|
1225
|
+
super().set_bounds(lower_bound, upper_bound)
|
|
1226
|
+
|
|
1227
|
+
def update_variable(self, domain: Domain, bounds: tuple[float | None, float | None] = (None, None)) -> None:
|
|
1228
|
+
if len(bounds) != 2: # noqa: PLR2004
|
|
1229
|
+
raise ValueError(
|
|
1230
|
+
"Invalid bounds provided: the bounds need to be a tuple with the format (lower_bound, upper_bound)"
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
if domain.check_value(self.value):
|
|
1234
|
+
self._domain = domain
|
|
1235
|
+
else:
|
|
1236
|
+
raise ValueError(
|
|
1237
|
+
f"The provided domain ({domain.name}) is incompatible with the current parameter value ({self.value})"
|
|
1238
|
+
)
|
|
1239
|
+
|
|
1240
|
+
self.set_bounds(lower_bound=bounds[0], upper_bound=bounds[1])
|
|
1241
|
+
|
|
1242
|
+
__hash__ = BaseVariable.__hash__
|
|
1243
|
+
|
|
1244
|
+
def __eq__(self, other: object) -> bool:
|
|
1245
|
+
if isinstance(other, BaseVariable):
|
|
1246
|
+
return super().__eq__(other)
|
|
1247
|
+
if isinstance(other, (float, int)):
|
|
1248
|
+
return self.value == other
|
|
1249
|
+
return False
|
|
1250
|
+
|
|
1251
|
+
def __le__(self, other: object) -> bool:
|
|
1252
|
+
if isinstance(other, (float, int)):
|
|
1253
|
+
return self.value <= other
|
|
1254
|
+
return NotImplemented
|
|
1255
|
+
|
|
1256
|
+
def __lt__(self, other: object) -> bool:
|
|
1257
|
+
if isinstance(other, (float, int)):
|
|
1258
|
+
return self.value < other
|
|
1259
|
+
return NotImplemented
|
|
1260
|
+
|
|
1261
|
+
def __ge__(self, other: object) -> bool:
|
|
1262
|
+
if isinstance(other, (float, int)):
|
|
1263
|
+
return self.value >= other
|
|
1264
|
+
return NotImplemented
|
|
1265
|
+
|
|
1266
|
+
def __gt__(self, other: object) -> bool:
|
|
1267
|
+
if isinstance(other, (float, int)):
|
|
1268
|
+
return self.value > other
|
|
1269
|
+
return NotImplemented
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
# Terms ###
|
|
1273
|
+
|
|
1274
|
+
|
|
1275
|
+
@yaml.register_class
|
|
1276
|
+
class Term:
|
|
1277
|
+
"""Represents a mathematical Term (e.g. 3x*y, 2x, ...).
|
|
1278
|
+
|
|
1279
|
+
And they are built from:
|
|
1280
|
+
- ``Variable``'s: The decision variables of the model (x, y, ...).
|
|
1281
|
+
- Other ``Term``'s: Allowing for complex expressions to be constructed.
|
|
1282
|
+
"""
|
|
1283
|
+
|
|
1284
|
+
CONST = Variable(CONST_KEY, Domain.REAL)
|
|
1285
|
+
TOL = get_settings().atol
|
|
1286
|
+
|
|
1287
|
+
def __init__(self, elements: Sequence[BaseVariable | Term | Number], operation: Operation) -> None:
|
|
1288
|
+
"""initialize a new term object.
|
|
1289
|
+
|
|
1290
|
+
Args:
|
|
1291
|
+
elements (Sequence[BaseVariable | Term | Number]): a list of elements in the term.
|
|
1292
|
+
operation (Operation): the mathematical operation between these elements.
|
|
1293
|
+
|
|
1294
|
+
Raises:
|
|
1295
|
+
ValueError: if the items inside elements are not from the listed types (BaseVariable | Term | Number).
|
|
1296
|
+
"""
|
|
1297
|
+
self._operation = operation
|
|
1298
|
+
self._elements: dict[BaseVariable | Term, Number] = {} # The list of elements in the term.
|
|
1299
|
+
# key: the term or variable | value: the coefficient corresponding to that value.
|
|
1300
|
+
for e in elements:
|
|
1301
|
+
if isinstance(e, BaseVariable):
|
|
1302
|
+
if e in self:
|
|
1303
|
+
if self._is_constant(e):
|
|
1304
|
+
self[e] = self._apply_operation_on_constants([self[e], 1])
|
|
1305
|
+
elif isinstance(e, BinaryVariable) and self.operation == Operation.MUL:
|
|
1306
|
+
self[e] = 1
|
|
1307
|
+
else:
|
|
1308
|
+
self[e] += 1
|
|
1309
|
+
else:
|
|
1310
|
+
self[e] = 1
|
|
1311
|
+
elif isinstance(e, Number):
|
|
1312
|
+
if self.CONST in self:
|
|
1313
|
+
self[self.CONST] = self._apply_operation_on_constants([self[self.CONST], e])
|
|
1314
|
+
else:
|
|
1315
|
+
self[self.CONST] = e
|
|
1316
|
+
elif isinstance(e, Term):
|
|
1317
|
+
if len(e) == 0:
|
|
1318
|
+
if self.CONST in self:
|
|
1319
|
+
self[self.CONST] = self._apply_operation_on_constants([self[self.CONST], 0])
|
|
1320
|
+
else:
|
|
1321
|
+
self[self.CONST] = 0
|
|
1322
|
+
elif e.operation == self._operation:
|
|
1323
|
+
for key in e:
|
|
1324
|
+
if key in self:
|
|
1325
|
+
if isinstance(key, BaseVariable) and self._is_constant(key):
|
|
1326
|
+
self[key] = self._apply_operation_on_constants([self[key], e[key]])
|
|
1327
|
+
elif isinstance(key, BinaryVariable) and self.operation == Operation.MUL:
|
|
1328
|
+
self[key] = 1
|
|
1329
|
+
else:
|
|
1330
|
+
self[key] += e[key]
|
|
1331
|
+
else:
|
|
1332
|
+
self[key] = e[key]
|
|
1333
|
+
else:
|
|
1334
|
+
e_copy = copy.copy(e)
|
|
1335
|
+
coeff = complex(1.0)
|
|
1336
|
+
if e_copy.operation == Operation.MUL and self.CONST in e_copy:
|
|
1337
|
+
coeff = e_copy.pop(self.CONST)
|
|
1338
|
+
simple_e = e_copy._simplify() # noqa: SLF001
|
|
1339
|
+
simple_e = self.CONST if isinstance(simple_e, Term) and len(simple_e) == 0 else simple_e
|
|
1340
|
+
if simple_e in self:
|
|
1341
|
+
if isinstance(simple_e, BaseVariable) and self._is_constant(simple_e):
|
|
1342
|
+
self[simple_e] = self._apply_operation_on_constants([self[simple_e], coeff])
|
|
1343
|
+
else:
|
|
1344
|
+
self[simple_e] += coeff
|
|
1345
|
+
else:
|
|
1346
|
+
self[simple_e] = coeff
|
|
1347
|
+
else:
|
|
1348
|
+
raise ValueError(
|
|
1349
|
+
f"Term accepts object of types Term or Variable but an object of type {e.__class__} was given"
|
|
1350
|
+
)
|
|
1351
|
+
self._remove_zeros()
|
|
1352
|
+
|
|
1353
|
+
@property
|
|
1354
|
+
def operation(self) -> Operation:
|
|
1355
|
+
"""
|
|
1356
|
+
Returns:
|
|
1357
|
+
Operation: the operation between the term's elements.
|
|
1358
|
+
"""
|
|
1359
|
+
return self._operation
|
|
1360
|
+
|
|
1361
|
+
@property
|
|
1362
|
+
def degree(self) -> int:
|
|
1363
|
+
"""
|
|
1364
|
+
Returns:
|
|
1365
|
+
int: the highest degree in the term.
|
|
1366
|
+
"""
|
|
1367
|
+
degree = 0
|
|
1368
|
+
if self.operation == Operation.MUL:
|
|
1369
|
+
for element in self:
|
|
1370
|
+
if isinstance(element, Term):
|
|
1371
|
+
degree += element.degree
|
|
1372
|
+
elif isinstance(element, BaseVariable) and not self._is_constant(element):
|
|
1373
|
+
degree += int(_assert_real(self[element]))
|
|
1374
|
+
return degree
|
|
1375
|
+
|
|
1376
|
+
for element in self:
|
|
1377
|
+
if isinstance(element, Term):
|
|
1378
|
+
degree = max(degree, element.degree)
|
|
1379
|
+
elif isinstance(element, BaseVariable) and not self._is_constant(element):
|
|
1380
|
+
degree = max(degree, 1)
|
|
1381
|
+
return degree
|
|
1382
|
+
|
|
1383
|
+
def to_binary(self) -> Term:
|
|
1384
|
+
"""Returns the term in binary format. That is encoding all continuous variables into
|
|
1385
|
+
binary according to the encoding defined in the variable.
|
|
1386
|
+
|
|
1387
|
+
Raises:
|
|
1388
|
+
ValueError: The term contains operations that are not addition or multiplication.
|
|
1389
|
+
ValueError: the term contains an element that is not a Term or a BaseVariable.
|
|
1390
|
+
|
|
1391
|
+
Returns:
|
|
1392
|
+
Term: the term after transforming all the variables into binary.
|
|
1393
|
+
"""
|
|
1394
|
+
if self.operation not in {Operation.ADD, Operation.MUL}:
|
|
1395
|
+
raise ValueError("Can not evaluate any operation that is not Addition of Multiplication")
|
|
1396
|
+
out_list: list[BaseVariable | Term | Number] = []
|
|
1397
|
+
for e in self:
|
|
1398
|
+
if isinstance(e, Term):
|
|
1399
|
+
out_list.append(self[e] * e.to_binary())
|
|
1400
|
+
elif isinstance(e, BaseVariable):
|
|
1401
|
+
if self._is_constant(e):
|
|
1402
|
+
out_list.append(self[e])
|
|
1403
|
+
elif isinstance(e, Variable):
|
|
1404
|
+
x = e.to_binary()
|
|
1405
|
+
if self.operation == Operation.MUL:
|
|
1406
|
+
out_list.append(x ** int(_assert_real(self[e])))
|
|
1407
|
+
else:
|
|
1408
|
+
out_list.append(self[e] * x)
|
|
1409
|
+
else:
|
|
1410
|
+
out_list.append(self[e] * e)
|
|
1411
|
+
else:
|
|
1412
|
+
raise ValueError(f"Evaluating term with elements of type {e.__class__} is not supported.")
|
|
1413
|
+
|
|
1414
|
+
return Term(out_list, self.operation)
|
|
1415
|
+
|
|
1416
|
+
def _apply_operation_on_constants(self, const_list: list[Number]) -> Number:
|
|
1417
|
+
out = complex(const_list[0])
|
|
1418
|
+
for i in range(1, len(const_list)):
|
|
1419
|
+
if self.operation is Operation.ADD:
|
|
1420
|
+
out += const_list[i]
|
|
1421
|
+
elif self.operation is Operation.SUB:
|
|
1422
|
+
out -= const_list[i]
|
|
1423
|
+
elif self.operation is Operation.MUL:
|
|
1424
|
+
out *= const_list[i]
|
|
1425
|
+
elif self.operation is Operation.DIV:
|
|
1426
|
+
out /= const_list[i]
|
|
1427
|
+
|
|
1428
|
+
return out
|
|
1429
|
+
|
|
1430
|
+
def variables(self) -> list[BaseVariable]:
|
|
1431
|
+
"""Returns the unique list of variables in the Term
|
|
1432
|
+
|
|
1433
|
+
Returns:
|
|
1434
|
+
list[Variable]: The unique list of variables in the Term.
|
|
1435
|
+
"""
|
|
1436
|
+
var = set()
|
|
1437
|
+
for e in self:
|
|
1438
|
+
if isinstance(e, BaseVariable) and not self._is_constant(e):
|
|
1439
|
+
var.add(e)
|
|
1440
|
+
elif isinstance(e, Term):
|
|
1441
|
+
var.update(e.variables())
|
|
1442
|
+
return sorted(var, key=lambda x: x.label)
|
|
1443
|
+
|
|
1444
|
+
def _simplify(self) -> Term | BaseVariable:
|
|
1445
|
+
"""Simplify the term object.
|
|
1446
|
+
|
|
1447
|
+
Returns:
|
|
1448
|
+
(Term | BaseVariable): the simplified term.
|
|
1449
|
+
"""
|
|
1450
|
+
if len(self) == 1 and not isinstance(self, MathematicalMap):
|
|
1451
|
+
item = next(iter(self._elements.keys()))
|
|
1452
|
+
if self._elements[item] == 1:
|
|
1453
|
+
return item
|
|
1454
|
+
return self
|
|
1455
|
+
|
|
1456
|
+
def pop(self, item: BaseVariable | Term) -> Number:
|
|
1457
|
+
"""Remove an item from the term.
|
|
1458
|
+
|
|
1459
|
+
Args:
|
|
1460
|
+
item (BaseVariable | Term): the item to be removed.
|
|
1461
|
+
|
|
1462
|
+
Raises:
|
|
1463
|
+
KeyError: if item is not in the term.
|
|
1464
|
+
|
|
1465
|
+
Returns:
|
|
1466
|
+
Number: the coefficient of the removed item.
|
|
1467
|
+
"""
|
|
1468
|
+
try:
|
|
1469
|
+
return self._elements.pop(item)
|
|
1470
|
+
except KeyError as e:
|
|
1471
|
+
raise KeyError(f'item "{item}" not found in the term.') from e
|
|
1472
|
+
|
|
1473
|
+
def _is_constant(self, variable: BaseVariable) -> bool:
|
|
1474
|
+
"""Checks if the variable is a constant variable as defined by the Term class.
|
|
1475
|
+
|
|
1476
|
+
Args:
|
|
1477
|
+
variable (BaseVariable): the variable to be checked.
|
|
1478
|
+
|
|
1479
|
+
Returns:
|
|
1480
|
+
bool: True if the variable is a constant, False otherwise.
|
|
1481
|
+
"""
|
|
1482
|
+
return variable == self.CONST
|
|
1483
|
+
|
|
1484
|
+
def to_list(self) -> list[BaseVariable | Term | Number]:
|
|
1485
|
+
"""Exports the current term into a list of its elements.
|
|
1486
|
+
|
|
1487
|
+
Returns:
|
|
1488
|
+
list[BaseVariable | Term | Number]: A list of the elements inside the term.
|
|
1489
|
+
"""
|
|
1490
|
+
out_list: list[BaseVariable | Term | Number] = []
|
|
1491
|
+
for e in self:
|
|
1492
|
+
if isinstance(e, BaseVariable) and self._is_constant(e):
|
|
1493
|
+
out_list.append(self[e])
|
|
1494
|
+
elif self.operation == Operation.MUL:
|
|
1495
|
+
for _ in range(int(_assert_real(self[e]))):
|
|
1496
|
+
out_list.append(e)
|
|
1497
|
+
else:
|
|
1498
|
+
out_list.append(self[e] * e if self[e] != 1 else e)
|
|
1499
|
+
return out_list
|
|
1500
|
+
|
|
1501
|
+
def _unfold_parentheses(self) -> Term:
|
|
1502
|
+
"""Simplifies any parentheses in the term expression.
|
|
1503
|
+
|
|
1504
|
+
Returns:
|
|
1505
|
+
Term: A new term with a more simplified form.
|
|
1506
|
+
"""
|
|
1507
|
+
out = copy.copy(self)
|
|
1508
|
+
if out.operation != Operation.MUL:
|
|
1509
|
+
return out
|
|
1510
|
+
|
|
1511
|
+
parentheses: list[tuple[Term, Number]] = []
|
|
1512
|
+
|
|
1513
|
+
for e in out:
|
|
1514
|
+
if isinstance(e, Term) and e.operation == Operation.ADD:
|
|
1515
|
+
parentheses.append((copy.copy(e), out[e]))
|
|
1516
|
+
|
|
1517
|
+
for term, _ in parentheses:
|
|
1518
|
+
out.pop(term)
|
|
1519
|
+
|
|
1520
|
+
if len(out) == 0 and len(parentheses) != 0:
|
|
1521
|
+
out = Term([1], Operation.ADD)
|
|
1522
|
+
|
|
1523
|
+
for _term, coeff in parentheses:
|
|
1524
|
+
term = copy.copy(_term)
|
|
1525
|
+
_coeff = _assert_real(coeff)
|
|
1526
|
+
if _coeff > 1:
|
|
1527
|
+
term **= int(_coeff)
|
|
1528
|
+
final_out = []
|
|
1529
|
+
for t in term:
|
|
1530
|
+
final_out.append(t * out * term[t])
|
|
1531
|
+
out = Term(final_out, Operation.ADD)
|
|
1532
|
+
|
|
1533
|
+
return out
|
|
1534
|
+
|
|
1535
|
+
def _remove_zeros(self) -> None:
|
|
1536
|
+
"""Simplifies any un-necessary zeros from terms."""
|
|
1537
|
+
to_be_popped = []
|
|
1538
|
+
if self.operation == Operation.MUL and self.CONST in self and self[self.CONST] == 0:
|
|
1539
|
+
l = len(self)
|
|
1540
|
+
for _ in range(l):
|
|
1541
|
+
self._elements.popitem()
|
|
1542
|
+
for e in self:
|
|
1543
|
+
if self[e] == 0:
|
|
1544
|
+
to_be_popped.append(e)
|
|
1545
|
+
for p in to_be_popped:
|
|
1546
|
+
self._elements.pop(p)
|
|
1547
|
+
|
|
1548
|
+
def evaluate(self, var_values: Mapping[BaseVariable, list[int] | RealNumber]) -> Number:
|
|
1549
|
+
"""Evaluates the term given a set of values for the variables in the term.
|
|
1550
|
+
|
|
1551
|
+
Args:
|
|
1552
|
+
var_values (Mapping[BaseVariable, list[int] | Number]): the values of the variables in the term.
|
|
1553
|
+
If the value provided is binary list (list[int]) then the value of the variable is evaluated based on
|
|
1554
|
+
its binary representation. This representation is constructed using the encoding, bounds and domain
|
|
1555
|
+
of the variable. To check the binary representation of a variable you can check the method `to_binary()`
|
|
1556
|
+
|
|
1557
|
+
Raises:
|
|
1558
|
+
ValueError: if not all variables in the term are provided a value.
|
|
1559
|
+
|
|
1560
|
+
Returns:
|
|
1561
|
+
float: the result from evaluating the term.
|
|
1562
|
+
"""
|
|
1563
|
+
if len(self._elements) == 0:
|
|
1564
|
+
return 0
|
|
1565
|
+
_var_values = dict(var_values)
|
|
1566
|
+
for var in self.variables():
|
|
1567
|
+
if isinstance(var, Parameter):
|
|
1568
|
+
if var not in _var_values:
|
|
1569
|
+
_var_values[var] = var.value
|
|
1570
|
+
else:
|
|
1571
|
+
value = _var_values[var]
|
|
1572
|
+
if not isinstance(value, RealNumber):
|
|
1573
|
+
raise ValueError(f"setting a parameter ({var}) value with a list is not supported.")
|
|
1574
|
+
# var.set_value(value)
|
|
1575
|
+
if var not in _var_values:
|
|
1576
|
+
raise ValueError(f"Can not evaluate term because the value of the variable {var} is not provided.")
|
|
1577
|
+
output = complex(0.0) if self.operation in {Operation.ADD, Operation.SUB} else complex(1.0)
|
|
1578
|
+
for e in self:
|
|
1579
|
+
if isinstance(e, Term):
|
|
1580
|
+
output = self._apply_operation_on_constants([output, e.evaluate(_var_values) * self[e]])
|
|
1581
|
+
elif isinstance(e, BaseVariable):
|
|
1582
|
+
if e == self.CONST:
|
|
1583
|
+
output = self._apply_operation_on_constants([output, self[e]])
|
|
1584
|
+
elif self.operation == Operation.MUL:
|
|
1585
|
+
output = self._apply_operation_on_constants([output, e.evaluate(_var_values[e]) ** self[e]])
|
|
1586
|
+
else:
|
|
1587
|
+
output = self._apply_operation_on_constants([output, e.evaluate(_var_values[e]) * self[e]])
|
|
1588
|
+
if isinstance(output, RealNumber):
|
|
1589
|
+
return float(output)
|
|
1590
|
+
if isinstance(output, complex) and abs(output.imag) < self.TOL:
|
|
1591
|
+
return float(output.real)
|
|
1592
|
+
return output
|
|
1593
|
+
|
|
1594
|
+
def get_constant(self) -> Number:
|
|
1595
|
+
"""
|
|
1596
|
+
Returns:
|
|
1597
|
+
Number: The constant value of the term.
|
|
1598
|
+
"""
|
|
1599
|
+
if self.CONST in self:
|
|
1600
|
+
return self[self.CONST]
|
|
1601
|
+
return 0 if self.operation in {Operation.ADD, Operation.SUB} else 1
|
|
1602
|
+
|
|
1603
|
+
def is_parameterized_term(self) -> bool:
|
|
1604
|
+
return all(isinstance(var, Parameter) for var in self.variables())
|
|
1605
|
+
|
|
1606
|
+
def __copy__(self) -> Term:
|
|
1607
|
+
return Term(copy.copy(self.to_list()), copy.copy(self.operation))
|
|
1608
|
+
|
|
1609
|
+
def __repr__(self) -> str:
|
|
1610
|
+
if len(self) == 0:
|
|
1611
|
+
return "0"
|
|
1612
|
+
output_string = ""
|
|
1613
|
+
const = self.get_constant()
|
|
1614
|
+
keys = list(self._elements.keys())
|
|
1615
|
+
|
|
1616
|
+
if (
|
|
1617
|
+
(self.operation in {Operation.ADD, Operation.SUB} and const == 0)
|
|
1618
|
+
or (self.operation in {Operation.MUL, Operation.DIV} and const == 1)
|
|
1619
|
+
) and Term.CONST in keys:
|
|
1620
|
+
keys.remove(Term.CONST)
|
|
1621
|
+
|
|
1622
|
+
for i, e in enumerate(keys):
|
|
1623
|
+
if isinstance(e, Term):
|
|
1624
|
+
term_str = str(e).strip()
|
|
1625
|
+
if len(term_str) > 0:
|
|
1626
|
+
if term_str[0] == "(" and term_str[-1] == ")":
|
|
1627
|
+
term_str = term_str.removeprefix("(").removesuffix(")")
|
|
1628
|
+
output_string += (
|
|
1629
|
+
f"({term_str}) " if self[e] == 1 else f"({_float_if_real(self[e])}) * ({term_str}) "
|
|
1630
|
+
)
|
|
1631
|
+
elif isinstance(e, BaseVariable):
|
|
1632
|
+
if self._is_constant(e):
|
|
1633
|
+
output_string += f"({_float_if_real(self[e])}) "
|
|
1634
|
+
elif (self.operation is Operation.MUL or self.operation is Operation.DIV) and _assert_real(self[e]) > 1:
|
|
1635
|
+
output_string += f"({e}^{_float_if_real(self[e])}) "
|
|
1636
|
+
else:
|
|
1637
|
+
output_string += f"{e} " if self[e] == 1 else f"({_float_if_real(self[e])}) * {e} "
|
|
1638
|
+
else:
|
|
1639
|
+
output_string += f"{e} "
|
|
1640
|
+
if i < len(keys) - 1:
|
|
1641
|
+
output_string += f"{self.operation.value} "
|
|
1642
|
+
|
|
1643
|
+
return output_string.strip()
|
|
1644
|
+
|
|
1645
|
+
__str__ = __repr__
|
|
1646
|
+
|
|
1647
|
+
def __getitem__(self, item: BaseVariable | Term) -> Number:
|
|
1648
|
+
return self._elements[item]
|
|
1649
|
+
|
|
1650
|
+
def __setitem__(self, key: BaseVariable | Term, item: Number) -> None:
|
|
1651
|
+
self._elements[key] = item
|
|
1652
|
+
|
|
1653
|
+
def __iter__(self) -> Iterator[BaseVariable | Term]:
|
|
1654
|
+
yield from self._elements
|
|
1655
|
+
|
|
1656
|
+
def __contains__(self, item: BaseVariable | Term) -> bool:
|
|
1657
|
+
return item in self._elements
|
|
1658
|
+
|
|
1659
|
+
__next__ = __iter__
|
|
1660
|
+
|
|
1661
|
+
def __len__(self) -> int:
|
|
1662
|
+
return len(self._elements)
|
|
1663
|
+
|
|
1664
|
+
def __add__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1665
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1666
|
+
return NotImplemented
|
|
1667
|
+
out = self.to_list() if self.operation == Operation.ADD else [copy.copy(self)]
|
|
1668
|
+
|
|
1669
|
+
if isinstance(other, np.generic):
|
|
1670
|
+
other = cast("Number", other.item())
|
|
1671
|
+
|
|
1672
|
+
out.append(other)
|
|
1673
|
+
return Term(out, Operation.ADD)
|
|
1674
|
+
|
|
1675
|
+
__iadd__ = __add__
|
|
1676
|
+
|
|
1677
|
+
def __radd__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1678
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1679
|
+
return NotImplemented
|
|
1680
|
+
out = self.to_list() if self.operation == Operation.ADD else [copy.copy(self)]
|
|
1681
|
+
|
|
1682
|
+
if isinstance(other, np.generic):
|
|
1683
|
+
other = cast("Number", other.item())
|
|
1684
|
+
out.insert(0, other)
|
|
1685
|
+
return Term(out, Operation.ADD)
|
|
1686
|
+
|
|
1687
|
+
def __mul__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1688
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1689
|
+
return NotImplemented
|
|
1690
|
+
out = self.to_list() if self.operation == Operation.MUL else [copy.copy(self)]
|
|
1691
|
+
if len(out) == 0:
|
|
1692
|
+
out = [0]
|
|
1693
|
+
|
|
1694
|
+
if isinstance(other, np.generic):
|
|
1695
|
+
other = cast("Number", other.item())
|
|
1696
|
+
|
|
1697
|
+
out.append(other)
|
|
1698
|
+
return Term(out, Operation.MUL)._unfold_parentheses()
|
|
1699
|
+
|
|
1700
|
+
__imul__ = __mul__
|
|
1701
|
+
|
|
1702
|
+
def __rmul__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1703
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1704
|
+
return NotImplemented
|
|
1705
|
+
out = self.to_list() if self.operation == Operation.MUL else [copy.copy(self)]
|
|
1706
|
+
if len(out) == 0:
|
|
1707
|
+
out = [0]
|
|
1708
|
+
|
|
1709
|
+
if isinstance(other, np.generic):
|
|
1710
|
+
other = cast("Number", other.item())
|
|
1711
|
+
|
|
1712
|
+
out.insert(0, other)
|
|
1713
|
+
return Term(out, Operation.MUL)._unfold_parentheses()
|
|
1714
|
+
|
|
1715
|
+
def __neg__(self) -> Term:
|
|
1716
|
+
return -1 * self
|
|
1717
|
+
|
|
1718
|
+
def __sub__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1719
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1720
|
+
return NotImplemented
|
|
1721
|
+
|
|
1722
|
+
if isinstance(other, np.generic):
|
|
1723
|
+
other = cast("Number", other.item())
|
|
1724
|
+
|
|
1725
|
+
return self + -1 * other
|
|
1726
|
+
|
|
1727
|
+
def __rsub__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1728
|
+
if not isinstance(other, (Number, BaseVariable, Term)):
|
|
1729
|
+
return NotImplemented
|
|
1730
|
+
return -1 * self + other
|
|
1731
|
+
|
|
1732
|
+
__isub__ = __sub__
|
|
1733
|
+
|
|
1734
|
+
def __truediv__(self, other: Number) -> Term:
|
|
1735
|
+
if not isinstance(other, Number):
|
|
1736
|
+
raise NotImplementedError("Only division by numbers is currently supported")
|
|
1737
|
+
|
|
1738
|
+
if abs(other) < self.TOL:
|
|
1739
|
+
raise ValueError("Division by zero is not allowed")
|
|
1740
|
+
|
|
1741
|
+
other = 1 / other
|
|
1742
|
+
return self * other
|
|
1743
|
+
|
|
1744
|
+
__itruediv__ = __truediv__
|
|
1745
|
+
|
|
1746
|
+
def __rtruediv__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1747
|
+
raise NotSupportedOperation("Only division by numbers is currently supported")
|
|
1748
|
+
|
|
1749
|
+
def __rfloordiv__(self, other: Number | BaseVariable | Term) -> Term:
|
|
1750
|
+
raise NotSupportedOperation("Only division by numbers is currently supported")
|
|
1751
|
+
|
|
1752
|
+
def __pow__(self, a: int) -> Term:
|
|
1753
|
+
if not isinstance(a, int):
|
|
1754
|
+
raise ValueError(f"Only integer exponents are allowed, but provided {type(a)}")
|
|
1755
|
+
if self.operation == Operation.ADD:
|
|
1756
|
+
out = copy.copy(self)
|
|
1757
|
+
for _ in range(a - 1):
|
|
1758
|
+
out_list = []
|
|
1759
|
+
for element in self:
|
|
1760
|
+
out_list.append(out * copy.copy(element) * self[element])
|
|
1761
|
+
out = Term(out_list, Operation.ADD)
|
|
1762
|
+
return out
|
|
1763
|
+
if self.operation == Operation.MUL:
|
|
1764
|
+
out = copy.copy(self)
|
|
1765
|
+
for element in out:
|
|
1766
|
+
if element is Term.CONST:
|
|
1767
|
+
out[element] **= a
|
|
1768
|
+
else:
|
|
1769
|
+
out[element] *= a
|
|
1770
|
+
return out
|
|
1771
|
+
raise NotImplementedError(
|
|
1772
|
+
"The power operation for terms that are not addition or multiplication is not supported."
|
|
1773
|
+
)
|
|
1774
|
+
|
|
1775
|
+
def __hash__(self) -> int:
|
|
1776
|
+
return hash((frozenset(self._elements.items()), self.operation))
|
|
1777
|
+
|
|
1778
|
+
def __eq__(self, other: object) -> bool:
|
|
1779
|
+
if not isinstance(other, Term):
|
|
1780
|
+
return False
|
|
1781
|
+
return hash(self) == hash(other)
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
@yaml.register_class
|
|
1785
|
+
class ComparisonTerm:
|
|
1786
|
+
"""Represents a mathematical comparison Term, that can be an equality or an inequality between two ``Term`` objects
|
|
1787
|
+
(e.g. x+y>0, x>2, ...).
|
|
1788
|
+
|
|
1789
|
+
They are built from a left and a right hand part, each of which can contain:
|
|
1790
|
+
- ``Variable``'s: The decision variables of the model (x, y, ...).
|
|
1791
|
+
- Other ``Term``'s: Allowing for complex expressions to be constructed (x+y, ...)
|
|
1792
|
+
"""
|
|
1793
|
+
|
|
1794
|
+
def __init__(
|
|
1795
|
+
self,
|
|
1796
|
+
lhs: RealNumber | BaseVariable | Term,
|
|
1797
|
+
rhs: RealNumber | BaseVariable | Term,
|
|
1798
|
+
operation: ComparisonOperation,
|
|
1799
|
+
) -> None:
|
|
1800
|
+
"""Initializes a new comparison term.
|
|
1801
|
+
|
|
1802
|
+
Args:
|
|
1803
|
+
lhs (RealNumber | BaseVariable | Term): the left hand side of the comparison term.
|
|
1804
|
+
rhs (RealNumber | BaseVariable | Term): the right hand side of the comparison term.
|
|
1805
|
+
operation (ComparisonOperation): the comparison operations between the left and right hand sides.
|
|
1806
|
+
"""
|
|
1807
|
+
term = lhs - rhs
|
|
1808
|
+
if not isinstance(term, Term):
|
|
1809
|
+
term = Term([term], Operation.ADD)
|
|
1810
|
+
const = -1 * term.pop(Term.CONST) if Term.CONST in term else 0
|
|
1811
|
+
self._lhs = term
|
|
1812
|
+
self._rhs = Term([const], Operation.ADD)
|
|
1813
|
+
self._operation = operation
|
|
1814
|
+
|
|
1815
|
+
@property
|
|
1816
|
+
def operation(self) -> ComparisonOperation:
|
|
1817
|
+
"""
|
|
1818
|
+
Returns:
|
|
1819
|
+
ComparisonOperation: the comparison operation between the left and right hand sides.
|
|
1820
|
+
"""
|
|
1821
|
+
return self._operation
|
|
1822
|
+
|
|
1823
|
+
@property
|
|
1824
|
+
def lhs(self) -> Term:
|
|
1825
|
+
"""
|
|
1826
|
+
Returns:
|
|
1827
|
+
Term: the left hand side of the comparison term.
|
|
1828
|
+
"""
|
|
1829
|
+
return self._lhs
|
|
1830
|
+
|
|
1831
|
+
@property
|
|
1832
|
+
def rhs(self) -> Term:
|
|
1833
|
+
"""
|
|
1834
|
+
Returns:
|
|
1835
|
+
Term: the right hand side of the comparison term.
|
|
1836
|
+
"""
|
|
1837
|
+
return self._rhs
|
|
1838
|
+
|
|
1839
|
+
def variables(self) -> list[BaseVariable]:
|
|
1840
|
+
"""Returns the unique list of variables in the Term
|
|
1841
|
+
|
|
1842
|
+
Returns:
|
|
1843
|
+
list[Variable]: The unique list of variables in the Term.
|
|
1844
|
+
"""
|
|
1845
|
+
lhs_var = self._lhs.variables()
|
|
1846
|
+
rhs_var = self._rhs.variables()
|
|
1847
|
+
|
|
1848
|
+
var = set()
|
|
1849
|
+
var.update(lhs_var)
|
|
1850
|
+
var.update(rhs_var)
|
|
1851
|
+
|
|
1852
|
+
return sorted(var, key=lambda x: x.label)
|
|
1853
|
+
|
|
1854
|
+
@property
|
|
1855
|
+
def degree(self) -> int:
|
|
1856
|
+
"""
|
|
1857
|
+
Returns:
|
|
1858
|
+
int: the maximum degree in the left and right hand sides of the comparison term.
|
|
1859
|
+
"""
|
|
1860
|
+
return max(self.rhs.degree, self.lhs.degree)
|
|
1861
|
+
|
|
1862
|
+
def to_list(self) -> list:
|
|
1863
|
+
"""Exports the comparison term into a list. The elements of the right hand side are first moved to the left hand
|
|
1864
|
+
side before the generation of the list. Therefore, you can assume that the right hand side will be zero.
|
|
1865
|
+
|
|
1866
|
+
Returns:
|
|
1867
|
+
list: a list constructed from all the elements in the left and right hand sides of the comparison term.
|
|
1868
|
+
"""
|
|
1869
|
+
logger.info(
|
|
1870
|
+
"to_list(): The elements of output list assume the comparison term has been transformed "
|
|
1871
|
+
+ f"from (lhs {self.operation.value} rhs) to (lhs - rhs {self.operation.value} 0).",
|
|
1872
|
+
)
|
|
1873
|
+
out = self.lhs.to_list()
|
|
1874
|
+
out.extend((-1 * self.rhs).to_list())
|
|
1875
|
+
return out
|
|
1876
|
+
|
|
1877
|
+
def to_binary(self) -> ComparisonTerm:
|
|
1878
|
+
"""Returns the comparison term in binary format. That is encoding all continuous variables into
|
|
1879
|
+
binary according to the encoding defined in the variable.
|
|
1880
|
+
|
|
1881
|
+
Returns:
|
|
1882
|
+
ComparisonTerm: the comparison term after transforming all the variables into binary.
|
|
1883
|
+
"""
|
|
1884
|
+
return ComparisonTerm(rhs=self.rhs.to_binary(), lhs=self.lhs.to_binary(), operation=self.operation)
|
|
1885
|
+
|
|
1886
|
+
def _apply_comparison_operation(self, v1: RealNumber, v2: RealNumber) -> bool:
|
|
1887
|
+
"""Compare two arguments.
|
|
1888
|
+
|
|
1889
|
+
Args:
|
|
1890
|
+
v1 (Number): the left hand side value.
|
|
1891
|
+
v2 (Number): the right hand side value.
|
|
1892
|
+
|
|
1893
|
+
Raises:
|
|
1894
|
+
ValueError: if the comparison term's operation is invalid.
|
|
1895
|
+
|
|
1896
|
+
Returns:
|
|
1897
|
+
bool: the result of the comparison between v1 and v2 assuming the
|
|
1898
|
+
comparison operation of the comparison term object.
|
|
1899
|
+
"""
|
|
1900
|
+
if self.operation is ComparisonOperation.EQ:
|
|
1901
|
+
return v1 == v2
|
|
1902
|
+
if self.operation is ComparisonOperation.GEQ:
|
|
1903
|
+
return v1 >= v2
|
|
1904
|
+
if self.operation is ComparisonOperation.GT:
|
|
1905
|
+
return v1 > v2
|
|
1906
|
+
if self.operation is ComparisonOperation.LEQ:
|
|
1907
|
+
return v1 <= v2
|
|
1908
|
+
if self.operation is ComparisonOperation.LT:
|
|
1909
|
+
return v1 < v2
|
|
1910
|
+
if self.operation is ComparisonOperation.NEQ:
|
|
1911
|
+
return v1 != v2
|
|
1912
|
+
raise ValueError(f"Unsupported Operation of type {self.operation.value}")
|
|
1913
|
+
|
|
1914
|
+
def evaluate(self, var_values: Mapping[BaseVariable, RealNumber | list[int]]) -> bool:
|
|
1915
|
+
"""Evaluates the comparison term given a set of values for the variables in the term.
|
|
1916
|
+
|
|
1917
|
+
Args:
|
|
1918
|
+
var_values (Mapping[BaseVariable, list[int] | RealNumber]): the values of the variables in the comparison term.
|
|
1919
|
+
|
|
1920
|
+
Returns:
|
|
1921
|
+
bool: the result from evaluating the comparison term.
|
|
1922
|
+
|
|
1923
|
+
Raises:
|
|
1924
|
+
ValueError: if the constraint contains imaginary numbers.
|
|
1925
|
+
"""
|
|
1926
|
+
lhs = self._lhs.evaluate(var_values)
|
|
1927
|
+
rhs = self._rhs.evaluate(var_values)
|
|
1928
|
+
if isinstance(lhs, complex):
|
|
1929
|
+
if abs(lhs.imag) > get_settings().atol:
|
|
1930
|
+
raise ValueError("evaluating inequality constraints with complex values is not allowed")
|
|
1931
|
+
lhs = lhs.real
|
|
1932
|
+
if isinstance(rhs, complex):
|
|
1933
|
+
if abs(rhs.imag) > get_settings().atol:
|
|
1934
|
+
raise ValueError("evaluating inequality constraints with complex values is not allowed")
|
|
1935
|
+
rhs = rhs.real
|
|
1936
|
+
return self._apply_comparison_operation(lhs, rhs)
|
|
1937
|
+
|
|
1938
|
+
def __copy__(self) -> ComparisonTerm:
|
|
1939
|
+
return ComparisonTerm(rhs=copy.copy(self.rhs), lhs=copy.copy(self.lhs), operation=self.operation)
|
|
1940
|
+
|
|
1941
|
+
def __repr__(self) -> str:
|
|
1942
|
+
return f"{str(self.lhs).strip()} {self.operation.value} {str(self.rhs).strip()}"
|
|
1943
|
+
|
|
1944
|
+
__str__ = __repr__
|
|
1945
|
+
|
|
1946
|
+
def __bool__(self) -> bool:
|
|
1947
|
+
raise TypeError(
|
|
1948
|
+
"Symbolic Constraint Term objects do not have an inherent truth value. "
|
|
1949
|
+
"Use a method like .evaluate() to obtain a Boolean value."
|
|
1950
|
+
)
|
|
1951
|
+
|
|
1952
|
+
def __hash__(self) -> int:
|
|
1953
|
+
return hash((hash(self._lhs), self.operation, hash(self._rhs)))
|
|
1954
|
+
|
|
1955
|
+
def __eq__(self, other: object) -> bool:
|
|
1956
|
+
if not isinstance(other, ComparisonTerm):
|
|
1957
|
+
return False
|
|
1958
|
+
return hash(self) == hash(other)
|
|
1959
|
+
|
|
1960
|
+
|
|
1961
|
+
class MathematicalMap(Term, ABC):
|
|
1962
|
+
"""Base class for applying a mathematical map (e.g., sin, cos) to a single term or parameter."""
|
|
1963
|
+
|
|
1964
|
+
MATH_SYMBOL = ""
|
|
1965
|
+
|
|
1966
|
+
@overload
|
|
1967
|
+
def __init__(self, arg: Term, /) -> None: ...
|
|
1968
|
+
@overload
|
|
1969
|
+
def __init__(self, arg: Parameter, /) -> None: ...
|
|
1970
|
+
@overload
|
|
1971
|
+
def __init__(self, arg: BaseVariable, /) -> None: ...
|
|
1972
|
+
|
|
1973
|
+
def __init__(self, arg: Term | Parameter | BaseVariable) -> None:
|
|
1974
|
+
if isinstance(arg, Term):
|
|
1975
|
+
self._initialize_with_term(arg)
|
|
1976
|
+
elif isinstance(arg, Parameter):
|
|
1977
|
+
self._initialize_with_parameter(arg)
|
|
1978
|
+
elif isinstance(arg, BaseVariable):
|
|
1979
|
+
self._initialize_with_variable(arg)
|
|
1980
|
+
else:
|
|
1981
|
+
raise TypeError("Sin expects Term | Parameter | BaseVariable")
|
|
1982
|
+
|
|
1983
|
+
def _initialize_with_term(self, term: Term) -> None:
|
|
1984
|
+
super().__init__(elements=[term], operation=Operation.MATH_MAP)
|
|
1985
|
+
|
|
1986
|
+
def _initialize_with_parameter(self, parameter: Parameter) -> None:
|
|
1987
|
+
super().__init__(elements=[parameter], operation=Operation.MATH_MAP)
|
|
1988
|
+
|
|
1989
|
+
def _initialize_with_variable(self, variable: BaseVariable) -> None:
|
|
1990
|
+
super().__init__(elements=[variable], operation=Operation.MATH_MAP)
|
|
1991
|
+
|
|
1992
|
+
@abstractmethod
|
|
1993
|
+
def _apply_mathematical_map(self, value: Number) -> Number: ...
|
|
1994
|
+
|
|
1995
|
+
def evaluate(self, var_values: Mapping[BaseVariable, list[int] | RealNumber]) -> Number:
|
|
1996
|
+
value: Number = 0
|
|
1997
|
+
|
|
1998
|
+
for e in self:
|
|
1999
|
+
if e not in var_values and isinstance(e, Parameter):
|
|
2000
|
+
aux: Number = e.evaluate()
|
|
2001
|
+
else:
|
|
2002
|
+
aux = e.evaluate(var_values) if isinstance(e, Term) else e.evaluate(var_values[e])
|
|
2003
|
+
|
|
2004
|
+
value += aux * self[e]
|
|
2005
|
+
|
|
2006
|
+
return self._apply_mathematical_map(value)
|
|
2007
|
+
|
|
2008
|
+
def __repr__(self) -> str:
|
|
2009
|
+
return f"{self.MATH_SYMBOL}[{super().__repr__()}]"
|
|
2010
|
+
|
|
2011
|
+
__str__ = __repr__
|
|
2012
|
+
|
|
2013
|
+
|
|
2014
|
+
class Sin(MathematicalMap):
|
|
2015
|
+
"""Apply a sine map to a parameter or term."""
|
|
2016
|
+
|
|
2017
|
+
MATH_SYMBOL = "sin"
|
|
2018
|
+
|
|
2019
|
+
def _apply_mathematical_map(self, value: Number) -> Number: # noqa: PLR6301
|
|
2020
|
+
return float(np.sin(_assert_real(value)))
|
|
2021
|
+
|
|
2022
|
+
def __copy__(self) -> Sin:
|
|
2023
|
+
return Sin(super().__copy__())
|
|
2024
|
+
|
|
2025
|
+
|
|
2026
|
+
class Cos(MathematicalMap):
|
|
2027
|
+
"""Apply a cosine map to a parameter or term."""
|
|
2028
|
+
|
|
2029
|
+
MATH_SYMBOL = "cos"
|
|
2030
|
+
|
|
2031
|
+
def _apply_mathematical_map(self, value: Number) -> Number: # noqa: PLR6301
|
|
2032
|
+
return float(np.cos(_assert_real(value)))
|
|
2033
|
+
|
|
2034
|
+
def __copy__(self) -> Cos:
|
|
2035
|
+
return Cos(super().__copy__())
|