luna-quantum 1.0.8rc2__cp314-cp314-win_amd64.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.

Potentially problematic release.


This version of luna-quantum might be problematic. Click here for more details.

Files changed (264) hide show
  1. luna_quantum/__init__.py +121 -0
  2. luna_quantum/__init__.pyi +85 -0
  3. luna_quantum/_core.cp314-win_amd64.pyd +0 -0
  4. luna_quantum/_core.pyi +4185 -0
  5. luna_quantum/algorithms/__init__.py +1 -0
  6. luna_quantum/aqm_overwrites/__init__.py +3 -0
  7. luna_quantum/aqm_overwrites/model.py +184 -0
  8. luna_quantum/backends/__init__.py +1 -0
  9. luna_quantum/client/__init__.py +0 -0
  10. luna_quantum/client/controllers/__init__.py +4 -0
  11. luna_quantum/client/controllers/luna_http_client.py +37 -0
  12. luna_quantum/client/controllers/luna_platform_client.py +256 -0
  13. luna_quantum/client/controllers/luna_q.py +67 -0
  14. luna_quantum/client/controllers/luna_solve.py +129 -0
  15. luna_quantum/client/error/__init__.py +0 -0
  16. luna_quantum/client/error/luna_api_key_invalid_error.py +10 -0
  17. luna_quantum/client/error/luna_api_key_missing_error.py +10 -0
  18. luna_quantum/client/error/luna_error.py +2 -0
  19. luna_quantum/client/error/luna_server_error.py +20 -0
  20. luna_quantum/client/error/timeout_error.py +12 -0
  21. luna_quantum/client/error/transformation_error.py +18 -0
  22. luna_quantum/client/error/utils/__init__.py +0 -0
  23. luna_quantum/client/error/utils/http_error_utils.py +112 -0
  24. luna_quantum/client/interfaces/__init__.py +4 -0
  25. luna_quantum/client/interfaces/clients/__init__.py +25 -0
  26. luna_quantum/client/interfaces/clients/circuit_rest_client_i.py +68 -0
  27. luna_quantum/client/interfaces/clients/info_rest_client_i.py +53 -0
  28. luna_quantum/client/interfaces/clients/model_rest_client_i.py +139 -0
  29. luna_quantum/client/interfaces/clients/qpu_token_rest_client_i.py +364 -0
  30. luna_quantum/client/interfaces/clients/rest_client_i.py +21 -0
  31. luna_quantum/client/interfaces/clients/solve_job_rest_client_i.py +201 -0
  32. luna_quantum/client/interfaces/clients/users_rest_client_i.py +29 -0
  33. luna_quantum/client/interfaces/services/__init__.py +0 -0
  34. luna_quantum/client/interfaces/services/luna_q_i.py +34 -0
  35. luna_quantum/client/interfaces/services/luna_solve_i.py +72 -0
  36. luna_quantum/client/interfaces/services/service_i.py +56 -0
  37. luna_quantum/client/rest_client/__init__.py +15 -0
  38. luna_quantum/client/rest_client/circuit_rest_client.py +107 -0
  39. luna_quantum/client/rest_client/info_rest_client.py +74 -0
  40. luna_quantum/client/rest_client/model_rest_client.py +216 -0
  41. luna_quantum/client/rest_client/qpu_token_rest_client.py +508 -0
  42. luna_quantum/client/rest_client/solve_job_rest_client.py +286 -0
  43. luna_quantum/client/rest_client/users_rest_client.py +35 -0
  44. luna_quantum/client/schemas/__init__.py +26 -0
  45. luna_quantum/client/schemas/circuit.py +48 -0
  46. luna_quantum/client/schemas/create/__init__.py +15 -0
  47. luna_quantum/client/schemas/create/circuit.py +30 -0
  48. luna_quantum/client/schemas/create/optimization.py +39 -0
  49. luna_quantum/client/schemas/create/qpu_token.py +22 -0
  50. luna_quantum/client/schemas/create/qpu_token_time_quota.py +35 -0
  51. luna_quantum/client/schemas/create/qpu_token_time_quota_update.py +24 -0
  52. luna_quantum/client/schemas/create/qubo.py +19 -0
  53. luna_quantum/client/schemas/create/solve_job_create.py +43 -0
  54. luna_quantum/client/schemas/enums/__init__.py +0 -0
  55. luna_quantum/client/schemas/enums/call_style.py +13 -0
  56. luna_quantum/client/schemas/enums/circuit.py +42 -0
  57. luna_quantum/client/schemas/enums/model_format.py +11 -0
  58. luna_quantum/client/schemas/enums/problem.py +50 -0
  59. luna_quantum/client/schemas/enums/qpu_token_type.py +20 -0
  60. luna_quantum/client/schemas/enums/sense.py +8 -0
  61. luna_quantum/client/schemas/enums/status.py +40 -0
  62. luna_quantum/client/schemas/enums/timeframe.py +11 -0
  63. luna_quantum/client/schemas/error_message.py +14 -0
  64. luna_quantum/client/schemas/model_metadata.py +35 -0
  65. luna_quantum/client/schemas/qpu_token/__init__.py +0 -0
  66. luna_quantum/client/schemas/qpu_token/qpu_token.py +154 -0
  67. luna_quantum/client/schemas/qpu_token/qpu_token_source.py +19 -0
  68. luna_quantum/client/schemas/qpu_token/qpu_token_time_quota.py +30 -0
  69. luna_quantum/client/schemas/qpu_token/token_provider.py +132 -0
  70. luna_quantum/client/schemas/representation.py +19 -0
  71. luna_quantum/client/schemas/solution.py +106 -0
  72. luna_quantum/client/schemas/solve_job.py +50 -0
  73. luna_quantum/client/schemas/solver_info.py +11 -0
  74. luna_quantum/client/schemas/user.py +11 -0
  75. luna_quantum/client/schemas/wrappers/__init__.py +5 -0
  76. luna_quantum/client/schemas/wrappers/datetime_wrapper.py +32 -0
  77. luna_quantum/client/utils/__init__.py +0 -0
  78. luna_quantum/client/utils/qpu_token_utils.py +147 -0
  79. luna_quantum/config.py +11 -0
  80. luna_quantum/decorators.py +248 -0
  81. luna_quantum/errors.py +34 -0
  82. luna_quantum/errors.pyi +287 -0
  83. luna_quantum/exceptions/__init__.py +0 -0
  84. luna_quantum/exceptions/base_luna_quantum_error.py +2 -0
  85. luna_quantum/exceptions/patch_class_field_exists_error.py +10 -0
  86. luna_quantum/factories/__init__.py +4 -0
  87. luna_quantum/factories/luna_solve_client_factory.py +100 -0
  88. luna_quantum/factories/usecase_factory.py +457 -0
  89. luna_quantum/py.typed +0 -0
  90. luna_quantum/solve/__init__.py +13 -0
  91. luna_quantum/solve/default_token.py +304 -0
  92. luna_quantum/solve/domain/__init__.py +0 -0
  93. luna_quantum/solve/domain/abstract/__init__.py +4 -0
  94. luna_quantum/solve/domain/abstract/luna_algorithm.py +205 -0
  95. luna_quantum/solve/domain/abstract/qpu_token_backend.py +34 -0
  96. luna_quantum/solve/domain/model_metadata.py +56 -0
  97. luna_quantum/solve/domain/solve_job.py +196 -0
  98. luna_quantum/solve/errors/__init__.py +0 -0
  99. luna_quantum/solve/errors/incompatible_backend_error.py +15 -0
  100. luna_quantum/solve/errors/model_metadata_missing_error.py +11 -0
  101. luna_quantum/solve/errors/solve_base_error.py +5 -0
  102. luna_quantum/solve/errors/token_missing_error.py +11 -0
  103. luna_quantum/solve/interfaces/__init__.py +0 -0
  104. luna_quantum/solve/interfaces/algorithm_i.py +49 -0
  105. luna_quantum/solve/interfaces/backend_i.py +28 -0
  106. luna_quantum/solve/interfaces/usecases/__init__.py +55 -0
  107. luna_quantum/solve/interfaces/usecases/model_delete_usecase_i.py +27 -0
  108. luna_quantum/solve/interfaces/usecases/model_fetch_metadata_usecase_i.py +33 -0
  109. luna_quantum/solve/interfaces/usecases/model_get_solutions_usecase_i.py +33 -0
  110. luna_quantum/solve/interfaces/usecases/model_get_solve_jobs_usecase_i.py +33 -0
  111. luna_quantum/solve/interfaces/usecases/model_load_by_id_usecase_i.py +32 -0
  112. luna_quantum/solve/interfaces/usecases/model_load_by_metadata_usecase_i.py +37 -0
  113. luna_quantum/solve/interfaces/usecases/model_load_metadata_by_hash_usecase_i.py +38 -0
  114. luna_quantum/solve/interfaces/usecases/model_save_usecase_i.py +36 -0
  115. luna_quantum/solve/interfaces/usecases/solve_job_cancel_usecase_i.py +33 -0
  116. luna_quantum/solve/interfaces/usecases/solve_job_create_usecase_i.py +44 -0
  117. luna_quantum/solve/interfaces/usecases/solve_job_delete_usecase_i.py +32 -0
  118. luna_quantum/solve/interfaces/usecases/solve_job_fetch_updates_usecase_i.py +38 -0
  119. luna_quantum/solve/interfaces/usecases/solve_job_get_result_usecase_i.py +63 -0
  120. luna_quantum/solve/parameters/__init__.py +0 -0
  121. luna_quantum/solve/parameters/algorithms/__init__.py +51 -0
  122. luna_quantum/solve/parameters/algorithms/base_params/__init__.py +24 -0
  123. luna_quantum/solve/parameters/algorithms/base_params/decomposer.py +57 -0
  124. luna_quantum/solve/parameters/algorithms/base_params/qaoa_circuit_params.py +95 -0
  125. luna_quantum/solve/parameters/algorithms/base_params/quantum_annealing_params.py +79 -0
  126. luna_quantum/solve/parameters/algorithms/base_params/scipy_optimizer.py +122 -0
  127. luna_quantum/solve/parameters/algorithms/base_params/simulated_annealing_params.py +106 -0
  128. luna_quantum/solve/parameters/algorithms/base_params/tabu_kerberos_params.py +39 -0
  129. luna_quantum/solve/parameters/algorithms/base_params/tabu_search_params.py +129 -0
  130. luna_quantum/solve/parameters/algorithms/flexible_parameter_algorithm.py +59 -0
  131. luna_quantum/solve/parameters/algorithms/genetic_algorithms/__init__.py +4 -0
  132. luna_quantum/solve/parameters/algorithms/genetic_algorithms/qaga.py +131 -0
  133. luna_quantum/solve/parameters/algorithms/genetic_algorithms/saga.py +139 -0
  134. luna_quantum/solve/parameters/algorithms/lq_fda/__init__.py +3 -0
  135. luna_quantum/solve/parameters/algorithms/lq_fda/fujits_da_base.py +85 -0
  136. luna_quantum/solve/parameters/algorithms/lq_fda/fujitsu_da_v3c.py +155 -0
  137. luna_quantum/solve/parameters/algorithms/optimization_solvers/__init__.py +3 -0
  138. luna_quantum/solve/parameters/algorithms/optimization_solvers/scip.py +51 -0
  139. luna_quantum/solve/parameters/algorithms/quantum_annealing/__init__.py +19 -0
  140. luna_quantum/solve/parameters/algorithms/quantum_annealing/kerberos.py +149 -0
  141. luna_quantum/solve/parameters/algorithms/quantum_annealing/leap_hybrid_bqm.py +75 -0
  142. luna_quantum/solve/parameters/algorithms/quantum_annealing/leap_hybrid_cqm.py +75 -0
  143. luna_quantum/solve/parameters/algorithms/quantum_annealing/parallel_tempering_qpu.py +139 -0
  144. luna_quantum/solve/parameters/algorithms/quantum_annealing/population_annealing_qpu.py +109 -0
  145. luna_quantum/solve/parameters/algorithms/quantum_annealing/qbsolv_like_qpu.py +111 -0
  146. luna_quantum/solve/parameters/algorithms/quantum_annealing/quantum_annealing.py +121 -0
  147. luna_quantum/solve/parameters/algorithms/quantum_annealing/repeated_reverse_quantum_annealing.py +174 -0
  148. luna_quantum/solve/parameters/algorithms/quantum_gate/__init__.py +6 -0
  149. luna_quantum/solve/parameters/algorithms/quantum_gate/flex_qaoa/__init__.py +26 -0
  150. luna_quantum/solve/parameters/algorithms/quantum_gate/flex_qaoa/config.py +80 -0
  151. luna_quantum/solve/parameters/algorithms/quantum_gate/flex_qaoa/flex_qaoa.py +226 -0
  152. luna_quantum/solve/parameters/algorithms/quantum_gate/flex_qaoa/optimizers.py +99 -0
  153. luna_quantum/solve/parameters/algorithms/quantum_gate/flex_qaoa/pipeline.py +87 -0
  154. luna_quantum/solve/parameters/algorithms/quantum_gate/qaoa.py +102 -0
  155. luna_quantum/solve/parameters/algorithms/quantum_gate/qaoa_fo.py +69 -0
  156. luna_quantum/solve/parameters/algorithms/quantum_gate/vqe.py +108 -0
  157. luna_quantum/solve/parameters/algorithms/search_algorithms/__init__.py +5 -0
  158. luna_quantum/solve/parameters/algorithms/search_algorithms/dialectic_search.py +136 -0
  159. luna_quantum/solve/parameters/algorithms/search_algorithms/qbsolv_like_tabu_search.py +117 -0
  160. luna_quantum/solve/parameters/algorithms/search_algorithms/tabu_search.py +126 -0
  161. luna_quantum/solve/parameters/algorithms/simulated_annealing/__init__.py +13 -0
  162. luna_quantum/solve/parameters/algorithms/simulated_annealing/parallel_tempering.py +131 -0
  163. luna_quantum/solve/parameters/algorithms/simulated_annealing/population_annealing.py +95 -0
  164. luna_quantum/solve/parameters/algorithms/simulated_annealing/qbsolv_like_simulated_annealing.py +141 -0
  165. luna_quantum/solve/parameters/algorithms/simulated_annealing/repeated_reverse_simulated_annealing.py +172 -0
  166. luna_quantum/solve/parameters/algorithms/simulated_annealing/simulated_annealing.py +126 -0
  167. luna_quantum/solve/parameters/backends/__init__.py +22 -0
  168. luna_quantum/solve/parameters/backends/aqarios.py +17 -0
  169. luna_quantum/solve/parameters/backends/aws/__init__.py +11 -0
  170. luna_quantum/solve/parameters/backends/aws/aws.py +36 -0
  171. luna_quantum/solve/parameters/backends/aws/aws_backend_base.py +74 -0
  172. luna_quantum/solve/parameters/backends/aws/ionq.py +43 -0
  173. luna_quantum/solve/parameters/backends/aws/iqm.py +31 -0
  174. luna_quantum/solve/parameters/backends/aws/rigetti.py +31 -0
  175. luna_quantum/solve/parameters/backends/dwave.py +17 -0
  176. luna_quantum/solve/parameters/backends/dwave_qpu.py +166 -0
  177. luna_quantum/solve/parameters/backends/fda.py +17 -0
  178. luna_quantum/solve/parameters/backends/ibm.py +138 -0
  179. luna_quantum/solve/parameters/backends/qctrl.py +103 -0
  180. luna_quantum/solve/parameters/backends/zib.py +17 -0
  181. luna_quantum/solve/parameters/constants.py +11 -0
  182. luna_quantum/solve/parameters/mixins/__init__.py +0 -0
  183. luna_quantum/solve/parameters/mixins/fujitsu_common_params_mixin.py +239 -0
  184. luna_quantum/solve/parameters/mixins/fujitsu_v2_mixin.py +70 -0
  185. luna_quantum/solve/parameters/mixins/qbsolv_like_mixin.py +60 -0
  186. luna_quantum/solve/use_cases/__init__.py +119 -0
  187. luna_quantum/solve/use_cases/arbitrage_edge_based.py +50 -0
  188. luna_quantum/solve/use_cases/arbitrage_node_based.py +55 -0
  189. luna_quantum/solve/use_cases/base.py +7 -0
  190. luna_quantum/solve/use_cases/binary_integer_linear_programming.py +54 -0
  191. luna_quantum/solve/use_cases/binary_paint_shop_problem.py +37 -0
  192. luna_quantum/solve/use_cases/credit_scoring_feature_selection.py +40 -0
  193. luna_quantum/solve/use_cases/dynamic_portfolio_optimization.py +64 -0
  194. luna_quantum/solve/use_cases/exact_cover.py +51 -0
  195. luna_quantum/solve/use_cases/flight_gate_assignment.py +79 -0
  196. luna_quantum/solve/use_cases/graph_coloring.py +42 -0
  197. luna_quantum/solve/use_cases/graph_isomorphism.py +52 -0
  198. luna_quantum/solve/use_cases/graph_partitioning.py +46 -0
  199. luna_quantum/solve/use_cases/hamiltonian_cycle.py +49 -0
  200. luna_quantum/solve/use_cases/induced_subgraph_isomorphism.py +50 -0
  201. luna_quantum/solve/use_cases/job_shop_scheduling.py +44 -0
  202. luna_quantum/solve/use_cases/k_medoids_clustering.py +49 -0
  203. luna_quantum/solve/use_cases/knapsack_integer_weights.py +56 -0
  204. luna_quantum/solve/use_cases/linear_regression.py +60 -0
  205. luna_quantum/solve/use_cases/lmwcs.py +84 -0
  206. luna_quantum/solve/use_cases/longest_path.py +50 -0
  207. luna_quantum/solve/use_cases/market_graph_clustering.py +61 -0
  208. luna_quantum/solve/use_cases/max2sat.py +54 -0
  209. luna_quantum/solve/use_cases/max3sat.py +55 -0
  210. luna_quantum/solve/use_cases/max_clique.py +60 -0
  211. luna_quantum/solve/use_cases/max_cut.py +48 -0
  212. luna_quantum/solve/use_cases/max_independent_set.py +37 -0
  213. luna_quantum/solve/use_cases/minimal_maximal_matching.py +54 -0
  214. luna_quantum/solve/use_cases/minimal_spanning_tree.py +90 -0
  215. luna_quantum/solve/use_cases/minimum_vertex_cover.py +45 -0
  216. luna_quantum/solve/use_cases/number_partitioning.py +32 -0
  217. luna_quantum/solve/use_cases/portfolio_optimization.py +46 -0
  218. luna_quantum/solve/use_cases/portfolio_optimization_ib_tv.py +63 -0
  219. luna_quantum/solve/use_cases/quadratic_assignment.py +49 -0
  220. luna_quantum/solve/use_cases/quadratic_knapsack.py +48 -0
  221. luna_quantum/solve/use_cases/satellite_scheduling.py +73 -0
  222. luna_quantum/solve/use_cases/sensor_placement.py +58 -0
  223. luna_quantum/solve/use_cases/set_cover.py +56 -0
  224. luna_quantum/solve/use_cases/set_packing.py +54 -0
  225. luna_quantum/solve/use_cases/set_partitioning.py +52 -0
  226. luna_quantum/solve/use_cases/subgraph_isomorphism.py +55 -0
  227. luna_quantum/solve/use_cases/subset_sum.py +37 -0
  228. luna_quantum/solve/use_cases/support_vector_machine.py +64 -0
  229. luna_quantum/solve/use_cases/traffic_flow.py +35 -0
  230. luna_quantum/solve/use_cases/travelling_salesman_problem.py +53 -0
  231. luna_quantum/solve/use_cases/type_aliases.py +9 -0
  232. luna_quantum/solve/use_cases/weighted_max_cut.py +37 -0
  233. luna_quantum/solve/usecases/__init__.py +45 -0
  234. luna_quantum/solve/usecases/model_delete_usecase.py +49 -0
  235. luna_quantum/solve/usecases/model_fetch_metadata_usecase.py +50 -0
  236. luna_quantum/solve/usecases/model_get_solution_usecase.py +59 -0
  237. luna_quantum/solve/usecases/model_get_solve_jobs_usecase.py +62 -0
  238. luna_quantum/solve/usecases/model_load_by_id_usecase.py +47 -0
  239. luna_quantum/solve/usecases/model_load_by_metadata_usecase.py +52 -0
  240. luna_quantum/solve/usecases/model_load_metadata_by_hash_usecase.py +51 -0
  241. luna_quantum/solve/usecases/model_save_usecase.py +63 -0
  242. luna_quantum/solve/usecases/solve_job_cancel_usecase.py +51 -0
  243. luna_quantum/solve/usecases/solve_job_create_usecase.py +112 -0
  244. luna_quantum/solve/usecases/solve_job_delete_usecase.py +38 -0
  245. luna_quantum/solve/usecases/solve_job_fetch_updates_usecase.py +49 -0
  246. luna_quantum/solve/usecases/solve_job_get_result_usecase.py +95 -0
  247. luna_quantum/transformations.py +18 -0
  248. luna_quantum/transformations.pyi +371 -0
  249. luna_quantum/translator.py +23 -0
  250. luna_quantum/translator.pyi +869 -0
  251. luna_quantum/util/__init__.py +0 -0
  252. luna_quantum/util/active_waiting.py +79 -0
  253. luna_quantum/util/class_patcher.py +164 -0
  254. luna_quantum/util/debug_info.py +52 -0
  255. luna_quantum/util/log_utils.py +187 -0
  256. luna_quantum/util/pretty_base.py +67 -0
  257. luna_quantum/util/pydantic_utils.py +38 -0
  258. luna_quantum/utils.py +3 -0
  259. luna_quantum/utils.pyi +67 -0
  260. luna_quantum-1.0.8rc2.dist-info/METADATA +36 -0
  261. luna_quantum-1.0.8rc2.dist-info/RECORD +264 -0
  262. luna_quantum-1.0.8rc2.dist-info/WHEEL +4 -0
  263. luna_quantum-1.0.8rc2.dist-info/licenses/LICENSE +176 -0
  264. luna_quantum-1.0.8rc2.dist-info/licenses/NOTICE +13 -0
luna_quantum/_core.pyi ADDED
@@ -0,0 +1,4185 @@
1
+ from collections.abc import Callable, Iterator
2
+ from datetime import datetime, timedelta
3
+ from enum import Enum
4
+ from types import TracebackType
5
+ from typing import Literal, Self, overload
6
+ from numpy.typing import NDArray
7
+ from . import errors, transformations, translator, utils
8
+ from luna_quantum.client.interfaces.services.luna_solve_i import ILunaSolve
9
+ from luna_quantum.solve.domain.model_metadata import ModelMetadata
10
+ from luna_quantum.solve.domain.solve_job import SolveJob
11
+
12
+ class Vtype(Enum):
13
+ """
14
+ Enumeration of variable types supported by the optimization system.
15
+
16
+ This enum defines the type of a variable used in a model. The type influences
17
+ the domain and behavior of the variable during optimization. It is often passed
18
+ when defining variables to specify how they should behave.
19
+
20
+ Attributes
21
+ ----------
22
+ Real : Vtype
23
+ Continuous real-valued variable. Can take any value within given bounds.
24
+ Integer : Vtype
25
+ Discrete integer-valued variable. Takes integer values within bounds.
26
+ Binary : Vtype
27
+ Binary variable. Can only take values 0 or 1.
28
+ Spin : Vtype
29
+ Spin variable. Can only take values -1 or +1.
30
+
31
+ Examples
32
+ --------
33
+ >>> from luna_quantum import Vtype
34
+ >>> Vtype.Real
35
+ Real
36
+
37
+ >>> str(Vtype.Binary)
38
+ 'Binary'
39
+ """
40
+
41
+ Real = ...
42
+ """Continuous real-valued variable. Can take any value within given bounds."""
43
+ Integer = ...
44
+ """Discrete integer-valued variable. Takes integer values within bounds."""
45
+ Binary = ...
46
+ """Binary variable. Can only take values 0 or 1."""
47
+ Spin = ...
48
+ """Spin variable. Can only take values -1 or +1."""
49
+
50
+ def __str__(self, /) -> str: ...
51
+ def __repr__(self, /) -> str: ...
52
+
53
+ class Unbounded: ...
54
+
55
+ class Bounds:
56
+ """
57
+ Represents bounds for a variable (only supported for real and integer variables).
58
+
59
+ A `Bounds` object defines the valid interval for a variable. Bounds are inclusive,
60
+ and can be partially specified by providing only a lower or upper limit. If neither
61
+ is specified, the variable is considered unbounded.
62
+
63
+ Parameters
64
+ ----------
65
+ lower : float, optional
66
+ Lower bound of the variable. Defaults to negative infinity if not specified.
67
+ upper : float, optional
68
+ Upper bound of the variable. Defaults to positive infinity if not specified.
69
+
70
+ Examples
71
+ --------
72
+ >>> from luna_quantum import Bounds
73
+ >>> Bounds(-1.0, 1.0)
74
+ Bounds { lower: -1, upper: 1 }
75
+
76
+ >>> Bounds(lower=0.0)
77
+ Bounds { lower: -1, upper: unlimited }
78
+
79
+ >>> Bounds(upper=10.0)
80
+ Bounds { lower: unlimited, upper: 1 }
81
+
82
+ Notes
83
+ -----
84
+ - Bounds are only meaningful for variables of type `Vtype.Real` or `Vtype.Integer`.
85
+ - If both bounds are omitted, the variable is unbounded.
86
+ """
87
+
88
+ @overload
89
+ def __init__(self, /, *, lower: (float | type[Unbounded])) -> None: ...
90
+ @overload
91
+ def __init__(self, /, *, upper: (float | type[Unbounded])) -> None: ...
92
+ @overload
93
+ def __init__(
94
+ self, /, lower: (float | type[Unbounded]), upper: (float | type[Unbounded])
95
+ ) -> None: ...
96
+ def __init__(
97
+ self,
98
+ /,
99
+ lower: (float | type[Unbounded] | None) = ...,
100
+ upper: (float | type[Unbounded] | None) = ...,
101
+ ) -> None:
102
+ """
103
+ Create bounds for a variable.
104
+
105
+ See class-level docstring for full documentation.
106
+ """
107
+ ...
108
+
109
+ @property
110
+ def lower(self, /) -> float | type[Unbounded] | None:
111
+ """Get the lower bound."""
112
+ ...
113
+
114
+ @property
115
+ def upper(self, /) -> float | type[Unbounded] | None:
116
+ """Get the upper bound."""
117
+ ...
118
+
119
+ def __str__(self, /) -> str: ...
120
+ def __repr__(self, /) -> str: ...
121
+
122
+ class Variable:
123
+ """
124
+ Represents a symbolic variable within an optimization environment.
125
+
126
+ A `Variable` is the fundamental building block of algebraic expressions
127
+ used in optimization models. Each variable is tied to an `Environment`
128
+ which scopes its lifecycle and expression context. Variables can be
129
+ typed and optionally bounded.
130
+
131
+ Parameters
132
+ ----------
133
+ name : str
134
+ The name of the variable.
135
+ vtype : Vtype, optional
136
+ The variable type (e.g., `Vtype.Real`, `Vtype.Integer`, etc.).
137
+ Defaults to `Vtype.Binary`.
138
+ bounds : Bounds, optional
139
+ Bounds restricting the range of the variable. Only applicable for
140
+ `Real` and `Integer` variables.
141
+ env : Environment, optional
142
+ The environment in which this variable is created. If not provided,
143
+ the current environment from the context manager is used.
144
+
145
+ Examples
146
+ --------
147
+ >>> from luna_quantum import Variable, Environment, Vtype, Bounds
148
+ >>> with Environment():
149
+ ... x = Variable("x")
150
+ ... y = Variable("y", vtype=Vtype.Integer, bounds=Bounds(0, 5))
151
+ ... expr = 2 * x + y - 1
152
+
153
+ Arithmetic Overloads
154
+ --------------------
155
+ Variables support standard arithmetic operations:
156
+
157
+ - Addition: `x + y`, `x + 2`, `2 + x`
158
+ - Subtraction: `x - y`, `3 - x`
159
+ - Multiplication: `x * y`, `2 * x`, `x * 2`
160
+
161
+ All expressions return `Expression` objects and preserve symbolic structure.
162
+
163
+ Notes
164
+ -----
165
+ - A `Variable` is bound to a specific `Environment` instance.
166
+ - Variables are immutable; all operations yield new `Expression` objects.
167
+ - Variables carry their environment, but the environment does not own the variable.
168
+ """
169
+
170
+ @overload
171
+ def __init__(self, /, name: str) -> None: ...
172
+ @overload
173
+ def __init__(self, /, name: str, *, env: Environment) -> None: ...
174
+ @overload
175
+ def __init__(self, /, name: str, *, env: Environment, vtype: Vtype) -> None: ...
176
+ @overload
177
+ def __init__(self, /, name: str, *, vtype: Vtype) -> None: ...
178
+ @overload
179
+ def __init__(self, /, name: str, *, vtype: Vtype, bounds: Bounds) -> None: ...
180
+ @overload
181
+ def __init__(
182
+ self, /, name: str, *, vtype: Vtype, bounds: Bounds, env: Environment
183
+ ) -> None: ...
184
+ def __init__(
185
+ self,
186
+ /,
187
+ name: str,
188
+ *,
189
+ vtype: (Vtype | None) = ...,
190
+ bounds: (Bounds | None) = ...,
191
+ env: (Environment | None) = ...,
192
+ ) -> None:
193
+ """
194
+ Initialize a new Variable.
195
+
196
+ See class-level docstring for full usage.
197
+
198
+ Raises
199
+ ------
200
+ NoActiveEnvironmentFoundError
201
+ If no active environment is found and none is explicitly provided.
202
+ VariableExistsError
203
+ If a variable with the same name already exists in the environment.
204
+ VariableCreationError
205
+ If the variable is tried to be created with incompatible bounds.
206
+ """
207
+ ...
208
+
209
+ @property
210
+ def id(self, /) -> int:
211
+ """Get the id of the variable."""
212
+ ...
213
+
214
+ @property
215
+ def name(self, /) -> str:
216
+ """Get the name of the variable."""
217
+ ...
218
+
219
+ @property
220
+ def bounds(self, /) -> Bounds:
221
+ """Get the bounds of the variable."""
222
+ ...
223
+
224
+ @property
225
+ def vtype(self, /) -> Vtype:
226
+ """Get the vtype of the variable."""
227
+ ...
228
+
229
+ @overload
230
+ def __add__(self, other: int, /) -> Expression: ...
231
+ @overload
232
+ def __add__(self, other: float, /) -> Expression: ...
233
+ @overload
234
+ def __add__(self, other: Variable, /) -> Expression: ...
235
+ @overload
236
+ def __add__(self, other: Expression, /) -> Expression: ...
237
+ def __add__(self, other: (int | float | Variable | Expression), /) -> Expression:
238
+ """
239
+ Add this variable to another value.
240
+
241
+ Parameters
242
+ ----------
243
+ other : int, float, Variable or Expression.
244
+
245
+ Returns
246
+ -------
247
+ Expression
248
+ The resulting symbolic expression.
249
+
250
+ Raises
251
+ ------
252
+ VariablesFromDifferentEnvsError
253
+ If the operands belong to different environments.
254
+ TypeError
255
+ If the operand type is unsupported.
256
+ """
257
+ ...
258
+
259
+ @overload
260
+ def __radd__(self, other: int, /) -> Expression: ...
261
+ @overload
262
+ def __radd__(self, other: float, /) -> Expression: ...
263
+ @overload
264
+ def __radd__(self, other: Variable, /) -> Expression: ...
265
+ @overload
266
+ def __radd__(self, other: Expression, /) -> Expression: ...
267
+ def __radd__(self, other: (int | float | Variable | Expression), /) -> Expression:
268
+ """
269
+ Right-hand addition.
270
+
271
+ Parameters
272
+ ----------
273
+ other : int, float, Variable or Expression.
274
+
275
+ Returns
276
+ -------
277
+ Expression
278
+ The resulting symbolic expression.
279
+
280
+ Raises
281
+ ------
282
+ TypeError
283
+ If the operand type is unsupported.
284
+ """
285
+ ...
286
+
287
+ @overload
288
+ def __sub__(self, other: int, /) -> Expression: ...
289
+ @overload
290
+ def __sub__(self, other: float, /) -> Expression: ...
291
+ @overload
292
+ def __sub__(self, other: Variable, /) -> Expression: ...
293
+ @overload
294
+ def __sub__(self, other: Expression, /) -> Expression: ...
295
+ def __sub__(self, other: (int | float | Variable | Expression), /) -> Expression:
296
+ """
297
+ Subtract a value from this variable.
298
+
299
+ Parameters
300
+ ----------
301
+ other : int, float, Variable or Expression.
302
+
303
+ Returns
304
+ -------
305
+ Expression
306
+ The resulting symbolic expression.
307
+
308
+ Raises
309
+ ------
310
+ VariablesFromDifferentEnvsError
311
+ If the operands belong to different environments.
312
+ TypeError
313
+ If the operand type is unsupported.
314
+ """
315
+ ...
316
+
317
+ @overload
318
+ def __rsub__(self, other: int, /) -> Expression: ...
319
+ @overload
320
+ def __rsub__(self, other: float, /) -> Expression: ...
321
+ def __rsub__(self, other: (int | float), /) -> Expression:
322
+ """
323
+ Subtract this variable from a scalar (right-hand subtraction).
324
+
325
+ Parameters
326
+ ----------
327
+ other : int or float
328
+
329
+ Returns
330
+ -------
331
+ Expression
332
+ The resulting symbolic expression.
333
+
334
+ Raises
335
+ ------
336
+ TypeError
337
+ If `other` is not a scalar.
338
+ """
339
+ ...
340
+
341
+ @overload
342
+ def __mul__(self, other: int, /) -> Expression: ...
343
+ @overload
344
+ def __mul__(self, other: float, /) -> Expression: ...
345
+ @overload
346
+ def __mul__(self, other: Variable, /) -> Expression: ...
347
+ @overload
348
+ def __mul__(self, other: Expression, /) -> Expression: ...
349
+ def __mul__(self, other: (int | float | Variable | Expression), /) -> Expression:
350
+ """
351
+ Multiply this variable by another value.
352
+
353
+ Parameters
354
+ ----------
355
+ other : Variable, Expression, int, or float
356
+
357
+ Returns
358
+ -------
359
+ Expression
360
+ The resulting symbolic expression.
361
+
362
+ Raises
363
+ ------
364
+ VariablesFromDifferentEnvsError
365
+ If the operands belong to different environments.
366
+ TypeError
367
+ If the operand type is unsupported.
368
+ """
369
+ ...
370
+
371
+ @overload
372
+ def __rmul__(self, other: int, /) -> Expression: ...
373
+ @overload
374
+ def __rmul__(self, other: float, /) -> Expression: ...
375
+ @overload
376
+ def __rmul__(self, other: Variable, /) -> Expression: ...
377
+ @overload
378
+ def __rmul__(self, other: Expression, /) -> Expression: ...
379
+ def __rmul__(self, other: (int | float | Variable | Expression), /) -> Expression:
380
+ """
381
+ Right-hand multiplication for scalars.
382
+
383
+ Parameters
384
+ ----------
385
+ other : int or float
386
+
387
+ Returns
388
+ -------
389
+ Expression
390
+ The resulting symbolic expression.
391
+
392
+ Raises
393
+ ------
394
+ TypeError
395
+ If the operand type is unsupported.
396
+ """
397
+ ...
398
+
399
+ def __pow__(self, other: int, /) -> Expression:
400
+ """
401
+ Raise the variable to the power specified by `other`.
402
+
403
+ Parameters
404
+ ----------
405
+ other : int
406
+
407
+ Returns
408
+ -------
409
+ Expression
410
+
411
+ Raises
412
+ ------
413
+ RuntimeError
414
+ If the param `modulo` usually supported for `__pow__` is specified.
415
+ """
416
+ ...
417
+
418
+ @overload
419
+ def __eq__(self, rhs: int, /) -> Constraint: ...
420
+ @overload
421
+ def __eq__(self, rhs: float, /) -> Constraint: ...
422
+ @overload
423
+ def __eq__(self, rhs: Expression, /) -> Constraint: ...
424
+ @overload
425
+ def __eq__(self, rhs: Variable, /) -> bool:
426
+ """
427
+ Check equality of two variables.
428
+
429
+ Parameters
430
+ ----------
431
+ rhs : Variable
432
+
433
+ Returns
434
+ -------
435
+ bool
436
+ """
437
+
438
+ def __eq__(self, rhs: (int | float | Expression), /) -> Constraint:
439
+ """
440
+ Create a constraint: Variable == float | int | Expression.
441
+
442
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
443
+ constraint, resulting in the following constraint:
444
+
445
+ self - rhs == 0
446
+
447
+ Parameters
448
+ ----------
449
+ rhs : float, int or Expression
450
+
451
+ Returns
452
+ -------
453
+ Constraint
454
+
455
+ Raises
456
+ ------
457
+ TypeError
458
+ If the right-hand side is not of type float, int or Expression.
459
+ """
460
+
461
+ @overload
462
+ def __le__(self, rhs: int, /) -> Constraint: ...
463
+ @overload
464
+ def __le__(self, rhs: float, /) -> Constraint: ...
465
+ @overload
466
+ def __le__(self, rhs: Variable, /) -> Constraint: ...
467
+ @overload
468
+ def __le__(self, rhs: Expression, /) -> Constraint: ...
469
+ def __le__(self, rhs: (int | float | Variable | Expression), /) -> Constraint:
470
+ """
471
+ Create a constraint: Variable <= scalar.
472
+
473
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
474
+ constraint, resulting in the following constraint:
475
+
476
+ self - rhs <= 0
477
+
478
+ Parameters
479
+ ----------
480
+ rhs : float, int, Variable or Expression
481
+
482
+ Returns
483
+ -------
484
+ Constraint
485
+
486
+ Raises
487
+ ------
488
+ TypeError
489
+ If the right-hand side is not of type float, int, Variable or Expression.
490
+ """
491
+ ...
492
+
493
+ @overload
494
+ def __ge__(self, rhs: int, /) -> Constraint: ...
495
+ @overload
496
+ def __ge__(self, rhs: float, /) -> Constraint: ...
497
+ @overload
498
+ def __ge__(self, rhs: Variable, /) -> Constraint: ...
499
+ @overload
500
+ def __ge__(self, rhs: Expression, /) -> Constraint: ...
501
+ def __ge__(self, rhs: (int | float | Variable | Expression), /) -> Constraint:
502
+ """
503
+ Create a constraint: Variable >= scalar.
504
+
505
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
506
+ constraint, resulting in the following constraint:
507
+
508
+ self - rhs >= 0
509
+
510
+ Parameters
511
+ ----------
512
+ rhs : float, int, Variable or Expression
513
+
514
+ Returns
515
+ -------
516
+ Constraint
517
+
518
+ Raises
519
+ ------
520
+ TypeError
521
+ If the right-hand side is not of type float, int, Variable or Expression.
522
+ """
523
+ ...
524
+
525
+ def __neg__(self, /) -> Expression:
526
+ """
527
+ Negate the variable, i.e., multiply it by `-1`.
528
+
529
+ Returns
530
+ -------
531
+ Expression
532
+ """
533
+ ...
534
+
535
+ @property
536
+ def _environment(self, /) -> Environment:
537
+ """Get this variables's environment."""
538
+ ...
539
+
540
+ def __hash__(self, /) -> int: ...
541
+ def __str__(self, /) -> str: ...
542
+ def __repr__(self, /) -> str: ...
543
+
544
+ class Constant:
545
+ """A constant expression.
546
+
547
+ Convenience class to indicate the empty set of variables of an expression's
548
+ constant term when iterating over the expression's components.
549
+
550
+ Note that the bias corresponding to the constant part is not part of this class.
551
+
552
+ Examples
553
+ --------
554
+ >>> from luna_quantum import Constant, Expression, HigherOrder, Linear, Quadratic
555
+ >>> expr: Expression = ...
556
+ >>> vars: Constant | Linear | Quadratic | HigherOrder
557
+ >>> bias: float
558
+ >>> for vars, bias in expr.items():
559
+ >>> match vars:
560
+ >>> case Constant(): do_something_with_constant(bias)
561
+ >>> case Linear(x): do_something_with_linear_var(x, bias)
562
+ >>> case Quadratic(x, y): do_something_with_quadratic_vars(x, y, bias)
563
+ >>> case HigherOrder(ho): do_something_with_higher_order_vars(ho, bias)
564
+ """
565
+
566
+ class Linear:
567
+ """A linear expression.
568
+
569
+ Convenience class to indicate the variable of an expression's linear term when
570
+ iterating over the expression's components.
571
+
572
+ Note that the bias corresponding to this variable is not part of this class.
573
+
574
+ Examples
575
+ --------
576
+ >>> from luna_quantum import Constant, Expression, HigherOrder, Linear, Quadratic
577
+ >>> expr: Expression = ...
578
+ >>> vars: Constant | Linear | Quadratic | HigherOrder
579
+ >>> bias: float
580
+ >>> for vars, bias in expr.items():
581
+ >>> match vars:
582
+ >>> case Constant(): do_something_with_constant(bias)
583
+ >>> case Linear(x): do_something_with_linear_var(x, bias)
584
+ >>> case Quadratic(x, y): do_something_with_quadratic_vars(x, y, bias)
585
+ >>> case HigherOrder(ho): do_something_with_higher_order_vars(ho, bias)
586
+ """
587
+
588
+ __match_args__ = ("var",)
589
+
590
+ @property
591
+ def var(self) -> Variable: ...
592
+
593
+ class Quadratic:
594
+ """A quadratic expression.
595
+
596
+ Convenience class to indicate the variables of an expression's quadratic term when
597
+ iterating over the expression's components.
598
+
599
+ Note that the bias corresponding to these two variables is not part of this class.
600
+
601
+ Examples
602
+ --------
603
+ >>> from luna_quantum import Constant, Expression, HigherOrder, Linear, Quadratic
604
+ >>> expr: Expression = ...
605
+ >>> vars: Constant | Linear | Quadratic | HigherOrder
606
+ >>> bias: float
607
+ >>> for vars, bias in expr.items():
608
+ >>> match vars:
609
+ >>> case Constant(): do_something_with_constant(bias)
610
+ >>> case Linear(x): do_something_with_linear_var(x, bias)
611
+ >>> case Quadratic(x, y): do_something_with_quadratic_vars(x, y, bias)
612
+ >>> case HigherOrder(ho): do_something_with_higher_order_vars(ho, bias)
613
+ """
614
+
615
+ __match_args__ = "var_a", "var_b"
616
+
617
+ @property
618
+ def var_a(self) -> Variable: ...
619
+ @property
620
+ def var_b(self) -> Variable: ...
621
+
622
+ class HigherOrder:
623
+ """A higher-order expression.
624
+
625
+ Convenience class to indicate the set of variables of an expression's higher-order
626
+ term when iterating over the expression's components.
627
+
628
+ Note that the bias corresponding to these variables is not part of this class.
629
+
630
+ Examples
631
+ --------
632
+ >>> from luna_quantum import Constant, Expression, HigherOrder, Linear, Quadratic
633
+ >>> expr: Expression = ...
634
+ >>> vars: Constant | Linear | Quadratic | HigherOrder
635
+ >>> bias: float
636
+ >>> for vars, bias in expr.items():
637
+ >>> match vars:
638
+ >>> case Constant(): do_something_with_constant(bias)
639
+ >>> case Linear(x): do_something_with_linear_var(x, bias)
640
+ >>> case Quadratic(x, y): do_something_with_quadratic_vars(x, y, bias)
641
+ >>> case HigherOrder(ho): do_something_with_higher_order_vars(ho, bias)
642
+ """
643
+
644
+ __match_args__ = ("vars",)
645
+
646
+ @property
647
+ def vars(self) -> list[Variable]: ...
648
+
649
+ class Timing:
650
+ """
651
+ The object that holds information about an algorithm's runtime.
652
+
653
+ This class can only be constructed using a `Timer`. This ensures that a
654
+ `Timing` object always contains a start as well as an end time.
655
+
656
+ The `qpu` field of this class can only be set after constructing it with a timer.
657
+
658
+ Examples
659
+ --------
660
+ >>> from dwave.samplers.tree.solve import BinaryQuadraticModel
661
+ >>> from luna_quantum import Model, Timer, Timing
662
+ >>> model = ... # third-party model
663
+ >>> algorithm = ... # third-party algorithm
664
+ >>> timer = Timer.start()
665
+ >>> sol = algorithm.run(model)
666
+ >>> timing: Timing = timer.stop()
667
+ >>> timing.qpu = sol.qpu_time
668
+ >>> timing.total_seconds
669
+ 1.2999193
670
+ >>> timing.qpu
671
+ 0.02491934
672
+ """
673
+
674
+ @property
675
+ def start(self, /) -> datetime:
676
+ """The starting time of the algorithm."""
677
+ ...
678
+
679
+ @property
680
+ def end(self, /) -> datetime:
681
+ """The end, or finishing, time of the algorithm."""
682
+ ...
683
+
684
+ @property
685
+ def total(self, /) -> timedelta:
686
+ """
687
+ The difference of the end and start time.
688
+
689
+ Raises
690
+ ------
691
+ RuntimeError
692
+ If total cannot be computed due to an inconsistent start or end time.
693
+ """
694
+ ...
695
+
696
+ @property
697
+ def total_seconds(self, /) -> float:
698
+ """
699
+ The total time in seconds an algorithm needed to run.
700
+
701
+ Computed as the difference of end and start time.
702
+
703
+ Raises
704
+ ------
705
+ RuntimeError
706
+ If `total_seconds` cannot be computed due to an inconsistent start or
707
+ end time.
708
+ """
709
+ ...
710
+
711
+ @property
712
+ def qpu(self, /) -> float | None:
713
+ """The qpu usage time of the algorithm this timing object was created for."""
714
+ ...
715
+
716
+ @qpu.setter
717
+ def qpu(self, /, value: (float | None)) -> None:
718
+ """
719
+ Set the qpu usage time.
720
+
721
+ Raises
722
+ ------
723
+ ValueError
724
+ If `value` is negative.
725
+ """
726
+ ...
727
+
728
+ def add_qpu(self, /, value: float) -> None:
729
+ """
730
+ Add qpu usage time to the qpu usage time already present.
731
+
732
+ If the current value is None, this method acts like a setter.
733
+
734
+ Parameters
735
+ ----------
736
+ value : float
737
+ The value to add to the already present qpu value.
738
+
739
+ Raises
740
+ ------
741
+ ValueError
742
+ If `value` is negative.
743
+ """
744
+ ...
745
+
746
+ class Timer:
747
+ """
748
+ Used to measure the computation time of an algorithm.
749
+
750
+ The sole purpose of the `Timer` class is to create a `Timing` object in a safe
751
+ way, i.e., to ensure that the `Timing` object always holds a starting and
752
+ finishing time.
753
+
754
+ Examples
755
+ --------
756
+ Basic usage:
757
+ >>> from luna_quantum import Timer
758
+ >>> timer = Timer.start()
759
+ >>> solution = ... # create a solution by running an algorithm.
760
+ >>> timing = timer.stop()
761
+ """
762
+
763
+ @staticmethod
764
+ def start() -> Timer:
765
+ """
766
+ Create a timer that starts counting immediately.
767
+
768
+ Returns
769
+ -------
770
+ Timer
771
+ The timer.
772
+ """
773
+ ...
774
+
775
+ def stop(self, /) -> Timing:
776
+ """
777
+ Stop the timer, and get the resulting `Timing` object.
778
+
779
+ Returns
780
+ -------
781
+ Timing
782
+ The timing object that holds the start and end time.
783
+ """
784
+ ...
785
+
786
+ class ValueSource(Enum):
787
+ """Toggle enum for choosing the quantity for solution convenience functions."""
788
+
789
+ Obj = ...
790
+ """Use the `obj_values` field."""
791
+ Raw = ...
792
+ """Use the `raw_energies` field."""
793
+
794
+ class Solution:
795
+ """
796
+ The solution object that is obtained by running an algorihtm.
797
+
798
+ The `Solution` class represents a summary of all data obtained from solving a
799
+ model. It contains samples, i.e., assignments of values to each model variable as
800
+ returned by the algorithm, metadata about the solution quality, e.g., the objective
801
+ value, and the runtime of the algorithm.
802
+
803
+ A `Solution` can be constructed explicitly using `from_dict` or by obtaining a
804
+ solution from an algorithm or by converting a different solution format with one of
805
+ the available translators. Note that the latter requires the environment the model
806
+ was created in.
807
+
808
+ Examples
809
+ --------
810
+ Basic usage, assuming that the algorithm already returns a `Solution`:
811
+
812
+ >>> from luna_quantum import Model, Solution
813
+ >>> model: Model = ...
814
+ >>> algorithm = ...
815
+ >>> solution: Solution = algorithm.run(model)
816
+ >>> solution.samples
817
+ [[1, 0, 1], [0, 0, 1]]
818
+
819
+ When you have a `dimod.Sampleset` as the raw solution format:
820
+
821
+ >>> from luna_quantum.translator import BqmTranslator
822
+ >>> from luna_quantum import Model, Solution, DwaveTranslator
823
+ >>> from dimod import SimulatedAnnealingSampler
824
+ >>> model: Model = ...
825
+ >>> bqm = BqmTranslator.from_aq(model)
826
+ >>> sampleset = SimulatedAnnealingSampler().sample(bqm)
827
+ >>> solution = DwaveTranslator.from_dimod_sample_set(sampleset)
828
+ >>> solution.samples
829
+ [[1, 0, 1], [0, 0, 1]]
830
+
831
+ Serialization:
832
+
833
+ >>> blob = solution.encode()
834
+ >>> restored = Solution.decode(blob)
835
+ >>> restored.samples
836
+ [[1, 0, 1], [0, 0, 1]]
837
+
838
+ Notes
839
+ -----
840
+ - To ensure metadata like objective values or feasibility, use
841
+ `model.evaluate(solution)`.
842
+ - Use `encode()` and `decode()` to serialize and recover solutions.
843
+ """
844
+
845
+ def __str__(self, /) -> str: ...
846
+ def __repr__(self, /) -> str: ...
847
+ def __len__(self, /) -> int: ...
848
+ def __iter__(self, /) -> ResultIterator:
849
+ """
850
+ Extract a result view from the `Solution` object.
851
+
852
+ Returns
853
+ -------
854
+ ResultView
855
+
856
+ Raises
857
+ ------
858
+ TypeError
859
+ If `item` has the wrong type.
860
+ IndexError
861
+ If the row index is out of bounds for the variable environment.
862
+ """
863
+ ...
864
+
865
+ def repr_html(self, /) -> str:
866
+ """Represent the solution as a html table.
867
+
868
+ Returns
869
+ -------
870
+ str
871
+ """
872
+
873
+ def __getitem__(self, item: int, /) -> ResultView:
874
+ """
875
+ Extract a result view from the `Solution` object.
876
+
877
+ Returns
878
+ -------
879
+ ResultView
880
+
881
+ Raises
882
+ ------
883
+ TypeError
884
+ If `item` has the wrong type.
885
+ IndexError
886
+ If the row index is out of bounds for the variable environment.
887
+ """
888
+ ...
889
+
890
+ def __eq__(self, other: Solution, /) -> bool:
891
+ """
892
+ Check whether this solution is equal to `other`.
893
+
894
+ Parameters
895
+ ----------
896
+ other : Model
897
+
898
+ Returns
899
+ -------
900
+ bool
901
+ """
902
+ ...
903
+
904
+ def best(self, /) -> ResultView | None:
905
+ """
906
+ Get the best result of the solution if it exists.
907
+
908
+ A best solution is defined as the result with the lowest (in case of Sense.Min)
909
+ or the highest (in case of Sense.Max) objective value that is feasible.
910
+
911
+ Returns
912
+ -------
913
+ ResultView
914
+ The best result of the solution as a view.
915
+ """
916
+ ...
917
+
918
+ @property
919
+ def results(self, /) -> ResultIterator:
920
+ """Get an iterator over the single results of the solution."""
921
+ ...
922
+
923
+ @property
924
+ def samples(self, /) -> Samples:
925
+ """Get a view into the samples of the solution."""
926
+ ...
927
+
928
+ @property
929
+ def obj_values(self, /) -> NDArray | None:
930
+ """
931
+ Get the objective values of the single samples as a ndarray.
932
+
933
+ A value will be None if the sample hasn't yet been evaluated.
934
+ """
935
+ ...
936
+
937
+ @obj_values.setter
938
+ def obj_values(self, other: (NDArray | None)) -> None:
939
+ """Set the objective values of the single samples as a ndarray."""
940
+ ...
941
+
942
+ @property
943
+ def raw_energies(self, /) -> NDArray | None:
944
+ """Get the raw energies.
945
+
946
+ Get the raw energy values of the single samples as returned by the solver /
947
+ algorithm. Will be None if the solver / algorithm did not provide a value.
948
+ """
949
+ ...
950
+
951
+ @raw_energies.setter
952
+ def raw_energies(self, other: (NDArray | None)) -> None:
953
+ """Set the raw energies of the single samples as a ndarray."""
954
+ ...
955
+
956
+ @property
957
+ def counts(self, /) -> NDArray:
958
+ """Return how often each sample occurred in the solution."""
959
+ ...
960
+
961
+ @property
962
+ def runtime(self, /) -> Timing | None:
963
+ """Get the solver / algorithm runtime."""
964
+ ...
965
+
966
+ @property
967
+ def sense(self, /) -> Sense:
968
+ """Get the optimization sense."""
969
+ ...
970
+
971
+ @property
972
+ def best_sample_idx(self, /) -> int | None:
973
+ """Get the index of the sample with the best objective value."""
974
+ ...
975
+
976
+ @property
977
+ def variable_names(self, /) -> list[str]:
978
+ """Get the names of all variables in the solution."""
979
+ ...
980
+
981
+ def cvar(self, /, alpha: float, value_toggle: ValueSource = ...) -> float:
982
+ """
983
+ Compute the Conditional Value at Rist (CVaR) of the solution.
984
+
985
+ Parameters
986
+ ----------
987
+ float : alpha
988
+ The confidence level.
989
+
990
+ Returns
991
+ -------
992
+ float
993
+ The CVaR.
994
+
995
+ Raises
996
+ ------
997
+ ComputationError
998
+ If the computation fails for any reason.
999
+ """
1000
+ ...
1001
+
1002
+ def temperature_weighted(
1003
+ self, /, beta: float, value_toggle: ValueSource = ...
1004
+ ) -> float:
1005
+ """
1006
+ Compute the temperature weighted expectation value of the solution.
1007
+
1008
+ Parameters
1009
+ ----------
1010
+ float : beta
1011
+ The inverse temperature for computing Boltzmann weights.
1012
+
1013
+ Returns
1014
+ -------
1015
+ float
1016
+ The temperature weighted expectation value.
1017
+
1018
+ Raises
1019
+ ------
1020
+ ComputationError
1021
+ If the computation fails for any reason.
1022
+ """
1023
+ ...
1024
+
1025
+ def expectation_value(self, /, value_toggle: ValueSource = ...) -> float:
1026
+ """
1027
+ Compute the expectation value of the solution.
1028
+
1029
+ Returns
1030
+ -------
1031
+ float
1032
+ The expectation value.
1033
+
1034
+ Raises
1035
+ ------
1036
+ ComputationError
1037
+ If the computation fails for any reason.
1038
+ """
1039
+ ...
1040
+
1041
+ def feasibility_ratio(self, /) -> float:
1042
+ """
1043
+ Compute the feasibility ratio of the solution.
1044
+
1045
+ Returns
1046
+ -------
1047
+ float
1048
+ The feasibility ratio.
1049
+
1050
+ Raises
1051
+ ------
1052
+ ComputationError
1053
+ If the computation fails for any reason.
1054
+ """
1055
+ ...
1056
+
1057
+ def filter(self, /, f: Callable[[ResultView], bool]) -> Solution:
1058
+ """
1059
+ Get a new solution with all samples for which the condition `f` is true.
1060
+
1061
+ Parameters
1062
+ ----------
1063
+ f : Callable[[ResultView], bool]
1064
+ A filter function yielding true for all samples to be contained in the
1065
+ new solution.
1066
+
1067
+ Returns
1068
+ -------
1069
+ Solution
1070
+ The new solution with only samples for which the condition is true.
1071
+ """
1072
+ ...
1073
+
1074
+ def filter_feasible(self, /) -> Solution:
1075
+ """
1076
+ Get a new solution with all infeasible samples removed.
1077
+
1078
+ Returns
1079
+ -------
1080
+ The new solution with only feasible samples.
1081
+
1082
+ Raises
1083
+ ------
1084
+ ComputationError
1085
+ If the computation fails for any reason.
1086
+ """
1087
+ ...
1088
+
1089
+ def highest_constraint_violation(self, /) -> int | None:
1090
+ """
1091
+ Get the index of the constraint with the highest number of violations.
1092
+
1093
+ Returns
1094
+ -------
1095
+ int | None
1096
+ The index of the constraint with the most violations. None, if the solution
1097
+ was created for an unconstrained model.
1098
+
1099
+ Raises
1100
+ ------
1101
+ ComputationError
1102
+ If the computation fails for any reason.
1103
+ """
1104
+ ...
1105
+
1106
+ @overload
1107
+ def encode(self, /) -> bytes: ...
1108
+ @overload
1109
+ def encode(self, /, *, compress: bool) -> bytes: ...
1110
+ @overload
1111
+ def encode(self, /, *, level: int) -> bytes: ...
1112
+ @overload
1113
+ def encode(self, /, *, compress: bool, level: int) -> bytes: ...
1114
+ def encode(self, /, *, compress: bool = True, level: int = 3) -> bytes:
1115
+ """
1116
+ Serialize the solution into a compact binary format.
1117
+
1118
+ Parameters
1119
+ ----------
1120
+ compress : bool, optional
1121
+ Whether to compress the binary output. Default is True.
1122
+ level : int, optional
1123
+ Compression level (0-9). Default is 3.
1124
+
1125
+ Returns
1126
+ -------
1127
+ bytes
1128
+ Encoded model representation.
1129
+
1130
+ Raises
1131
+ ------
1132
+ IOError
1133
+ If serialization fails.
1134
+ """
1135
+ ...
1136
+
1137
+ @overload
1138
+ def serialize(self, /) -> bytes: ...
1139
+ @overload
1140
+ def serialize(self, /, *, compress: bool) -> bytes: ...
1141
+ @overload
1142
+ def serialize(self, /, *, level: int) -> bytes: ...
1143
+ @overload
1144
+ def serialize(self, /, compress: bool, level: int) -> bytes: ...
1145
+ def serialize(
1146
+ self, /, compress: (bool | None) = ..., level: (int | None) = ...
1147
+ ) -> bytes:
1148
+ """
1149
+ Alias for `encode()`.
1150
+
1151
+ See `encode()` for details.
1152
+ """
1153
+ ...
1154
+
1155
+ @classmethod
1156
+ def decode(cls, data: bytes) -> Solution:
1157
+ """
1158
+ Reconstruct a solution object from binary data.
1159
+
1160
+ Parameters
1161
+ ----------
1162
+ data : bytes
1163
+ Serialized model blob created by `encode()`.
1164
+
1165
+ Returns
1166
+ -------
1167
+ Solution
1168
+ The reconstructed solution.
1169
+
1170
+ Raises
1171
+ ------
1172
+ DecodeError
1173
+ If decoding fails due to corruption or incompatibility.
1174
+ """
1175
+ ...
1176
+
1177
+ @classmethod
1178
+ def deserialize(cls, data: bytes) -> Solution:
1179
+ """Alias for `decode()`."""
1180
+ ...
1181
+
1182
+ @overload
1183
+ @staticmethod
1184
+ def from_dict(
1185
+ data: dict[Variable, int],
1186
+ *,
1187
+ env: Environment = ...,
1188
+ model: Model = ...,
1189
+ timing: Timing = ...,
1190
+ counts: int = ...,
1191
+ sense: Sense = ...,
1192
+ ) -> Solution: ...
1193
+ @overload
1194
+ @staticmethod
1195
+ def from_dict(
1196
+ data: dict[Variable, float],
1197
+ *,
1198
+ env: Environment = ...,
1199
+ model: Model = ...,
1200
+ timing: Timing = ...,
1201
+ counts: int = ...,
1202
+ sense: Sense = ...,
1203
+ ) -> Solution: ...
1204
+ @overload
1205
+ @staticmethod
1206
+ def from_dict(
1207
+ data: dict[str, int],
1208
+ *,
1209
+ env: Environment = ...,
1210
+ model: Model = ...,
1211
+ timing: Timing = ...,
1212
+ counts: int = ...,
1213
+ sense: Sense = ...,
1214
+ ) -> Solution: ...
1215
+ @overload
1216
+ @staticmethod
1217
+ def from_dict(
1218
+ data: dict[str, float],
1219
+ *,
1220
+ env: Environment = ...,
1221
+ model: Model = ...,
1222
+ timing: Timing = ...,
1223
+ counts: int = ...,
1224
+ sense: Sense = ...,
1225
+ ) -> Solution: ...
1226
+ @overload
1227
+ @staticmethod
1228
+ def from_dict(
1229
+ data: dict[Variable | str, int],
1230
+ *,
1231
+ env: Environment = ...,
1232
+ model: Model = ...,
1233
+ timing: Timing = ...,
1234
+ counts: int = ...,
1235
+ sense: Sense = ...,
1236
+ ) -> Solution: ...
1237
+ @overload
1238
+ @staticmethod
1239
+ def from_dict(
1240
+ data: dict[Variable | str, float],
1241
+ *,
1242
+ env: Environment = ...,
1243
+ model: Model = ...,
1244
+ timing: Timing = ...,
1245
+ counts: int = ...,
1246
+ sense: Sense = ...,
1247
+ ) -> Solution: ...
1248
+ @overload
1249
+ @staticmethod
1250
+ def from_dict(
1251
+ data: dict[Variable, int | float],
1252
+ *,
1253
+ env: Environment = ...,
1254
+ model: Model = ...,
1255
+ timing: Timing = ...,
1256
+ counts: int = ...,
1257
+ sense: Sense = ...,
1258
+ ) -> Solution: ...
1259
+ @overload
1260
+ @staticmethod
1261
+ def from_dict(
1262
+ data: dict[str, int | float],
1263
+ *,
1264
+ env: Environment = ...,
1265
+ model: Model = ...,
1266
+ timing: Timing = ...,
1267
+ counts: int = ...,
1268
+ sense: Sense = ...,
1269
+ ) -> Solution: ...
1270
+ @overload
1271
+ @staticmethod
1272
+ def from_dict(
1273
+ data: dict[Variable | str, int | float],
1274
+ *,
1275
+ env: Environment = ...,
1276
+ model: Model = ...,
1277
+ timing: Timing = ...,
1278
+ counts: int = ...,
1279
+ sense: Sense = ...,
1280
+ ) -> Solution: ...
1281
+ @staticmethod
1282
+ def from_dict(
1283
+ data: dict[Variable | str, int | float],
1284
+ *,
1285
+ env: (Environment | None) = ...,
1286
+ model: (Model | None) = ...,
1287
+ timing: (Timing | None) = ...,
1288
+ counts: (int | None) = ...,
1289
+ sense: (Sense | None) = ...,
1290
+ ) -> Solution:
1291
+ """Create a `Solution` from a dict.
1292
+
1293
+ Create a `Solution` from a dict that maps variables or variable names to their
1294
+ assigned values.
1295
+
1296
+ If a Model is passed, the solution will be evaluated immediately. Otherwise,
1297
+ there has to be an environment present to determine the correct variable types.
1298
+
1299
+ Parameters
1300
+ ----------
1301
+ data : dict[Variable | str, int | float]
1302
+ The sample that shall be part of the solution.
1303
+ env : Environment, optional
1304
+ The environment the variable types shall be determined from.
1305
+ model : Model, optional
1306
+ A model to evaluate the sample with.
1307
+ counts : int, optional
1308
+ The number of occurrences of this sample.
1309
+
1310
+ Returns
1311
+ -------
1312
+ Solution
1313
+ The solution object created from the sample dict.
1314
+
1315
+ Raises
1316
+ ------
1317
+ NoActiveEnvironmentFoundError
1318
+ If no environment or model is passed to the method or available from the
1319
+ context.
1320
+ ValueError
1321
+ If `env` and `model` are both present. When this is the case, the user's
1322
+ intention is unclear as the model itself already contains an environment.
1323
+ Or if `sense` and `model` are both present as the sense is then ambiguous.
1324
+ SolutionTranslationError
1325
+ Generally if the sample translation fails. Might be specified by one of the
1326
+ three following errors.
1327
+ SampleIncorrectLengthErr
1328
+ If a sample has a different number of variables than the environment.
1329
+ SampleUnexpectedVariableError
1330
+ If a sample has a variable that is not present in the environment.
1331
+ ModelVtypeError
1332
+ If the result's variable types are incompatible with the model environment's
1333
+ variable types.
1334
+ """
1335
+ ...
1336
+
1337
+ @overload
1338
+ @staticmethod
1339
+ def from_dicts(
1340
+ data: list[dict[Variable, int]],
1341
+ *,
1342
+ env: Environment = ...,
1343
+ model: Model = ...,
1344
+ timing: Timing = ...,
1345
+ counts: list[int] = ...,
1346
+ sense: Sense = ...,
1347
+ ) -> Solution: ...
1348
+ @overload
1349
+ @staticmethod
1350
+ def from_dicts(
1351
+ data: list[dict[Variable, float]],
1352
+ *,
1353
+ env: Environment = ...,
1354
+ model: Model = ...,
1355
+ timing: Timing = ...,
1356
+ counts: list[int] = ...,
1357
+ sense: Sense = ...,
1358
+ ) -> Solution: ...
1359
+ @overload
1360
+ @staticmethod
1361
+ def from_dicts(
1362
+ data: list[dict[str, int]],
1363
+ *,
1364
+ env: Environment = ...,
1365
+ model: Model = ...,
1366
+ timing: Timing = ...,
1367
+ counts: list[int] = ...,
1368
+ sense: Sense = ...,
1369
+ ) -> Solution: ...
1370
+ @overload
1371
+ @staticmethod
1372
+ def from_dicts(
1373
+ data: list[dict[str, float]],
1374
+ *,
1375
+ env: Environment = ...,
1376
+ model: Model = ...,
1377
+ timing: Timing = ...,
1378
+ counts: list[int] = ...,
1379
+ sense: Sense = ...,
1380
+ ) -> Solution: ...
1381
+ @overload
1382
+ @staticmethod
1383
+ def from_dicts(
1384
+ data: list[dict[Variable | str, int]],
1385
+ *,
1386
+ env: Environment = ...,
1387
+ model: Model = ...,
1388
+ timing: Timing = ...,
1389
+ counts: list[int] = ...,
1390
+ sense: Sense = ...,
1391
+ ) -> Solution: ...
1392
+ @overload
1393
+ @staticmethod
1394
+ def from_dicts(
1395
+ data: list[dict[Variable | str, float]],
1396
+ *,
1397
+ env: Environment = ...,
1398
+ model: Model = ...,
1399
+ timing: Timing = ...,
1400
+ counts: list[int] = ...,
1401
+ sense: Sense = ...,
1402
+ ) -> Solution: ...
1403
+ @overload
1404
+ @staticmethod
1405
+ def from_dicts(
1406
+ data: list[dict[Variable, int | float]],
1407
+ *,
1408
+ env: Environment = ...,
1409
+ model: Model = ...,
1410
+ timing: Timing = ...,
1411
+ counts: list[int] = ...,
1412
+ sense: Sense = ...,
1413
+ ) -> Solution: ...
1414
+ @overload
1415
+ @staticmethod
1416
+ def from_dicts(
1417
+ data: list[dict[str, int | float]],
1418
+ *,
1419
+ env: Environment = ...,
1420
+ model: Model = ...,
1421
+ timing: Timing = ...,
1422
+ counts: list[int] = ...,
1423
+ sense: Sense = ...,
1424
+ ) -> Solution: ...
1425
+ @overload
1426
+ @staticmethod
1427
+ def from_dicts(
1428
+ data: list[dict[Variable | str, int | float]],
1429
+ *,
1430
+ env: Environment = ...,
1431
+ model: Model = ...,
1432
+ timing: Timing = ...,
1433
+ counts: list[int] = ...,
1434
+ sense: Sense = ...,
1435
+ ) -> Solution: ...
1436
+ @staticmethod
1437
+ def from_dicts(
1438
+ data: list[dict[Variable | str, int | float]],
1439
+ *,
1440
+ env: (Environment | None) = ...,
1441
+ model: (Model | None) = ...,
1442
+ timing: (Timing | None) = ...,
1443
+ counts: (list[int] | None) = ...,
1444
+ sense: (Sense | None) = ...,
1445
+ ) -> Solution:
1446
+ """Create a `Solution` from multiple dicts.
1447
+
1448
+ Create a `Solution` from multiple dicts that map variables or variable names to
1449
+ their assigned values. Duplicate samples contained in the `data` list are
1450
+ aggregated to a single sample.
1451
+
1452
+ If a Model is passed, the solution will be evaluated immediately. Otherwise,
1453
+ there has to be an environment present to determine the correct variable types.
1454
+
1455
+ Parameters
1456
+ ----------
1457
+ data : list[dict[Variable | str, int | float]]
1458
+ The samples that shall be part of the solution.
1459
+ env : Environment, optional
1460
+ The environment the variable types shall be determined from.
1461
+ model : Model, optional
1462
+ A model to evaluate the sample with.
1463
+ counts : int, optional
1464
+ The number of occurrences for each sample.
1465
+ sense: Sense, optional
1466
+ The sense of the optimization problem.
1467
+
1468
+ Returns
1469
+ -------
1470
+ Solution
1471
+ The solution object created from the sample dict.
1472
+
1473
+ Raises
1474
+ ------
1475
+ NoActiveEnvironmentFoundError
1476
+ If no environment or model is passed to the method or available from the
1477
+ context.
1478
+ ValueError
1479
+ If `env` and `model` are both present. When this is the case, the user's
1480
+ intention is unclear as the model itself already contains an environment.
1481
+ Or if `sense` and `model` are both present as the sense is then ambiguous.
1482
+ Or if the the number of samples and the number of counts do not match.
1483
+ SolutionTranslationError
1484
+ Generally if the sample translation fails. Might be specified by one of the
1485
+ three following errors.
1486
+ SampleIncorrectLengthErr
1487
+ If a sample has a different number of variables than the environment.
1488
+ SampleUnexpectedVariableError
1489
+ If a sample has a variable that is not present in the environment.
1490
+ ModelVtypeError
1491
+ If the result's variable types are incompatible with the model environment's
1492
+ variable types.
1493
+ """
1494
+ ...
1495
+
1496
+ @staticmethod
1497
+ def from_counts(
1498
+ data: dict[str, int],
1499
+ *,
1500
+ env: (Environment | None) = ...,
1501
+ model: (Model | None) = ...,
1502
+ timing: (Timing | None) = ...,
1503
+ sense: (Sense | None) = ...,
1504
+ bit_order: Literal["LTR", "RTL"] = "RTL",
1505
+ raw_energies: (list[float] | None) = ...,
1506
+ var_order: (list[str] | None) = ...,
1507
+ ) -> Solution:
1508
+ """
1509
+ Create a `Solution` from a dict that maps measured bitstrings to counts.
1510
+
1511
+ If a Model is passed, the solution will be evaluated immediately. Otherwise,
1512
+ there has to be an environment present to determine the correct variable types.
1513
+ Only applicable to binary or spin models.
1514
+
1515
+ Parameters
1516
+ ----------
1517
+ data : dict[str, int]
1518
+ The counts that shall be part of the solution.
1519
+ env : Environment, optional
1520
+ The environment the variable types shall be determined from.
1521
+ model : Model, optional
1522
+ A model to evaluate the sample with.
1523
+ timing : Timing, optional
1524
+ The timing for acquiring the solution.
1525
+ sense : Sense, optional
1526
+ The sense the model the solution belongs to. Default: Sense.Min
1527
+ bit_order : Literal["LTR", "RTL"]
1528
+ The order of the bits in the bitstring. Default "RTL".
1529
+ energies: list[float], optional
1530
+ The raw energies for each sample. Default None.
1531
+
1532
+ Returns
1533
+ -------
1534
+ Solution
1535
+ The solution object created from the sample dict.
1536
+
1537
+ Raises
1538
+ ------
1539
+ NoActiveEnvironmentFoundError
1540
+ If no environment or model is passed to the method or available from the
1541
+ context.
1542
+ ValueError
1543
+ If `env` and `model` are both present. When this is the case, the user's
1544
+ intention is unclear as the model itself already contains an environment.
1545
+ Or if `sense` and `model` are both present as the sense is then ambiguous.
1546
+ Or if the the environment contains non-(binary or spin) variables.
1547
+ Or if a bitstring contains chars other than '0' and '1'.
1548
+ SolutionTranslationError
1549
+ Generally if the sample translation fails. Might be specified by one of the
1550
+ three following errors.
1551
+ SampleIncorrectLengthErr
1552
+ If a sample has a different number of variables than the environment.
1553
+ """
1554
+ ...
1555
+
1556
+ def print(
1557
+ self,
1558
+ /,
1559
+ layout: Literal["row", "column"] = "column",
1560
+ max_line_length: int = 80,
1561
+ max_column_length: int = 5,
1562
+ max_lines: int = 10,
1563
+ max_var_name_length: int = 10,
1564
+ show_metadata: Literal["before", "after", "hide"] = "after",
1565
+ ) -> None:
1566
+ """
1567
+ Show a solution object as a human-readable string.
1568
+
1569
+ This method provides various ways to customize the way the solution is
1570
+ represented as a string.
1571
+
1572
+ Parameters
1573
+ ----------
1574
+ layout : Literal["row", "column"]
1575
+ With `"row"` layout, all assignments to one variable across different
1576
+ samples are shown in the same *row*, and each sample is shown in one
1577
+ column.
1578
+ With `"column"` layout, all assignments to one variable across different
1579
+ samples are shown in the same *column*, and each sample is shown in one row.
1580
+ max_line_length : int
1581
+ The max number of chars shown in one line or, in other words, the max width
1582
+ of a row.
1583
+ max_column_length : int
1584
+ The maximal number of chars in one column. For both the row and column
1585
+ layout, this controls the max number of chars a single variable assignment
1586
+ may be shown with. For the column layout, this also controls the max number
1587
+ of chars that a variable name is shown with.
1588
+ Note: the max column length cannot always be adhered to. This is
1589
+ specifically the case when a variable assignment is so high that the max
1590
+ column length is not sufficient to show the number correctly.
1591
+ max_lines : int
1592
+ The max number of lines used for showing the samples. Note that this
1593
+ parameter does not influence how metadata are shown, s.t. the total number
1594
+ of lines may be higher than `max_lines`.
1595
+ max_var_name_length : int
1596
+ The max number of chars that a variable is shown with in row layout. This
1597
+ parameter is ignored in column layout.
1598
+ show_metadata : Literal["before", "after", "hide"]
1599
+ Whether and where to show sample-specific metadata such as feasibility and
1600
+ objective value. Note that this parameter only controls how sample-specific
1601
+ metadata are shown. Other metadata, like the solution timing will be shown
1602
+ after the samples regardless of the value of this parameter.
1603
+
1604
+ - `"before"`: show metadata before the actual sample, i.e., above the
1605
+ sample in row layout, and left of the sample in column layout.
1606
+ - `"after"`: show metadata after the actual sample, i.e., below the
1607
+ sample in row layout, and right of the sample in column layout.
1608
+ - "hide": do not show sample-specific metadata.
1609
+
1610
+ Returns
1611
+ -------
1612
+ str
1613
+ The solution represented as a string.
1614
+
1615
+ Raises
1616
+ ------
1617
+ ValueError
1618
+ If at least one of the params has an invalid value.
1619
+ """
1620
+ ...
1621
+
1622
+ @overload
1623
+ def add_var(self, var: Variable, data: list[int | float]) -> None: ...
1624
+ @overload
1625
+ def add_var(
1626
+ self, var: str, data: list[int | float], vtype: (Vtype | None) = ...
1627
+ ) -> None: ...
1628
+ def add_var(
1629
+ self,
1630
+ var: (str | Variable),
1631
+ data: list[int | float],
1632
+ vtype: (Vtype | None) = ...,
1633
+ ) -> None:
1634
+ """Add a variable column to the solution.
1635
+
1636
+ Parameters
1637
+ ----------
1638
+ var : str | Variable
1639
+ The name of the variable for which the sample column is created,
1640
+ or the variable itself.
1641
+ data : list[int | float]
1642
+ The contents of the sample column to be added.
1643
+ vtype : Vtype | None, default None
1644
+ The vtype of the variable for which the sample column is created.
1645
+ If the `var` parameter is a str, the vtype is defaulted to Vtype.Binary.
1646
+ If the `var` is a Variable, the `vtype` parameter is ignored and the
1647
+ vtype of the variable is used.
1648
+
1649
+ Raises
1650
+ ------
1651
+ SampleColumnCreationError
1652
+ """
1653
+
1654
+ @overload
1655
+ def add_vars(
1656
+ self, variables: list[Variable], data: list[list[int | float]]
1657
+ ) -> None: ...
1658
+ @overload
1659
+ def add_vars(
1660
+ self, variables: list[str], data: list[list[int | float]], vtypes: list[Vtype]
1661
+ ) -> None: ...
1662
+ @overload
1663
+ def add_vars(
1664
+ self,
1665
+ variables: list[Variable | str],
1666
+ data: list[list[int | float]],
1667
+ vtypes: list[Vtype | None],
1668
+ ) -> None: ...
1669
+ def add_vars(
1670
+ self,
1671
+ variables: list[Variable | str],
1672
+ data: list[list[int | float]],
1673
+ vtypes: (list[Vtype | None] | None) = ...,
1674
+ ) -> None:
1675
+ """Add multiple variable columns to the solution.
1676
+
1677
+ Parameters
1678
+ ----------
1679
+ vars : list[str | Variable]
1680
+ The names of the variable for which the sample columns are created,
1681
+ or a list of the variables itself.
1682
+ data : list[list[int | float]]
1683
+ A list of the contents of the sample columns to be added.
1684
+ vtypes : list[Vtype] | None
1685
+ The vtypes of the variables for which the sample columns are created.
1686
+ If the `vars` parameter is a `list[str], the vtypes are defaulted to
1687
+ Vtype.Binary.
1688
+ If the `vars` is a list[Variable], the `vtypes` parameter is ignored and the
1689
+ vtypes of the variable is used.
1690
+ For mixed `vars`, the vtype is chosen dynamically following the
1691
+ two rules above.
1692
+
1693
+ Raises
1694
+ ------
1695
+ SampleColumnCreationError
1696
+ """
1697
+
1698
+ def remove_var(self, var: (str | Variable)) -> None:
1699
+ """Remove the sample column for the given variable."""
1700
+ ...
1701
+
1702
+ def remove_vars(self, variables: list[str | Variable]) -> None:
1703
+ """Remove the sample columns for the given variables."""
1704
+ ...
1705
+
1706
+ class SamplesIterator:
1707
+ """
1708
+ An iterator over a solution's samples.
1709
+
1710
+ Examples
1711
+ --------
1712
+ >>> from luna_quantum import Solution
1713
+ >>> solution: Solution = ...
1714
+
1715
+ Note: ``solution.samples`` is automatically converted into a ``SamplesIterator``.
1716
+
1717
+ >>> for sample in solution.samples:
1718
+ ... sample
1719
+ [0, -5, 0.28]
1720
+ [1, -4, -0.42]
1721
+ """
1722
+
1723
+ def __iter__(self, /) -> SamplesIterator: ...
1724
+ def __next__(self, /) -> Sample: ...
1725
+
1726
+ class SampleIterator:
1727
+ """
1728
+ An iterator over the variable assignments of a solution's sample.
1729
+
1730
+ Examples
1731
+ --------
1732
+ >>> from luna_quantum import Solution
1733
+ >>> solution: Solution = ...
1734
+ >>> sample = solution.samples[0]
1735
+
1736
+ Note: ``sample`` is automatically converted into a ``SampleIterator``.
1737
+
1738
+ >>> for var in sample:
1739
+ ... var
1740
+ 0
1741
+ -5
1742
+ 0.28
1743
+ """
1744
+
1745
+ def __iter__(self, /) -> SampleIterator: ...
1746
+ def __next__(self, /) -> int | float: ...
1747
+
1748
+ class Samples:
1749
+ """A set-like object containing every different sample of a solution.
1750
+
1751
+ A samples object is simply a set-like object that contains every different sample
1752
+ of a solution. The ``Samples`` class is readonly as it's merely a helper class for
1753
+ looking into a solution's different samples.
1754
+
1755
+ Examples
1756
+ --------
1757
+ >>> from luna_quantum import Model, Sample, Solution
1758
+ >>> model: Model = ...
1759
+ >>> solution: Solution = ...
1760
+ >>> samples: Samples = solution.samples
1761
+ >>> samples
1762
+ [0, -5, 0.28]
1763
+ [1, -4, -0.42]
1764
+ """
1765
+
1766
+ def __str__(self, /) -> str: ...
1767
+ @overload
1768
+ def __getitem__(self, item: int, /) -> Sample: ...
1769
+ @overload
1770
+ def __getitem__(self, item: tuple[int, int], /) -> int | float: ...
1771
+ def __getitem__(self, item: (int | tuple[int, int]), /) -> int | float:
1772
+ """Extract a sample or variable assignment from the ``Samples`` object.
1773
+
1774
+ If ``item`` is an int, returns the sample in this row. If ``item`` is a tuple
1775
+ of ints `(i, j)`, returns the variable assignment in row `i` and column `j`.
1776
+
1777
+ Returns
1778
+ -------
1779
+ Sample or int or float
1780
+
1781
+ Raises
1782
+ ------
1783
+ TypeError
1784
+ If ``item`` has the wrong type.
1785
+ IndexError
1786
+ If the row or column index is out of bounds for the variable environment.
1787
+ """
1788
+ ...
1789
+
1790
+ def __len__(self, /) -> int:
1791
+ """
1792
+ Get the number of samples present in this sample set.
1793
+
1794
+ Returns
1795
+ -------
1796
+ int
1797
+ """
1798
+ ...
1799
+
1800
+ def __iter__(self, /) -> SamplesIterator:
1801
+ """
1802
+ Iterate over all samples of this sample set.
1803
+
1804
+ Returns
1805
+ -------
1806
+ SamplesIterator
1807
+ """
1808
+ ...
1809
+
1810
+ def tolist(self, /) -> list[list[int | float]]:
1811
+ """Convert sample into a 2-dimensional list.
1812
+
1813
+ Convert the sample into a 2-dimensional list where a row constitutes a single
1814
+ sample, and a column constitutes all assignments for a single variable.
1815
+
1816
+ Returns
1817
+ -------
1818
+ list[list[int | float]]
1819
+ The samples object as a 2-dimensional list.
1820
+ """
1821
+ ...
1822
+
1823
+ class Sample:
1824
+ """Assignment of actual values to the model's variables.
1825
+
1826
+ A sample object is an assignment of an actual value to each of the model's
1827
+ variables.
1828
+
1829
+ The ``Sample`` class is readonly as it's merely a helper class for looking into a
1830
+ single sample of a solution.
1831
+
1832
+ Note: a ``Sample`` can be converted to ``list[int | float]`` simply by calling
1833
+ ``list(sample)``.
1834
+
1835
+ Examples
1836
+ --------
1837
+ >>> from luna_quantum import Model, Sample, Solution
1838
+ >>> model: Model = ...
1839
+ >>> solution: Solution = ...
1840
+ >>> sample: Sample = solution.samples[0]
1841
+ >>> sample
1842
+ [0, -5, 0.28]
1843
+ """
1844
+
1845
+ def __str__(self, /) -> str: ...
1846
+ @overload
1847
+ def __getitem__(self, item: int, /) -> int | float: ...
1848
+ @overload
1849
+ def __getitem__(self, item: Variable, /) -> int | float: ...
1850
+ @overload
1851
+ def __getitem__(self, item: str, /) -> int | float: ...
1852
+ def __getitem__(self, item: (int | Variable | str), /) -> int | float:
1853
+ """
1854
+ Extract a variable assignment from the ``Sample`` object.
1855
+
1856
+ Returns
1857
+ -------
1858
+ int or float
1859
+
1860
+ Raises
1861
+ ------
1862
+ TypeError
1863
+ If ``item`` has the wrong type.
1864
+ IndexError
1865
+ If the row or column index is out of bounds for the variable environment.
1866
+ """
1867
+ ...
1868
+
1869
+ def __len__(self, /) -> int:
1870
+ """
1871
+ Get the number of variables present in this sample.
1872
+
1873
+ Returns
1874
+ -------
1875
+ int
1876
+ """
1877
+ ...
1878
+
1879
+ def __iter__(self, /) -> SampleIterator:
1880
+ """
1881
+ Iterate over all variable assignments of this sample.
1882
+
1883
+ Returns
1884
+ -------
1885
+ SampleIterator
1886
+ """
1887
+ ...
1888
+
1889
+ def to_dict(self, /) -> dict[str, int | float]:
1890
+ """Convert the sample to a dictionary.
1891
+
1892
+ Returns
1893
+ -------
1894
+ dict
1895
+ A dictionary representation of the sample, where the keys are the
1896
+ variable names and the values are the variables' assignments.
1897
+ """
1898
+
1899
+ class ResultIterator:
1900
+ """
1901
+ An iterator over a solution's results.
1902
+
1903
+ Examples
1904
+ --------
1905
+ >>> from luna_quantum import ResultIterator, Solution
1906
+ >>> solution: Solution = ...
1907
+ >>> results: ResultIterator = solution.results
1908
+ >>> for result in results:
1909
+ ... result.sample
1910
+ [0, -5, 0.28]
1911
+ [1, -4, -0.42]
1912
+ """
1913
+
1914
+ def __iter__(self, /) -> ResultIterator: ...
1915
+ def __next__(self, /) -> ResultView: ...
1916
+
1917
+ class Result:
1918
+ """
1919
+ A result object can be understood as a solution with only one sample.
1920
+
1921
+ It can be obtained by calling `model.evaluate_sample` for a single sample.
1922
+
1923
+ Most properties available for the solution object are also available for a result,
1924
+ but in the singular form. For example, you can call `solution.obj_values`, but
1925
+ `result.obj_value`.
1926
+
1927
+ Examples
1928
+ --------
1929
+ >>> from luna_quantum import Model, Result, Solution
1930
+ >>> model: Model = ...
1931
+ >>> solution: Solution = ...
1932
+ >>> sample = solution.samples[0]
1933
+ >>> result = model.evaluate_sample(sample)
1934
+ >>> result.obj_value
1935
+ -109.42
1936
+ >>> result.sample
1937
+ [0, -5, 0.28]
1938
+ >>> result.constraints
1939
+ [True, False]
1940
+ >>> result.feasible
1941
+ False
1942
+ """
1943
+
1944
+ @property
1945
+ def sample(self, /) -> Sample:
1946
+ """Get the sample of the result."""
1947
+ ...
1948
+
1949
+ @property
1950
+ def obj_value(self, /) -> float | None:
1951
+ """Get the objective value of the result."""
1952
+ ...
1953
+
1954
+ @property
1955
+ def constraints(self, /) -> NDArray | None:
1956
+ """The result's feasibility of all constraints.
1957
+
1958
+ Get this result's feasibility values of all constraints. Note that
1959
+ `results.constraints[i]` iff. `model.constraints[i]` is feasible for
1960
+ this result.
1961
+ """
1962
+ ...
1963
+
1964
+ @property
1965
+ def variable_bounds(self, /) -> NDArray | None:
1966
+ """Get this result's feasibility values of all variable bounds."""
1967
+ ...
1968
+
1969
+ @property
1970
+ def feasible(self, /) -> bool | None:
1971
+ """Return whether all constraint results are feasible for this result."""
1972
+ ...
1973
+
1974
+ def __str__(self, /) -> str: ...
1975
+ def __repr__(self, /) -> str: ...
1976
+
1977
+ class ResultView:
1978
+ """
1979
+ A result view object serves as a view into one row of a solution object.
1980
+
1981
+ The `Result` class is readonly as it's merely a helper class for looking into a
1982
+ solution's row, i.e., a single sample and this sample's metadata.
1983
+
1984
+ Most properties available for the solution object are also available for a result,
1985
+ but in the singular form. For example, you can call `solution.obj_values`, but
1986
+ `result.obj_value`.
1987
+
1988
+ Examples
1989
+ --------
1990
+ >>> from luna_quantum import ResultView, Solution
1991
+ >>> solution: Solution = ...
1992
+ >>> result: ResultView = solution[0]
1993
+ >>> result.obj_value
1994
+ -109.42
1995
+ >>> result.sample
1996
+ [0, -5, 0.28]
1997
+ >>> result.constraints
1998
+ [True, False]
1999
+ >>> result.feasible
2000
+ False
2001
+ """
2002
+
2003
+ @property
2004
+ def sample(self, /) -> Sample:
2005
+ """Get the sample of the result."""
2006
+ ...
2007
+
2008
+ @property
2009
+ def counts(self, /) -> int:
2010
+ """Return how often this result appears in the solution."""
2011
+ ...
2012
+
2013
+ @property
2014
+ def obj_value(self, /) -> float | None:
2015
+ """
2016
+ Get the objective value of this sample if present.
2017
+
2018
+ This is the value computed by the corresponding AqModel.
2019
+ """
2020
+ ...
2021
+
2022
+ @property
2023
+ def raw_energy(self, /) -> float | None:
2024
+ """
2025
+ Get the raw energy returned by the algorithm if present.
2026
+
2027
+ This value is not guaranteed to be accurate under consideration of the
2028
+ corresponding AqModel.
2029
+ """
2030
+ ...
2031
+
2032
+ @property
2033
+ def constraints(self, /) -> NDArray | None:
2034
+ """
2035
+ Get this result's feasibility values of all constraints.
2036
+
2037
+ Note that `results.constraints[i]` iff. `model.constraints[i]` is feasible for
2038
+ this result.
2039
+ """
2040
+ ...
2041
+
2042
+ @property
2043
+ def variable_bounds(self, /) -> NDArray | None:
2044
+ """Get this result's feasibility values of all variable bounds."""
2045
+ ...
2046
+
2047
+ @property
2048
+ def feasible(self, /) -> bool | None:
2049
+ """Return whether all constraint results are feasible for this result."""
2050
+ ...
2051
+
2052
+ def __str__(self, /) -> str: ...
2053
+ def __repr__(self, /) -> str: ...
2054
+ def __eq__(self, other: ResultView, /) -> bool: ...
2055
+
2056
+ class Sense(Enum):
2057
+ """
2058
+ Enumeration of optimization senses supported by the optimization system.
2059
+
2060
+ This enum defines the type of optimization used for a model. The type influences
2061
+ the domain and behavior of the model during optimization.
2062
+ """
2063
+
2064
+ Min = ...
2065
+ """Indicate the objective function to be minimized."""
2066
+ Max = ...
2067
+ """Indicate the objective function to be maximized."""
2068
+
2069
+ class Model:
2070
+ """
2071
+ A symbolic optimization model consisting of an objective and constraints.
2072
+
2073
+ The `Model` class represents a structured symbolic optimization problem. It
2074
+ combines a scalar objective `Expression`, a collection of `Constraints`, and
2075
+ a shared `Environment` that scopes all variables used in the model.
2076
+
2077
+ Models can be constructed explicitly by passing an environment, or implicitly
2078
+ by allowing the model to create its own private environment. If constructed
2079
+ inside an active `Environment` context (via `with Environment()`), that context
2080
+ is used automatically.
2081
+
2082
+ Parameters
2083
+ ----------
2084
+ env : Environment, optional
2085
+ The environment in which variables and expressions are created. If not
2086
+ provided, the model will either use the current context (if active), or
2087
+ create a new private environment.
2088
+ name : str, optional
2089
+ An optional name assigned to the model.
2090
+
2091
+ Examples
2092
+ --------
2093
+ Basic usage:
2094
+
2095
+ >>> from luna_quantum import Model, Variable
2096
+ >>> model = Model("MyModel")
2097
+ >>> with model.environment:
2098
+ ... x = Variable("x")
2099
+ ... y = Variable("y")
2100
+ >>> model.objective = x * y + x
2101
+ >>> model.constraints += x >= 0
2102
+ >>> model.constraints += y <= 5
2103
+
2104
+ With explicit environment:
2105
+
2106
+ >>> from luna_quantum import Environment
2107
+ >>> env = Environment()
2108
+ >>> model = Model("ScopedModel", env)
2109
+ >>> with env:
2110
+ ... x = Variable("x")
2111
+ ... model.objective = x * x
2112
+
2113
+ Serialization:
2114
+
2115
+ >>> blob = model.encode()
2116
+ >>> restored = Model.decode(blob)
2117
+ >>> restored.name
2118
+ 'MyModel'
2119
+
2120
+ Notes
2121
+ -----
2122
+ - The `Model` class does not solve the optimization problem.
2123
+ - Use `.objective`, `.constraints`, and `.environment` to access the symbolic
2124
+ content.
2125
+ - Use `encode()` and `decode()` to serialize and recover models.
2126
+ """
2127
+
2128
+ @overload
2129
+ def __init__(self, /) -> None: ...
2130
+ @overload
2131
+ def __init__(self, /, name: str) -> None: ...
2132
+ @overload
2133
+ def __init__(self, /, name: str, *, sense: Sense) -> None: ...
2134
+ @overload
2135
+ def __init__(self, /, name: str, *, env: Environment) -> None: ...
2136
+ @overload
2137
+ def __init__(self, /, *, sense: Sense) -> None: ...
2138
+ @overload
2139
+ def __init__(self, /, *, env: Environment) -> None: ...
2140
+ @overload
2141
+ def __init__(self, /, *, sense: Sense, env: Environment) -> None: ...
2142
+ @overload
2143
+ def __init__(self, /, name: str, *, sense: Sense, env: Environment) -> None: ...
2144
+ def __init__(
2145
+ self,
2146
+ /,
2147
+ name: (str | None) = ...,
2148
+ *,
2149
+ sense: (Sense | None) = ...,
2150
+ env: (Environment | None) = ...,
2151
+ ) -> None:
2152
+ """
2153
+ Initialize a new symbolic model.
2154
+
2155
+ Parameters
2156
+ ----------
2157
+ name : str, optional
2158
+ An optional name for the model.
2159
+ env : Environment, optional
2160
+ The environment in which the model operates. If not provided, a new
2161
+ environment will be created or inferred from context.
2162
+ """
2163
+ ...
2164
+
2165
+ def set_sense(self, /, sense: Sense) -> None:
2166
+ """
2167
+ Set the optimization sense of a model.
2168
+
2169
+ Parameters
2170
+ ----------
2171
+ sense : Sense
2172
+ The sense of the model (minimization, maximization)
2173
+ """
2174
+ ...
2175
+
2176
+ @overload
2177
+ def add_variable(self, name: str, /) -> Variable: ...
2178
+ @overload
2179
+ def add_variable(self, name: str, /, vtype: (Vtype | None) = ...) -> Variable: ...
2180
+ @overload
2181
+ def add_variable(
2182
+ self, name: str, /, vtype: Vtype, *, lower: (float | type[Unbounded] | None)
2183
+ ) -> Variable: ...
2184
+ @overload
2185
+ def add_variable(
2186
+ self, name: str, /, vtype: Vtype, *, upper: (float | type[Unbounded] | None)
2187
+ ) -> Variable: ...
2188
+ @overload
2189
+ def add_variable(
2190
+ self,
2191
+ name: str,
2192
+ /,
2193
+ vtype: Vtype,
2194
+ *,
2195
+ lower: (float | type[Unbounded] | None),
2196
+ upper: (float | type[Unbounded] | None),
2197
+ ) -> Variable: ...
2198
+ def add_variable(
2199
+ self,
2200
+ name: str,
2201
+ /,
2202
+ vtype: (Vtype | None) = ...,
2203
+ *,
2204
+ lower: (float | type[Unbounded] | None) = ...,
2205
+ upper: (float | type[Unbounded] | None) = ...,
2206
+ ) -> Variable:
2207
+ """
2208
+ Add a new variable to the model.
2209
+
2210
+ Parameters
2211
+ ----------
2212
+ name : str
2213
+ The name of the variable.
2214
+ vtype : Vtype, optional
2215
+ The variable type (e.g., `Vtype.Real`, `Vtype.Integer`, etc.).
2216
+ Defaults to `Vtype.Binary`.
2217
+ lower: float, optional
2218
+ The lower bound restricts the range of the variable. Only applicable for
2219
+ `Real` and `Integer` variables.
2220
+ upper: float, optional
2221
+ The upper bound restricts the range of the variable. Only applicable for
2222
+ `Real` and `Integer` variables.
2223
+
2224
+ Returns
2225
+ -------
2226
+ Variable
2227
+ The variable added to the model.
2228
+ """
2229
+ ...
2230
+
2231
+ @overload
2232
+ def add_variable_with_fallback(self, name: str, /) -> Variable: ...
2233
+ @overload
2234
+ def add_variable_with_fallback(
2235
+ self, name: str, /, vtype: (Vtype | None) = ...
2236
+ ) -> Variable: ...
2237
+ @overload
2238
+ def add_variable_with_fallback(
2239
+ self, name: str, /, vtype: Vtype, *, lower: (float | type[Unbounded] | None)
2240
+ ) -> Variable: ...
2241
+ @overload
2242
+ def add_variable_with_fallback(
2243
+ self, name: str, /, vtype: Vtype, *, upper: (float | type[Unbounded] | None)
2244
+ ) -> Variable: ...
2245
+ @overload
2246
+ def add_variable_with_fallback(
2247
+ self,
2248
+ name: str,
2249
+ /,
2250
+ vtype: Vtype,
2251
+ *,
2252
+ lower: (float | type[Unbounded] | None),
2253
+ upper: (float | type[Unbounded] | None),
2254
+ ) -> Variable: ...
2255
+ def add_variable_with_fallback(
2256
+ self,
2257
+ name: str,
2258
+ /,
2259
+ vtype: (Vtype | None) = ...,
2260
+ *,
2261
+ lower: (float | type[Unbounded] | None) = ...,
2262
+ upper: (float | type[Unbounded] | None) = ...,
2263
+ ) -> Variable:
2264
+ """
2265
+ Add a new variable to the model with fallback renaming.
2266
+
2267
+ Parameters
2268
+ ----------
2269
+ name : str
2270
+ The name of the variable.
2271
+ vtype : Vtype, optional
2272
+ The variable type (e.g., `Vtype.Real`, `Vtype.Integer`, etc.).
2273
+ Defaults to `Vtype.Binary`.
2274
+ lower: float, optional
2275
+ The lower bound restricts the range of the variable. Only applicable for
2276
+ `Real` and `Integer` variables.
2277
+ upper: float, optional
2278
+ The upper bound restricts the range of the variable. Only applicable for
2279
+ `Real` and `Integer` variables.
2280
+
2281
+ Returns
2282
+ -------
2283
+ Variable
2284
+ The variable added to the model.
2285
+ """
2286
+ ...
2287
+
2288
+ def get_variable(self, name: str, /) -> Variable:
2289
+ """Get a variable by its label (name).
2290
+
2291
+ Parameters
2292
+ ----------
2293
+ label : str
2294
+ The name/label of the variable
2295
+
2296
+ Returns
2297
+ -------
2298
+ Variable
2299
+ The variable with the specified label/name.
2300
+
2301
+ Raises
2302
+ ------
2303
+ VariableNotExistingError
2304
+ If no variable with the specified name is registered.
2305
+ """
2306
+ ...
2307
+
2308
+ @property
2309
+ def name(self, /) -> str:
2310
+ """Return the name of the model."""
2311
+ ...
2312
+
2313
+ @name.setter
2314
+ def name(self, /, name: str) -> None:
2315
+ """Set the name of the model."""
2316
+ ...
2317
+
2318
+ @property
2319
+ def sense(self, /) -> Sense:
2320
+ """
2321
+ Get the sense of the model.
2322
+
2323
+ Returns
2324
+ -------
2325
+ Sense
2326
+ The sense of the model (Min or Max).
2327
+ """
2328
+ ...
2329
+
2330
+ @property
2331
+ def objective(self, /) -> Expression:
2332
+ """Get the objective expression of the model."""
2333
+ ...
2334
+
2335
+ @objective.setter
2336
+ def objective(self, value: Expression, /) -> None:
2337
+ """Set the objective expression of the model."""
2338
+ ...
2339
+
2340
+ @property
2341
+ def constraints(self, /) -> Constraints:
2342
+ """Access the set of constraints associated with the model."""
2343
+ ...
2344
+
2345
+ @constraints.setter
2346
+ def constraints(self, value: Constraints, /) -> None:
2347
+ """Replace the model's constraints with a new set."""
2348
+ ...
2349
+
2350
+ @property
2351
+ def environment(self, /) -> Environment:
2352
+ """Get the environment in which this model is defined."""
2353
+ ...
2354
+
2355
+ @overload
2356
+ def variables(self, /) -> list[Variable]: ...
2357
+ @overload
2358
+ def variables(self, /, *, active: bool) -> list[Variable]: ...
2359
+ def variables(self, /, active: (bool | None) = ...) -> list[Variable]:
2360
+ """
2361
+ Get all variables that are part of this model.
2362
+
2363
+ Parameters
2364
+ ----------
2365
+ active : bool, optional
2366
+ Instead of all variables from the environment, return only those that are
2367
+ actually present in the model's objective.
2368
+
2369
+ Returns
2370
+ -------
2371
+ The model's variables as a list.
2372
+ """
2373
+ ...
2374
+
2375
+ @overload
2376
+ def add_constraint(self, /, constraint: Constraint) -> None: ...
2377
+ @overload
2378
+ def add_constraint(self, /, constraint: Constraint, name: str) -> None: ...
2379
+ def add_constraint(
2380
+ self, /, constraint: Constraint, name: (str | None) = ...
2381
+ ) -> None:
2382
+ """
2383
+ Add a constraint to the model's constraint collection.
2384
+
2385
+ Parameters
2386
+ ----------
2387
+ constraint : Constraint
2388
+ The constraint to be added.
2389
+ name : str, optional
2390
+ The name of the constraint to be added.
2391
+ """
2392
+ ...
2393
+
2394
+ @overload
2395
+ def set_objective(self, /, expression: Expression) -> None: ...
2396
+ @overload
2397
+ def set_objective(self, /, expression: Expression, *, sense: Sense) -> None: ...
2398
+ def set_objective(
2399
+ self, /, expression: Expression, *, sense: (Sense | None) = ...
2400
+ ) -> None:
2401
+ """
2402
+ Set the model's objective to this expression.
2403
+
2404
+ Parameters
2405
+ ----------
2406
+ expression : Expression
2407
+ The expression assigned to the model's objective.
2408
+ sense : Sense, optional
2409
+ The sense of the model for this objective, by default Sense.Min.
2410
+ """
2411
+ ...
2412
+
2413
+ @property
2414
+ def num_variables(self, /) -> int:
2415
+ """
2416
+ Return the number of variables defined in the model.
2417
+
2418
+ Returns
2419
+ -------
2420
+ int
2421
+ Total number of variables.
2422
+ """
2423
+ ...
2424
+
2425
+ @property
2426
+ def num_constraints(self, /) -> int:
2427
+ """
2428
+ Return the number of constraints defined in the model.
2429
+
2430
+ Returns
2431
+ -------
2432
+ int
2433
+ Total number of constraints.
2434
+ """
2435
+ ...
2436
+
2437
+ def evaluate(self, /, solution: Solution) -> Solution:
2438
+ """
2439
+ Evaluate the model given a solution.
2440
+
2441
+ Parameters
2442
+ ----------
2443
+ solution : Solution
2444
+ The solution used to evaluate the model with.
2445
+
2446
+ Returns
2447
+ -------
2448
+ Solution
2449
+ A new solution object with filled-out information.
2450
+ """
2451
+ ...
2452
+
2453
+ def evaluate_sample(self, /, sample: Sample) -> Result:
2454
+ """
2455
+ Evaluate the model given a single sample.
2456
+
2457
+ Parameters
2458
+ ----------
2459
+ sample : Sample
2460
+ The sample used to evaluate the model with.
2461
+
2462
+ Returns
2463
+ -------
2464
+ Result
2465
+ A result object containing the information from the evaluation process.
2466
+ """
2467
+ ...
2468
+
2469
+ def violated_constraints(self, /, sample: Sample) -> Constraints:
2470
+ """
2471
+ Get all model constraints that are violated by the given sample.
2472
+
2473
+ Parameters
2474
+ ----------
2475
+ sample : Sample
2476
+ The sample to check constraint feasibility for.
2477
+
2478
+ Returns
2479
+ -------
2480
+ Constraints
2481
+ The constraints violated by the given sample.
2482
+ """
2483
+ ...
2484
+
2485
+ def substitute(
2486
+ self, /, target: Variable, replacement: (Expression | Variable)
2487
+ ) -> None:
2488
+ """Substitute every occurrence of variable.
2489
+
2490
+ Substitute every occurrence of a variable in the model's objective and
2491
+ constraint expressions with another expression.
2492
+
2493
+ Given a `Model` instance `self`, this method replaces all occurrences of
2494
+ `target` with `replacement` for the objective and each constraint.
2495
+ If any substitution would cross differing environments (e.g. captures from two
2496
+ different scopes), it raises a `DifferentEnvsError`.
2497
+
2498
+ Parameters
2499
+ ----------
2500
+ target : VarRef
2501
+ The variable reference to replace.
2502
+ replacement : Expression
2503
+ The expression to insert in place of `target`.
2504
+
2505
+ Returns
2506
+ -------
2507
+ None
2508
+ Performs substitution in place; no return value.
2509
+
2510
+ Raises
2511
+ ------
2512
+ DifferentEnvsError
2513
+ If the environments of `self`, `target`, and `replacement`
2514
+ are not compatible.
2515
+ """
2516
+
2517
+ @overload
2518
+ def encode(self, /) -> bytes: ...
2519
+ @overload
2520
+ def encode(self, /, *, compress: bool) -> bytes: ...
2521
+ @overload
2522
+ def encode(self, /, *, level: int) -> bytes: ...
2523
+ @overload
2524
+ def encode(self, /, compress: bool, level: int) -> bytes: ...
2525
+ def encode(
2526
+ self, /, compress: (bool | None) = True, level: (int | None) = 3
2527
+ ) -> bytes:
2528
+ """
2529
+ Serialize the model into a compact binary format.
2530
+
2531
+ Parameters
2532
+ ----------
2533
+ compress : bool, optional
2534
+ Whether to compress the binary output. Default is True.
2535
+ level : int, optional
2536
+ Compression level (0-9). Default is 3.
2537
+
2538
+ Returns
2539
+ -------
2540
+ bytes
2541
+ Encoded model representation.
2542
+
2543
+ Raises
2544
+ ------
2545
+ IOError
2546
+ If serialization fails.
2547
+ """
2548
+ ...
2549
+
2550
+ @overload
2551
+ def serialize(self, /) -> bytes: ...
2552
+ @overload
2553
+ def serialize(self, /, *, compress: bool) -> bytes: ...
2554
+ @overload
2555
+ def serialize(self, /, *, level: int) -> bytes: ...
2556
+ @overload
2557
+ def serialize(self, /, compress: bool, level: int) -> bytes: ...
2558
+ def serialize(
2559
+ self, /, compress: (bool | None) = ..., level: (int | None) = ...
2560
+ ) -> bytes:
2561
+ """
2562
+ Alias for `encode()`.
2563
+
2564
+ See `encode()` for full documentation.
2565
+ """
2566
+ ...
2567
+
2568
+ @classmethod
2569
+ def decode(cls, data: bytes) -> Model:
2570
+ """
2571
+ Reconstruct a symbolic model from binary data.
2572
+
2573
+ Parameters
2574
+ ----------
2575
+ data : bytes
2576
+ Serialized model blob created by `encode()`.
2577
+
2578
+ Returns
2579
+ -------
2580
+ Model
2581
+ The reconstructed model.
2582
+
2583
+ Raises
2584
+ ------
2585
+ DecodeError
2586
+ If decoding fails due to corruption or incompatibility.
2587
+ """
2588
+ ...
2589
+
2590
+ @classmethod
2591
+ def deserialize(cls, data: bytes) -> Model:
2592
+ """
2593
+ Alias for `decode()`.
2594
+
2595
+ See `decode()` for full documentation.
2596
+ """
2597
+ ...
2598
+
2599
+ def __eq__(self, other: Model, /) -> bool:
2600
+ """
2601
+ Check whether this model is equal to `other`.
2602
+
2603
+ Parameters
2604
+ ----------
2605
+ other : Model
2606
+
2607
+ Returns
2608
+ -------
2609
+ bool
2610
+ """
2611
+ ...
2612
+
2613
+ def equal_contents(self, other: Model, /) -> bool:
2614
+ """
2615
+ Check whether this model has equal contents as `other`.
2616
+
2617
+ Parameters
2618
+ ----------
2619
+ other : Model
2620
+
2621
+ Returns
2622
+ -------
2623
+ bool
2624
+ """
2625
+ ...
2626
+
2627
+ def vtypes(self, /) -> list[Vtype]:
2628
+ """Get a list of all unique variable types of all variables in this model."""
2629
+ ...
2630
+
2631
+ def __str__(self, /) -> str: ...
2632
+ def __repr__(self, /) -> str: ...
2633
+ def __hash__(self, /) -> int: ...
2634
+ def deep_clone(self) -> Model:
2635
+ """Make a deep clone of the model."""
2636
+ ...
2637
+ metadata: ModelMetadata | None = ...
2638
+
2639
+ @staticmethod
2640
+ def load_luna(model_id: str, client: (ILunaSolve | str | None) = None) -> Model: ...
2641
+ def save_luna(self, client: (ILunaSolve | str | None) = None) -> None: ...
2642
+ def delete_luna(self, client: (ILunaSolve | str | None) = None) -> None: ...
2643
+ def load_solutions(
2644
+ self, client: (ILunaSolve | str | None) = None
2645
+ ) -> list[Solution]: ...
2646
+ def load_solve_jobs(
2647
+ self, client: (ILunaSolve | str | None) = None
2648
+ ) -> list[SolveJob]: ...
2649
+
2650
+ class Expression:
2651
+ """
2652
+ Polynomial expression supporting symbolic arithmetic, constraint creation.
2653
+
2654
+ An `Expression` represents a real-valued mathematical function composed of
2655
+ variables, scalars, and coefficients. Expressions may include constant, linear,
2656
+ quadratic, and higher-order terms (cubic and beyond). They are used to build
2657
+ objective functions and constraints in symbolic optimization models.
2658
+
2659
+ Expressions support both regular and in-place arithmetic, including addition and
2660
+ multiplication with integers, floats, `Variable` instances, and other `Expression`s.
2661
+
2662
+ Parameters
2663
+ ----------
2664
+ env : Environment, optional
2665
+ Environment used to scope the expression when explicitly instantiating it.
2666
+ Typically, expressions are constructed implicitly via arithmetic on variables.
2667
+
2668
+ Examples
2669
+ --------
2670
+ Constructing expressions from variables:
2671
+
2672
+ >>> from luna_quantum import Environment, Variable
2673
+ >>> with Environment():
2674
+ ... x = Variable("x")
2675
+ ... y = Variable("y")
2676
+ ... expr = 1 + 2 * x + 3 * x * y + x * y * y
2677
+
2678
+ Inspecting terms:
2679
+
2680
+ >>> expr.get_offset()
2681
+ 1.0
2682
+ >>> expr.get_linear(x)
2683
+ 2.0
2684
+ >>> expr.get_quadratic(x, y)
2685
+ 3.0
2686
+ >>> expr.get_higher_order((x, y, y))
2687
+ 1.0
2688
+
2689
+ In-place arithmetic:
2690
+
2691
+ >>> expr += x
2692
+ >>> expr *= 2
2693
+
2694
+ Creating constraints:
2695
+
2696
+ >>> constraint = expr == 10.0
2697
+ >>> constraint2 = expr <= 15
2698
+
2699
+ Serialization:
2700
+
2701
+ >>> blob = expr.encode()
2702
+ >>> restored = Expression.decode(blob)
2703
+
2704
+ Supported Arithmetic
2705
+ --------------------
2706
+ The following operations are supported:
2707
+
2708
+ - Addition:
2709
+ * `expr + expr` → `Expression`
2710
+ * `expr + variable` → `Expression`
2711
+ * `expr + int | float` → `Expression`
2712
+ * `int | float + expr` → `Expression`
2713
+
2714
+ - In-place addition:
2715
+ * `expr += expr`
2716
+ * `expr += variable`
2717
+ * `expr += int | float`
2718
+
2719
+ - Multiplication:
2720
+ * `expr * expr`
2721
+ * `expr * variable`
2722
+ * `expr * int | float`
2723
+ * `int | float * expr`
2724
+
2725
+ - In-place multiplication:
2726
+ * `expr *= expr`
2727
+ * `expr *= variable`
2728
+ * `expr *= int | float`
2729
+
2730
+ - Constraint creation:
2731
+ * `expr == constant` → `Constraint`
2732
+ * `expr <= constant` → `Constraint`
2733
+ * `expr >= constant` → `Constraint`
2734
+
2735
+ Notes
2736
+ -----
2737
+ - Expressions are mutable: in-place operations (`+=`, `*=`) modify the instance.
2738
+ - Expressions are scoped to an environment via the variables they reference.
2739
+ - Comparisons like `expr == expr` return `bool`, not constraints.
2740
+ - Use `==`, `<=`, `>=` with numeric constants to create constraints.
2741
+ """
2742
+
2743
+ @overload
2744
+ def __init__(self, /) -> None: ...
2745
+ @overload
2746
+ def __init__(self, /, env: Environment) -> None: ...
2747
+ def __init__(self, /, env: (Environment | None) = ...) -> None:
2748
+ """
2749
+ Create a new empty expression scoped to an environment.
2750
+
2751
+ Parameters
2752
+ ----------
2753
+ env : Environment
2754
+ The environment to which this expression is bound.
2755
+
2756
+ Raises
2757
+ ------
2758
+ NoActiveEnvironmentFoundError
2759
+ If no environment is provided and none is active in the context.
2760
+ """
2761
+ ...
2762
+
2763
+ @overload
2764
+ @staticmethod
2765
+ def const(val: float, /) -> Expression: ...
2766
+ @overload
2767
+ @staticmethod
2768
+ def const(val: float, /, env: Environment) -> Expression: ...
2769
+ @staticmethod
2770
+ def const(val: float, /, env: (Environment | None) = None) -> Expression:
2771
+ """Create constant expression.
2772
+
2773
+ Parameters
2774
+ ----------
2775
+ val : float
2776
+ The constant
2777
+
2778
+ Returns
2779
+ -------
2780
+ Expression
2781
+ """
2782
+ ...
2783
+
2784
+ def get_offset(self, /) -> float:
2785
+ """
2786
+ Get the constant (offset) term in the expression.
2787
+
2788
+ Returns
2789
+ -------
2790
+ float
2791
+ The constant term.
2792
+ """
2793
+ ...
2794
+
2795
+ def get_linear(self, /, variable: Variable) -> float:
2796
+ """
2797
+ Get the coefficient of a linear term for a given variable.
2798
+
2799
+ Parameters
2800
+ ----------
2801
+ variable : Variable
2802
+ The variable whose linear coefficient is being queried.
2803
+
2804
+ Returns
2805
+ -------
2806
+ float
2807
+ The coefficient, or 0.0 if the variable is not present.
2808
+
2809
+ Raises
2810
+ ------
2811
+ VariableOutOfRangeError
2812
+ If the variable index is not valid in this expression's environment.
2813
+ """
2814
+ ...
2815
+
2816
+ def get_quadratic(self, /, u: Variable, v: Variable) -> float:
2817
+ """
2818
+ Get the coefficient for a quadratic term (u * v).
2819
+
2820
+ Parameters
2821
+ ----------
2822
+ u : Variable
2823
+ v : Variable
2824
+
2825
+ Returns
2826
+ -------
2827
+ float
2828
+ The coefficient, or 0.0 if not present.
2829
+
2830
+ Raises
2831
+ ------
2832
+ VariableOutOfRangeError
2833
+ If either variable is out of bounds for the expression's environment.
2834
+ """
2835
+ ...
2836
+
2837
+ def get_higher_order(self, /, variables: tuple[Variable, ...]) -> float:
2838
+ """
2839
+ Get the coefficient for a higher-order term (degree ≥ 3).
2840
+
2841
+ Parameters
2842
+ ----------
2843
+ variables : tuple of Variable
2844
+ A tuple of variables specifying the term.
2845
+
2846
+ Returns
2847
+ -------
2848
+ float
2849
+ The coefficient, or 0.0 if not present.
2850
+
2851
+ Raises
2852
+ ------
2853
+ VariableOutOfRangeError
2854
+ If any variable is out of bounds for the environment.
2855
+ """
2856
+ ...
2857
+
2858
+ def items(self, /) -> ExpressionIterator:
2859
+ """
2860
+ Iterate over the single components of an expression.
2861
+
2862
+ An *component* refers to
2863
+ a single constant, linear, quadratic, or higher-order term of an expression.
2864
+
2865
+ Returns
2866
+ -------
2867
+ ExpressionIterator
2868
+ The iterator over the expression's components.
2869
+ """
2870
+ ...
2871
+
2872
+ @property
2873
+ def num_variables(self, /) -> int:
2874
+ """
2875
+ Return the number of distinct variables in the expression.
2876
+
2877
+ Returns
2878
+ -------
2879
+ int
2880
+ Number of variables with non-zero coefficients.
2881
+ """
2882
+ ...
2883
+
2884
+ def variables(self, /) -> list[Variable]:
2885
+ """
2886
+ Get all variables that are part of this expression.
2887
+
2888
+ Returns
2889
+ -------
2890
+ list[Variable]
2891
+ The list of active variables
2892
+ """
2893
+ ...
2894
+
2895
+ def linear_items(self, /) -> list[tuple[Variable, float]]:
2896
+ """
2897
+ Get all linear components.
2898
+
2899
+ Returns
2900
+ -------
2901
+ list[tuple[Variable, float]]
2902
+ The linear components.
2903
+ """
2904
+ ...
2905
+
2906
+ def quadratic_items(self, /) -> list[tuple[Variable, Variable, float]]:
2907
+ """
2908
+ Get all quadratic components.
2909
+
2910
+ Returns
2911
+ -------
2912
+ list[tuple[Variable, Variable, float]]
2913
+ The quadratic components.
2914
+ """
2915
+ ...
2916
+
2917
+ def higher_order_items(self, /) -> list[tuple[list[Variable], float]]:
2918
+ """
2919
+ Get all higher-order components.
2920
+
2921
+ Returns
2922
+ -------
2923
+ list[tuple[list[Variable], float]]
2924
+ The higher-order components.
2925
+ """
2926
+ ...
2927
+
2928
+ def is_constant(self, /) -> bool:
2929
+ """
2930
+ Check if expression is constant.
2931
+
2932
+ Returns
2933
+ -------
2934
+ bool
2935
+ If the expression is constant
2936
+ """
2937
+ ...
2938
+
2939
+ def has_quadratic(self, /) -> bool:
2940
+ """
2941
+ Check if expression has quadratic.
2942
+
2943
+ Returns
2944
+ -------
2945
+ bool
2946
+ If the expression has quadratic
2947
+ """
2948
+ ...
2949
+
2950
+ def has_higher_order(self, /) -> bool:
2951
+ """
2952
+ Check if expression has higher-order.
2953
+
2954
+ Returns
2955
+ -------
2956
+ bool
2957
+ If the expression has higher-order
2958
+ """
2959
+ ...
2960
+
2961
+ def is_equal(self, /, other: Expression) -> bool:
2962
+ """
2963
+ Compare two expressions for equality.
2964
+
2965
+ Parameters
2966
+ ----------
2967
+ other : Expression
2968
+ The expression to which `self` is compared to.
2969
+
2970
+ Returns
2971
+ -------
2972
+ bool
2973
+ If the two expressions are equal.
2974
+ """
2975
+ ...
2976
+
2977
+ def separate(self, variables: list[Variable]) -> tuple[Expression, Expression]:
2978
+ """
2979
+ Separates expression into two expressions based on presence of variables.
2980
+
2981
+ Parameters
2982
+ ----------
2983
+ variables : list[Variable]
2984
+ The variables of which one must at least be present in a left term.
2985
+
2986
+ Returns
2987
+ -------
2988
+ tuple[Expression, Expression]
2989
+ Two expressions, left contains one of the variables right does not, i.e.
2990
+ (contains, does not contain)
2991
+ """
2992
+
2993
+ def substitute(
2994
+ self, /, target: Variable, replacement: (Expression | Variable)
2995
+ ) -> Expression:
2996
+ """
2997
+ Substitute every occurrence of a variable with another expression.
2998
+
2999
+ Given an expression `self`, this method replaces all occurrences of `target`
3000
+ with `replacement`. If the substitution would cross differing environments
3001
+ (e.g. captures from two different scopes), it returns a `DifferentEnvsErr`.
3002
+
3003
+ Parameters
3004
+ ----------
3005
+ target : VarRef
3006
+ The variable reference to replace.
3007
+ replacement : Expression
3008
+ The expression to insert in place of `target`.
3009
+
3010
+ Returns
3011
+ -------
3012
+ Expression
3013
+ The resulting expression after substitution.
3014
+
3015
+ Raises
3016
+ ------
3017
+ DifferentEnvsErr
3018
+ If the environments of `self`, `target` and `replacement`
3019
+ are not compatible.
3020
+ """
3021
+ ...
3022
+
3023
+ def equal_contents(self, other: Expression, /) -> bool:
3024
+ """
3025
+ Check whether this expression has equal contents as `other`.
3026
+
3027
+ Parameters
3028
+ ----------
3029
+ other : Expression
3030
+
3031
+ Returns
3032
+ -------
3033
+ bool
3034
+ """
3035
+ ...
3036
+
3037
+ @overload
3038
+ def encode(self, /) -> bytes: ...
3039
+ @overload
3040
+ def encode(self, /, *, compress: bool) -> bytes: ...
3041
+ @overload
3042
+ def encode(self, /, *, level: int) -> bytes: ...
3043
+ @overload
3044
+ def encode(self, /, compress: bool, level: int) -> bytes: ...
3045
+ def encode(
3046
+ self, /, compress: (bool | None) = True, level: (int | None) = 3
3047
+ ) -> bytes:
3048
+ """
3049
+ Serialize the expression into a compact binary format.
3050
+
3051
+ Parameters
3052
+ ----------
3053
+ compress : bool, optional
3054
+ Whether to compress the data. Default is True.
3055
+ level : int, optional
3056
+ Compression level (0-9). Default is 3.
3057
+
3058
+ Returns
3059
+ -------
3060
+ bytes
3061
+ Encoded representation of the expression.
3062
+
3063
+ Raises
3064
+ ------
3065
+ IOError
3066
+ If serialization fails.
3067
+ """
3068
+ ...
3069
+
3070
+ @overload
3071
+ def serialize(self, /) -> bytes: ...
3072
+ @overload
3073
+ def serialize(self, /, *, compress: bool) -> bytes: ...
3074
+ @overload
3075
+ def serialize(self, /, *, level: int) -> bytes: ...
3076
+ @overload
3077
+ def serialize(self, /, compress: bool, level: int) -> bytes: ...
3078
+ def serialize(
3079
+ self, /, compress: (bool | None) = ..., level: (int | None) = ...
3080
+ ) -> bytes:
3081
+ """
3082
+ Alias for `encode()`.
3083
+
3084
+ See `encode()` for full documentation.
3085
+ """
3086
+ ...
3087
+
3088
+ @classmethod
3089
+ def decode(cls, data: bytes, env: Environment) -> Expression:
3090
+ """
3091
+ Reconstruct an expression from encoded bytes.
3092
+
3093
+ Parameters
3094
+ ----------
3095
+ data : bytes
3096
+ Binary blob returned by `encode()`.
3097
+ env : Environment
3098
+ The environment of the expression.
3099
+
3100
+ Returns
3101
+ -------
3102
+ Expression
3103
+ Deserialized expression object.
3104
+
3105
+ Raises
3106
+ ------
3107
+ DecodeError
3108
+ If decoding fails due to corruption or incompatibility.
3109
+ """
3110
+ ...
3111
+
3112
+ @classmethod
3113
+ def deserialize(cls, data: bytes, env: Environment) -> Expression:
3114
+ """
3115
+ Alias for `decode()`.
3116
+
3117
+ See `decode()` for full documentation.
3118
+ """
3119
+ ...
3120
+
3121
+ @staticmethod
3122
+ def deep_clone_many(exprs: list[Expression]) -> list[Expression]:
3123
+ """Deep clones all provided expressions into new environment.
3124
+
3125
+ Parameters
3126
+ ----------
3127
+ exprs: list[Expression]
3128
+ The expressions to move to new_environment
3129
+
3130
+ Returns
3131
+ -------
3132
+ list[Expressions]
3133
+ The same expressions but part of a new environment
3134
+ """
3135
+ ...
3136
+
3137
+ @overload
3138
+ def __add__(self, other: Expression, /) -> Expression: ...
3139
+ @overload
3140
+ def __add__(self, other: Variable, /) -> Expression: ...
3141
+ @overload
3142
+ def __add__(self, other: int, /) -> Expression: ...
3143
+ @overload
3144
+ def __add__(self, other: float, /) -> Expression: ...
3145
+ def __add__(self, other: (Expression | Variable | int | float), /) -> Expression:
3146
+ """
3147
+ Add another expression, variable, or scalar.
3148
+
3149
+ Parameters
3150
+ ----------
3151
+ other : Expression, Variable, int, or float
3152
+
3153
+ Returns
3154
+ -------
3155
+ Expression
3156
+
3157
+ Raises
3158
+ ------
3159
+ VariablesFromDifferentEnvsError
3160
+ If operands are from different environments.
3161
+ TypeError
3162
+ If the operand type is unsupported.
3163
+ """
3164
+ ...
3165
+
3166
+ @overload
3167
+ def __radd__(self, other: Expression, /) -> Expression: ...
3168
+ @overload
3169
+ def __radd__(self, other: Variable, /) -> Expression: ...
3170
+ @overload
3171
+ def __radd__(self, other: int, /) -> Expression: ...
3172
+ @overload
3173
+ def __radd__(self, other: float, /) -> Expression: ...
3174
+ def __radd__(self, other: (Expression | Variable | int | float), /) -> Expression:
3175
+ """
3176
+ Add this expression to a scalar or variable.
3177
+
3178
+ Parameters
3179
+ ----------
3180
+ other : int, float, or Variable
3181
+
3182
+ Returns
3183
+ -------
3184
+ Expression
3185
+
3186
+ Raises
3187
+ ------
3188
+ TypeError
3189
+ If the operand type is unsupported.
3190
+ """
3191
+ ...
3192
+
3193
+ @overload
3194
+ def __iadd__(self, other: Expression, /) -> Self: ...
3195
+ @overload
3196
+ def __iadd__(self, other: Variable, /) -> Self: ...
3197
+ @overload
3198
+ def __iadd__(self, other: int, /) -> Self: ...
3199
+ @overload
3200
+ def __iadd__(self, other: float, /) -> Self: ...
3201
+ def __iadd__(self, other: (Expression | Variable | int | float), /) -> Self:
3202
+ """
3203
+ In-place addition.
3204
+
3205
+ Parameters
3206
+ ----------
3207
+ other : Expression, Variable, int, or float
3208
+
3209
+ Returns
3210
+ -------
3211
+ Self
3212
+
3213
+ Raises
3214
+ ------
3215
+ VariablesFromDifferentEnvsError
3216
+ If operands are from different environments.
3217
+ TypeError
3218
+ If the operand type is unsupported.
3219
+ """
3220
+ ...
3221
+
3222
+ @overload
3223
+ def __isub__(self, other: Expression, /) -> Self: ...
3224
+ @overload
3225
+ def __isub__(self, other: Variable, /) -> Self: ...
3226
+ @overload
3227
+ def __isub__(self, other: int, /) -> Self: ...
3228
+ @overload
3229
+ def __isub__(self, other: float, /) -> Self: ...
3230
+ def __isub__(self, other: (Expression | Variable | int | float), /) -> Self:
3231
+ """
3232
+ In-place subtraction.
3233
+
3234
+ Parameters
3235
+ ----------
3236
+ other : Expression, Variable, int, or float
3237
+
3238
+ Returns
3239
+ -------
3240
+ Self
3241
+
3242
+ Raises
3243
+ ------
3244
+ VariablesFromDifferentEnvsError
3245
+ If operands are from different environments.
3246
+ TypeError
3247
+ If the operand type is unsupported.
3248
+ """
3249
+ ...
3250
+
3251
+ @overload
3252
+ def __sub__(self, other: Expression, /) -> Expression: ...
3253
+ @overload
3254
+ def __sub__(self, other: Variable, /) -> Expression: ...
3255
+ @overload
3256
+ def __sub__(self, other: int, /) -> Expression: ...
3257
+ @overload
3258
+ def __sub__(self, other: float, /) -> Expression: ...
3259
+ def __sub__(self, other: (Expression | Variable | int | float), /) -> Expression:
3260
+ """
3261
+ Subtract another expression, variable, or scalar.
3262
+
3263
+ Parameters
3264
+ ----------
3265
+ other : Expression, Variable, int, or float
3266
+
3267
+ Returns
3268
+ -------
3269
+ Expression
3270
+
3271
+ Raises
3272
+ ------
3273
+ VariablesFromDifferentEnvsError
3274
+ If operands are from different environments.
3275
+ TypeError
3276
+ If the operand type is unsupported.
3277
+ """
3278
+ ...
3279
+
3280
+ @overload
3281
+ def __mul__(self, other: Expression, /) -> Expression: ...
3282
+ @overload
3283
+ def __mul__(self, other: Variable, /) -> Expression: ...
3284
+ @overload
3285
+ def __mul__(self, other: int, /) -> Expression: ...
3286
+ @overload
3287
+ def __mul__(self, other: float, /) -> Expression: ...
3288
+ def __mul__(self, other: (Expression | Variable | int | float), /) -> Expression:
3289
+ """
3290
+ Multiply this expression by another value.
3291
+
3292
+ Parameters
3293
+ ----------
3294
+ other : Expression, Variable, int, or float
3295
+
3296
+ Returns
3297
+ -------
3298
+ Expression
3299
+
3300
+ Raises
3301
+ ------
3302
+ VariablesFromDifferentEnvsError
3303
+ If operands are from different environments.
3304
+ TypeError
3305
+ If the operand type is unsupported.
3306
+ """
3307
+ ...
3308
+
3309
+ @overload
3310
+ def __rmul__(self, other: int, /) -> Expression: ...
3311
+ @overload
3312
+ def __rmul__(self, other: float, /) -> Expression: ...
3313
+ def __rmul__(self, other: (int | float), /) -> Expression:
3314
+ """
3315
+ Right-hand multiplication.
3316
+
3317
+ Parameters
3318
+ ----------
3319
+ other : int or float
3320
+
3321
+ Returns
3322
+ -------
3323
+ Expression
3324
+
3325
+ Raises
3326
+ ------
3327
+ TypeError
3328
+ If the operand type is unsupported.
3329
+ """
3330
+ ...
3331
+
3332
+ @overload
3333
+ def __imul__(self, other: Expression, /) -> Self: ...
3334
+ @overload
3335
+ def __imul__(self, other: Variable, /) -> Self: ...
3336
+ @overload
3337
+ def __imul__(self, other: int, /) -> Self: ...
3338
+ @overload
3339
+ def __imul__(self, other: float, /) -> Self: ...
3340
+ def __imul__(self, other: (Expression | Variable | int | float), /) -> Self:
3341
+ """
3342
+ In-place multiplication.
3343
+
3344
+ Parameters
3345
+ ----------
3346
+ other : Expression, Variable, int, or float
3347
+
3348
+ Returns
3349
+ -------
3350
+ Self
3351
+
3352
+ Raises
3353
+ ------
3354
+ VariablesFromDifferentEnvsError
3355
+ If operands are from different environments.
3356
+ TypeError
3357
+ If the operand type is unsupported.
3358
+ """
3359
+ ...
3360
+
3361
+ def __pow__(self, other: int, /) -> Expression:
3362
+ """
3363
+ Raise the expression to the power specified by `other`.
3364
+
3365
+ Parameters
3366
+ ----------
3367
+ other : int
3368
+
3369
+ Returns
3370
+ -------
3371
+ Expression
3372
+
3373
+ Raises
3374
+ ------
3375
+ RuntimeError
3376
+ If the param `modulo` usually supported for `__pow__` is specified.
3377
+ """
3378
+ ...
3379
+
3380
+ @overload
3381
+ def __eq__(self, rhs: Expression, /) -> Constraint: ...
3382
+ @overload
3383
+ def __eq__(self, rhs: Variable, /) -> Constraint: ...
3384
+ @overload
3385
+ def __eq__(self, rhs: int, /) -> Constraint: ...
3386
+ @overload
3387
+ def __eq__(self, rhs: float, /) -> Constraint: ...
3388
+ def __eq__(self, rhs: (Expression | Variable | int | float), /) -> Constraint:
3389
+ """
3390
+ Compare to a different expression or create a constraint `expression == scalar`.
3391
+
3392
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
3393
+ constraint, resulting in the following constraint:
3394
+
3395
+ self - rhs == 0
3396
+
3397
+ Parameters
3398
+ ----------
3399
+ rhs : Expression or float, int, Variable or Expression
3400
+
3401
+ Returns
3402
+ -------
3403
+ bool or Constraint
3404
+
3405
+ Raises
3406
+ ------
3407
+ TypeError
3408
+ If the right-hand side is not an Expression or scalar.
3409
+ """
3410
+ ...
3411
+
3412
+ @overload
3413
+ def __le__(self, rhs: Expression, /) -> Constraint: ...
3414
+ @overload
3415
+ def __le__(self, rhs: Variable, /) -> Constraint: ...
3416
+ @overload
3417
+ def __le__(self, rhs: int, /) -> Constraint: ...
3418
+ @overload
3419
+ def __le__(self, rhs: float, /) -> Constraint: ...
3420
+ def __le__(self, rhs: (Expression | Variable | int | float), /) -> Constraint:
3421
+ """
3422
+ Create a constraint `expression <= scalar`.
3423
+
3424
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
3425
+ constraint, resulting in the following constraint:
3426
+
3427
+ self - rhs <= 0
3428
+
3429
+ Parameters
3430
+ ----------
3431
+ rhs : float, int, Variable or Expression
3432
+
3433
+ Returns
3434
+ -------
3435
+ Constraint
3436
+
3437
+ Raises
3438
+ ------
3439
+ TypeError
3440
+ If the right-hand side is not of type float, int, Variable or Expression.
3441
+ """
3442
+ ...
3443
+
3444
+ @overload
3445
+ def __ge__(self, rhs: Expression, /) -> Constraint: ...
3446
+ @overload
3447
+ def __ge__(self, rhs: Variable, /) -> Constraint: ...
3448
+ @overload
3449
+ def __ge__(self, rhs: int, /) -> Constraint: ...
3450
+ @overload
3451
+ def __ge__(self, rhs: float, /) -> Constraint: ...
3452
+ def __ge__(self, rhs: (Expression | Variable | int | float), /) -> Constraint:
3453
+ """
3454
+ Create a constraint: expression >= scalar.
3455
+
3456
+ If `rhs` is of type `Variable` or `Expression` it is moved to the `lhs` in the
3457
+ constraint, resulting in the following constraint:
3458
+
3459
+ self - rhs >= 0
3460
+
3461
+ Parameters
3462
+ ----------
3463
+ rhs : float, int, Variable or Expression
3464
+
3465
+ Returns
3466
+ -------
3467
+ Constraint
3468
+
3469
+ Raises
3470
+ ------
3471
+ TypeError
3472
+ If the right-hand side is not of type float, int, Variable or Expression.
3473
+ """
3474
+ ...
3475
+
3476
+ def __neg__(self, /) -> Expression:
3477
+ """
3478
+ Negate the expression, i.e., multiply it by `-1`.
3479
+
3480
+ Returns
3481
+ -------
3482
+ Expression
3483
+ """
3484
+ ...
3485
+
3486
+ def degree(self, /) -> int:
3487
+ """Get the degree of this expression."""
3488
+ ...
3489
+
3490
+ @property
3491
+ def environment(self, /) -> Environment:
3492
+ """Get this expression's environment."""
3493
+ ...
3494
+
3495
+ def __str__(self, /) -> str: ...
3496
+ def __repr__(self, /) -> str: ...
3497
+ def evaluate(self, solution: Solution, /) -> NDArray:
3498
+ """Evaluate an expression based on an existing solution."""
3499
+ ...
3500
+
3501
+ class ExpressionIterator:
3502
+ """
3503
+ Iterate over the single components of an expression.
3504
+
3505
+ Examples
3506
+ --------
3507
+ >>> from luna_quantum import Constant, Expression, HigherOrder, Linear, Quadratic
3508
+ >>> expr: Expression = ...
3509
+ >>> vars: Constant | Linear | Quadratic | HigherOrder
3510
+ >>> bias: float
3511
+ >>> for vars, bias in expr.items():
3512
+ >>> match vars:
3513
+ >>> case Constant(): do_something_with_constant(bias)
3514
+ >>> case Linear(x): do_something_with_linear_var(x, bias)
3515
+ >>> case Quadratic(x, y): do_something_with_quadratic_vars(x, y, bias)
3516
+ >>> case HigherOrder(ho): do_something_with_higher_order_vars(ho, bias)
3517
+ """
3518
+
3519
+ def __next__(self) -> tuple[Constant | Linear | Quadratic | HigherOrder, float]: ...
3520
+ def __iter__(self) -> ExpressionIterator: ...
3521
+
3522
+ class Environment:
3523
+ """
3524
+ Execution context for variable creation and expression scoping.
3525
+
3526
+ An `Environment` provides the symbolic scope in which `Variable`s are defined.
3527
+ It is required for constructing variables ensuring consistency across expressions.
3528
+ The environment does **not** store constraints or expressions — it only facilitates
3529
+ their creation by acting as a context manager and anchor for `Variable` instances.
3530
+
3531
+ Environments are best used with `with` blocks, but can also be passed manually
3532
+ to models or variables.
3533
+
3534
+ Examples
3535
+ --------
3536
+ Create variables inside an environment:
3537
+
3538
+ >>> from luna_quantum import Environment, Variable
3539
+ >>> with Environment() as env:
3540
+ ... x = Variable("x")
3541
+ ... y = Variable("y")
3542
+
3543
+ Serialize the environment state:
3544
+
3545
+ >>> data = env.encode()
3546
+ >>> expr = Environment.decode(data)
3547
+
3548
+ Notes
3549
+ -----
3550
+ - The environment is required to create `Variable` instances.
3551
+ - It does **not** own constraints or expressions — they merely reference variables
3552
+ tied to an environment.
3553
+ - Environments **cannot be nested**. Only one can be active at a time.
3554
+ - Use `encode()` / `decode()` to persist and recover expression trees.
3555
+ """
3556
+
3557
+ def __init__(self, /) -> None:
3558
+ """
3559
+ Initialize a new environment for variable construction.
3560
+
3561
+ It is recommended to use this in a `with` statement to ensure proper scoping.
3562
+ """
3563
+ ...
3564
+
3565
+ def __enter__(self, /) -> Self:
3566
+ """
3567
+ Activate this environment for variable creation.
3568
+
3569
+ Returns
3570
+ -------
3571
+ Environment
3572
+ The current environment (self).
3573
+
3574
+ Raises
3575
+ ------
3576
+ MultipleActiveEnvironmentsError
3577
+ If another environment is already active.
3578
+ """
3579
+ ...
3580
+
3581
+ def __exit__(
3582
+ self,
3583
+ /,
3584
+ exc_type: (type[BaseException] | None) = ...,
3585
+ exc_value: (BaseException | None) = ...,
3586
+ exc_traceback: (TracebackType | None) = ...,
3587
+ ) -> None:
3588
+ """
3589
+ Deactivate this environment.
3590
+
3591
+ Called automatically at the end of a `with` block.
3592
+ """
3593
+ ...
3594
+
3595
+ def get_variable(self, /, name: str) -> Variable:
3596
+ """
3597
+ Get a variable by its label (name).
3598
+
3599
+ Parameters
3600
+ ----------
3601
+ name : str
3602
+ The name/label of the variable
3603
+
3604
+ Returns
3605
+ -------
3606
+ Variable
3607
+ The variable with the specified label/name.
3608
+
3609
+ Raises
3610
+ ------
3611
+ VariableNotExistingError
3612
+ If no variable with the specified name is registered.
3613
+ """
3614
+ ...
3615
+
3616
+ @overload
3617
+ def encode(self, /) -> bytes: ...
3618
+ @overload
3619
+ def encode(self, /, *, compress: bool) -> bytes: ...
3620
+ @overload
3621
+ def encode(self, /, *, level: int) -> bytes: ...
3622
+ @overload
3623
+ def encode(self, /, compress: bool, level: int) -> bytes: ...
3624
+ def encode(
3625
+ self, /, compress: (bool | None) = True, level: (int | None) = 3
3626
+ ) -> bytes:
3627
+ """
3628
+ Serialize the environment into a compact binary format.
3629
+
3630
+ This is the preferred method for persisting an environment's state.
3631
+
3632
+ Parameters
3633
+ ----------
3634
+ compress : bool, optional
3635
+ Whether to compress the binary output. Default is `True`.
3636
+ level : int, optional
3637
+ Compression level (e.g., from 0 to 9). Default is `3`.
3638
+
3639
+ Returns
3640
+ -------
3641
+ bytes
3642
+ Encoded binary representation of the environment.
3643
+
3644
+ Raises
3645
+ ------
3646
+ IOError
3647
+ If serialization fails.
3648
+ """
3649
+ ...
3650
+
3651
+ @overload
3652
+ def serialize(self, /) -> bytes: ...
3653
+ @overload
3654
+ def serialize(self, /, *, compress: bool) -> bytes: ...
3655
+ @overload
3656
+ def serialize(self, /, *, level: int) -> bytes: ...
3657
+ @overload
3658
+ def serialize(self, /, compress: bool, level: int) -> bytes: ...
3659
+ def serialize(
3660
+ self, /, compress: (bool | None) = ..., level: (int | None) = ...
3661
+ ) -> bytes:
3662
+ """
3663
+ Alias for `encode()`.
3664
+
3665
+ See `encode()` for full usage details.
3666
+ """
3667
+ ...
3668
+
3669
+ @classmethod
3670
+ def decode(cls, data: bytes) -> Environment:
3671
+ """
3672
+ Reconstruct an expression from a previously encoded binary blob.
3673
+
3674
+ Parameters
3675
+ ----------
3676
+ data : bytes
3677
+ The binary data returned from `Environment.encode()`.
3678
+
3679
+ Returns
3680
+ -------
3681
+ Expression
3682
+ The reconstructed symbolic expression.
3683
+
3684
+ Raises
3685
+ ------
3686
+ DecodeError
3687
+ If decoding fails due to corruption or incompatibility.
3688
+ """
3689
+ ...
3690
+
3691
+ @classmethod
3692
+ def deserialize(cls, data: bytes) -> Environment:
3693
+ """
3694
+ Alias for `decode()`.
3695
+
3696
+ See `decode()` for full usage details.
3697
+ """
3698
+ ...
3699
+
3700
+ def equal_contents(self, other: Environment, /) -> bool:
3701
+ """
3702
+ Check whether this environment has equal contents as `other`.
3703
+
3704
+ Parameters
3705
+ ----------
3706
+ other : Environment
3707
+
3708
+ Returns
3709
+ -------
3710
+ bool
3711
+ """
3712
+ ...
3713
+
3714
+ def __eq__(self, other: Environment, /) -> bool: ...
3715
+ def __str__(self, /) -> str: ...
3716
+ def __repr__(self, /) -> str: ...
3717
+ @property
3718
+ def num_variables(self, /) -> int:
3719
+ """Get the number of variables in env."""
3720
+ ...
3721
+
3722
+ def variables(self, /) -> list[Variable]:
3723
+ """Get the variables in env."""
3724
+ ...
3725
+
3726
+ class Comparator(Enum):
3727
+ """
3728
+ Comparison operators used to define constraints.
3729
+
3730
+ This enum represents the logical relation between the left-hand side (LHS)
3731
+ and the right-hand side (RHS) of a constraint.
3732
+
3733
+ Attributes
3734
+ ----------
3735
+ Eq : Comparator
3736
+ Equality constraint (==).
3737
+ Le : Comparator
3738
+ Less-than-or-equal constraint (<=).
3739
+ Ge : Comparator
3740
+ Greater-than-or-equal constraint (>=).
3741
+
3742
+ Examples
3743
+ --------
3744
+ >>> from luna_quantum import Comparator
3745
+ >>> str(Comparator.Eq)
3746
+ '=='
3747
+ """
3748
+
3749
+ Eq = ...
3750
+ """Equality (==)"""
3751
+ Le = ...
3752
+ """Less-than or equal (<=)"""
3753
+ Ge = ...
3754
+ """Greater-than or equal (>=)"""
3755
+
3756
+ def __str__(self, /) -> str: ...
3757
+ def __repr__(self, /) -> str: ...
3758
+
3759
+ class Constraint:
3760
+ """
3761
+ A symbolic constraint formed by comparing an expression to a constant.
3762
+
3763
+ A `Constraint` captures a relation of the form:
3764
+ `expression comparator constant`, where the comparator is one of:
3765
+ `==`, `<=`, or `>=`.
3766
+
3767
+ While constraints are usually created by comparing an `Expression` to a scalar
3768
+ (e.g., `expr == 3.0`), they can also be constructed manually using this class.
3769
+
3770
+ Parameters
3771
+ ----------
3772
+ lhs : Expression
3773
+ The left-hand side expression.
3774
+ rhs : float
3775
+ The scalar right-hand side value.
3776
+ comparator : Comparator
3777
+ The relation between lhs and rhs (e.g., `Comparator.Eq`).
3778
+
3779
+ Examples
3780
+ --------
3781
+ >>> from luna_quantum import Environment, Variable, Constraint, Comparator
3782
+ >>> with Environment():
3783
+ ... x = Variable("x")
3784
+ ... c = Constraint(x + 2, 5.0, Comparator.Eq)
3785
+
3786
+ Or create via comparison:
3787
+
3788
+ >>> expr = 2 * x + 1
3789
+ >>> c2 = expr <= 10.0
3790
+ """
3791
+
3792
+ @overload
3793
+ def __init__(
3794
+ self, /, lhs: Expression, rhs: Expression, comparator: Comparator
3795
+ ) -> None: ...
3796
+ @overload
3797
+ def __init__(
3798
+ self, /, lhs: Expression, rhs: Variable, comparator: Comparator
3799
+ ) -> None: ...
3800
+ @overload
3801
+ def __init__(
3802
+ self, /, lhs: Expression, rhs: int, comparator: Comparator
3803
+ ) -> None: ...
3804
+ @overload
3805
+ def __init__(
3806
+ self, /, lhs: Expression, rhs: float, comparator: Comparator
3807
+ ) -> None: ...
3808
+ @overload
3809
+ def __init__(
3810
+ self, /, lhs: Expression, rhs: Expression, comparator: Comparator, name: str
3811
+ ) -> None: ...
3812
+ @overload
3813
+ def __init__(
3814
+ self, /, lhs: Expression, rhs: Variable, comparator: Comparator, name: str
3815
+ ) -> None: ...
3816
+ @overload
3817
+ def __init__(
3818
+ self, /, lhs: Expression, rhs: int, comparator: Comparator, name: str
3819
+ ) -> None: ...
3820
+ @overload
3821
+ def __init__(
3822
+ self, /, lhs: Expression, rhs: float, comparator: Comparator, name: str
3823
+ ) -> None: ...
3824
+ @overload
3825
+ def __init__(
3826
+ self, /, lhs: Variable, rhs: Expression, comparator: Comparator
3827
+ ) -> None: ...
3828
+ @overload
3829
+ def __init__(
3830
+ self, /, lhs: Variable, rhs: Variable, comparator: Comparator
3831
+ ) -> None: ...
3832
+ @overload
3833
+ def __init__(self, /, lhs: Variable, rhs: int, comparator: Comparator) -> None: ...
3834
+ @overload
3835
+ def __init__(
3836
+ self, /, lhs: Variable, rhs: float, comparator: Comparator
3837
+ ) -> None: ...
3838
+ @overload
3839
+ def __init__(
3840
+ self, /, lhs: Variable, rhs: Expression, comparator: Comparator, name: str
3841
+ ) -> None: ...
3842
+ @overload
3843
+ def __init__(
3844
+ self, /, lhs: Variable, rhs: Variable, comparator: Comparator, name: str
3845
+ ) -> None: ...
3846
+ @overload
3847
+ def __init__(
3848
+ self, /, lhs: Variable, rhs: int, comparator: Comparator, name: str
3849
+ ) -> None: ...
3850
+ @overload
3851
+ def __init__(
3852
+ self, /, lhs: Variable, rhs: float, comparator: Comparator, name: str
3853
+ ) -> None: ...
3854
+ def __init__(
3855
+ self,
3856
+ /,
3857
+ lhs: (Variable | Expression),
3858
+ rhs: (int | float | Expression | Variable),
3859
+ comparator: Comparator,
3860
+ name: str,
3861
+ ) -> None:
3862
+ """
3863
+ Construct a new symbolic constraint.
3864
+
3865
+ Parameters
3866
+ ----------
3867
+ lhs : Expression | Variable
3868
+ Left-hand side symbolic expression or variable.
3869
+ rhs : int | float | Expression | Variable
3870
+ Scalar right-hand side constant.
3871
+ comparator : Comparator
3872
+ Relational operator (e.g., Comparator.Eq, Comparator.Le).
3873
+ name : str
3874
+ The name of the constraint
3875
+
3876
+ Raises
3877
+ ------
3878
+ TypeError
3879
+ If lhs is not an Expression or rhs is not a scalar float.
3880
+ IllegalConstraintNameError
3881
+ If the constraint is tried to be created with an illegal name.
3882
+ """
3883
+ ...
3884
+
3885
+ @property
3886
+ def name(self, /) -> str | None:
3887
+ """
3888
+ Get the name of the constraint.
3889
+
3890
+ Returns
3891
+ -------
3892
+ str, optional
3893
+ Returns the name of the constraint as a string or None if it is unnamed.
3894
+ """
3895
+ ...
3896
+
3897
+ @property
3898
+ def lhs(self, /) -> Expression:
3899
+ """
3900
+ Get the left-hand side of the constraint.
3901
+
3902
+ Returns
3903
+ -------
3904
+ Expression
3905
+ The left-hand side expression.
3906
+ """
3907
+ ...
3908
+
3909
+ @property
3910
+ def rhs(self, /) -> float:
3911
+ """
3912
+ Get the right-hand side of the constraint.
3913
+
3914
+ Returns
3915
+ -------
3916
+ float
3917
+ The right-hand side expression.
3918
+ """
3919
+ ...
3920
+
3921
+ @property
3922
+ def comparator(self, /) -> Comparator:
3923
+ """
3924
+ Get the comparator of the constraint.
3925
+
3926
+ Returns
3927
+ -------
3928
+ Comparator
3929
+ The comparator of the constraint.
3930
+ """
3931
+ ...
3932
+
3933
+ def __eq__(self, other: Constraint, /) -> bool: ...
3934
+ def __str__(self, /) -> str: ...
3935
+ def __repr__(self, /) -> str: ...
3936
+
3937
+ class Constraints:
3938
+ """
3939
+ A collection of symbolic constraints used to define a model.
3940
+
3941
+ The `Constraints` object serves as a container for individual `Constraint`
3942
+ instances. It supports adding constraints programmatically and exporting
3943
+ them for serialization.
3944
+
3945
+ Constraints are typically added using `add_constraint()` or the `+=` operator.
3946
+
3947
+ Examples
3948
+ --------
3949
+ >>> from luna_quantum import Constraints, Constraint, Environment, Variable
3950
+ >>> with Environment():
3951
+ ... x = Variable("x")
3952
+ ... c = Constraint(x + 1, 0.0, Comparator.Le)
3953
+
3954
+ >>> cs = Constraints()
3955
+ >>> cs += x >= 1.0
3956
+
3957
+ Serialization:
3958
+
3959
+ >>> blob = cs.encode()
3960
+ >>> expr = Constraints.decode(blob)
3961
+
3962
+ Notes
3963
+ -----
3964
+ - This class does not check feasibility or enforce satisfaction.
3965
+ - Use `encode()`/`decode()` to serialize constraints alongside expressions.
3966
+ """
3967
+
3968
+ def __init__(self, /) -> None: ...
3969
+ @overload
3970
+ def add_constraint(self, /, constraint: Constraint) -> None: ...
3971
+ @overload
3972
+ def add_constraint(self, /, constraint: Constraint, name: str) -> None: ...
3973
+ def add_constraint(
3974
+ self, /, constraint: Constraint, name: (str | None) = ...
3975
+ ) -> None:
3976
+ """
3977
+ Add a constraint to the collection.
3978
+
3979
+ Parameters
3980
+ ----------
3981
+ constraint : Constraint
3982
+ The constraint to be added.
3983
+ name : str, optional
3984
+ The name of the constraint to be added.
3985
+ """
3986
+ ...
3987
+
3988
+ @overload
3989
+ def encode(self, /) -> bytes: ...
3990
+ @overload
3991
+ def encode(self, /, *, compress: bool) -> bytes: ...
3992
+ @overload
3993
+ def encode(self, /, *, level: int) -> bytes: ...
3994
+ @overload
3995
+ def encode(self, /, compress: bool, level: int) -> bytes: ...
3996
+ def encode(
3997
+ self, /, compress: (bool | None) = True, level: (int | None) = 3
3998
+ ) -> bytes:
3999
+ """
4000
+ Serialize the constraint collection to a binary blob.
4001
+
4002
+ Parameters
4003
+ ----------
4004
+ compress : bool, optional
4005
+ Whether to compress the result. Default is True.
4006
+ level : int, optional
4007
+ Compression level (0-9). Default is 3.
4008
+
4009
+ Returns
4010
+ -------
4011
+ bytes
4012
+ Encoded representation of the constraints.
4013
+
4014
+ Raises
4015
+ ------
4016
+ IOError
4017
+ If serialization fails.
4018
+ """
4019
+ ...
4020
+
4021
+ @overload
4022
+ def serialize(self, /) -> bytes: ...
4023
+ @overload
4024
+ def serialize(self, /, *, compress: bool) -> bytes: ...
4025
+ @overload
4026
+ def serialize(self, /, *, level: int) -> bytes: ...
4027
+ @overload
4028
+ def serialize(self, /, compress: bool, level: int) -> bytes: ...
4029
+ def serialize(
4030
+ self, /, compress: (bool | None) = ..., level: (int | None) = ...
4031
+ ) -> bytes:
4032
+ """
4033
+ Alias for `encode()`.
4034
+
4035
+ See `encode()` for details.
4036
+ """
4037
+ ...
4038
+
4039
+ @classmethod
4040
+ def decode(cls, data: bytes, env: Environment) -> Expression:
4041
+ """
4042
+ Deserialize an expression from binary constraint data.
4043
+
4044
+ Parameters
4045
+ ----------
4046
+ data : bytes
4047
+ Encoded blob from `encode()`.
4048
+
4049
+ Returns
4050
+ -------
4051
+ Expression
4052
+ Expression reconstructed from the constraint context.
4053
+
4054
+ Raises
4055
+ ------
4056
+ DecodeError
4057
+ If decoding fails due to corruption or incompatibility.
4058
+ """
4059
+ ...
4060
+
4061
+ @classmethod
4062
+ def deserialize(cls, data: bytes, env: Environment) -> Expression:
4063
+ """
4064
+ Alias for `decode()`.
4065
+
4066
+ See `decode()` for usage.
4067
+ """
4068
+ ...
4069
+
4070
+ @overload
4071
+ def __iadd__(self, constraint: Constraint, /) -> Self: ...
4072
+ @overload
4073
+ def __iadd__(self, constraint: tuple[Constraint, str], /) -> Self: ...
4074
+ def __iadd__(self, constraint: (Constraint | tuple[Constraint, str]), /) -> Self:
4075
+ """
4076
+ In-place constraint addition using `+=`.
4077
+
4078
+ Parameters
4079
+ ----------
4080
+ constraint : Constraint | tuple[Constraint, str]
4081
+ The constraint to add.
4082
+
4083
+ Returns
4084
+ -------
4085
+ Constraints
4086
+ The updated collection.
4087
+
4088
+ Raises
4089
+ ------
4090
+ TypeError
4091
+ If the value is not a `Constraint` or valid symbolic comparison.
4092
+ """
4093
+ ...
4094
+
4095
+ @overload
4096
+ def get(self, item: str, /) -> Constraint: ...
4097
+ @overload
4098
+ def get(self, item: int, /) -> Constraint: ...
4099
+ def get(self, item: (int | str), /) -> Constraint:
4100
+ """Get a constraint for its name or index."""
4101
+ ...
4102
+
4103
+ @overload
4104
+ def remove(self, item: str, /) -> Constraint: ...
4105
+ @overload
4106
+ def remove(self, item: int, /) -> Constraint: ...
4107
+ def remove(self, item: (int | str), /) -> Constraint:
4108
+ """Remove a constraint for its name or index."""
4109
+ ...
4110
+
4111
+ def __eq__(self, other: Constraints, /) -> bool: ...
4112
+ def __str__(self, /) -> str: ...
4113
+ def __repr__(self, /) -> str: ...
4114
+ @overload
4115
+ def __getitem__(self, item: str, /) -> Constraint: ...
4116
+ @overload
4117
+ def __getitem__(self, item: int, /) -> Constraint: ...
4118
+ def __getitem__(self, item: (int | str), /) -> Constraint: ...
4119
+ @overload
4120
+ def __setitem__(self, item: str, content: Constraint, /) -> None: ...
4121
+ @overload
4122
+ def __setitem__(self, item: int, content: Constraint, /) -> None: ...
4123
+ def __setitem__(self, item: (int | str), content: Constraint, /) -> None: ...
4124
+ def __len__(self, /) -> int:
4125
+ """
4126
+ Get the number of constraints.
4127
+
4128
+ Returns
4129
+ -------
4130
+ int
4131
+ The number of constraints associated with this `Constraints` object.
4132
+ """
4133
+ ...
4134
+
4135
+ def __iter__(self, /) -> Iterator[Constraint]: ...
4136
+ def equal_contents(self, other: Constraints, /) -> bool:
4137
+ """
4138
+ Check whether this constraints has equal contents as `other`.
4139
+
4140
+ Parameters
4141
+ ----------
4142
+ other : Constraints
4143
+
4144
+ Returns
4145
+ -------
4146
+ bool
4147
+ """
4148
+ ...
4149
+
4150
+ def ctypes(self, /) -> list[Comparator]:
4151
+ """Get all unique constraint types identified using their comparator."""
4152
+ ...
4153
+
4154
+ __version__: str
4155
+ __aq_model_version__: str
4156
+ __luna_quantum_version__: str
4157
+ __all__ = [
4158
+ "Bounds",
4159
+ "Comparator",
4160
+ "Constraint",
4161
+ "Constraints",
4162
+ "Environment",
4163
+ "Expression",
4164
+ "Model",
4165
+ "Result",
4166
+ "ResultIterator",
4167
+ "ResultView",
4168
+ "Sample",
4169
+ "SampleIterator",
4170
+ "Samples",
4171
+ "SamplesIterator",
4172
+ "Sense",
4173
+ "Solution",
4174
+ "Timer",
4175
+ "Timing",
4176
+ "Variable",
4177
+ "Vtype",
4178
+ "__aq_model_version__",
4179
+ "__luna_quantum_version__",
4180
+ "__version__",
4181
+ "errors",
4182
+ "transformations",
4183
+ "translator",
4184
+ "utils",
4185
+ ]