ommx-openjij-adapter 1.8.6__tar.gz → 1.9.0rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ommx_openjij_adapter
3
- Version: 1.8.6
3
+ Version: 1.9.0rc2
4
4
  Summary: OMMX Adapter for OpenJij.
5
5
  Author-email: "Jij Inc." <info@j-ij.com>
6
6
  Project-URL: Repository, https://github.com/Jij-Inc/ommx
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Requires-Python: <3.13,>=3.9
16
16
  Description-Content-Type: text/markdown
17
- Requires-Dist: ommx<2.0.0,>=1.8.6
17
+ Requires-Dist: ommx<2.0.0,>=1.9.0rc1
18
18
  Requires-Dist: openjij>=0.9.2
19
19
 
20
20
  OMMX Adapter for OpenJij
@@ -4,6 +4,8 @@ from ommx.v1 import Instance, State, Samples, SampleSet
4
4
  from ommx.adapter import SamplerAdapter
5
5
  import openjij as oj
6
6
  from typing_extensions import deprecated
7
+ from typing import Optional
8
+ import copy
7
9
 
8
10
 
9
11
  class OMMXOpenJijSAAdapter(SamplerAdapter):
@@ -46,6 +48,13 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
46
48
  seed: int | None = None
47
49
  """ seed for Monte Carlo algorithm """
48
50
 
51
+ uniform_penalty_weight: Optional[float] = None
52
+ """ Weight for uniform penalty, passed to ``Instance.to_qubo`` """
53
+ penalty_weights: dict[int, float] = {}
54
+ """ Penalty weights for each constraint, passed to ``Instance.to_qubo`` """
55
+ inequality_integer_slack_max_range: int = 32
56
+ """ Max range for integer slack variables in inequality constraints, passed to ``Instance.to_qubo`` """
57
+
49
58
  @classmethod
50
59
  def sample(
51
60
  cls,
@@ -61,6 +70,9 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
61
70
  sparse: bool | None = None,
62
71
  reinitialize_state: bool | None = None,
63
72
  seed: int | None = None,
73
+ uniform_penalty_weight: Optional[float] = None,
74
+ penalty_weights: dict[int, float] = {},
75
+ inequality_integer_slack_max_range: int = 32,
64
76
  ) -> SampleSet:
65
77
  sampler = cls(
66
78
  ommx_instance,
@@ -74,6 +86,9 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
74
86
  sparse=sparse,
75
87
  reinitialize_state=reinitialize_state,
76
88
  seed=seed,
89
+ uniform_penalty_weight=uniform_penalty_weight,
90
+ penalty_weights=penalty_weights,
91
+ inequality_integer_slack_max_range=inequality_integer_slack_max_range,
77
92
  )
78
93
  response = sampler._sample()
79
94
  return sampler.decode_to_sampleset(response)
@@ -92,8 +107,11 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
92
107
  sparse: bool | None = None,
93
108
  reinitialize_state: bool | None = None,
94
109
  seed: int | None = None,
110
+ uniform_penalty_weight: Optional[float] = None,
111
+ penalty_weights: dict[int, float] = {},
112
+ inequality_integer_slack_max_range: int = 32,
95
113
  ):
96
- self.ommx_instance = ommx_instance
114
+ self.ommx_instance = copy.deepcopy(ommx_instance)
97
115
  self.beta_min = beta_min
98
116
  self.beta_max = beta_max
99
117
  self.num_sweeps = num_sweeps
@@ -104,6 +122,9 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
104
122
  self.sparse = sparse
105
123
  self.reinitialize_state = reinitialize_state
106
124
  self.seed = seed
125
+ self.uniform_penalty_weight = uniform_penalty_weight
126
+ self.penalty_weights = penalty_weights
127
+ self.inequality_integer_slack_max_range = inequality_integer_slack_max_range
107
128
 
108
129
  def decode_to_sampleset(self, data: oj.Response) -> SampleSet:
109
130
  samples = decode_to_samples(data)
@@ -119,12 +140,16 @@ class OMMXOpenJijSAAdapter(SamplerAdapter):
119
140
 
120
141
  @property
121
142
  def sampler_input(self) -> dict[tuple[int, int], float]:
122
- qubo, _offset = self.ommx_instance.as_qubo_format()
143
+ qubo, _offset = self.ommx_instance.to_qubo(
144
+ uniform_penalty_weight=self.uniform_penalty_weight,
145
+ penalty_weights=self.penalty_weights,
146
+ inequality_integer_slack_max_range=self.inequality_integer_slack_max_range,
147
+ )
123
148
  return qubo
124
149
 
125
150
  def _sample(self) -> oj.Response:
126
151
  sampler = oj.SASampler()
127
- qubo, _offset = self.ommx_instance.as_qubo_format()
152
+ qubo = self.sampler_input
128
153
  return sampler.sample_qubo(
129
154
  qubo, # type: ignore
130
155
  beta_min=self.beta_min,
@@ -189,10 +214,8 @@ def sample_qubo_sa(
189
214
  """
190
215
  Deprecated: Use :meth:`OMMXOpenJijSAAdapter.sample` instead
191
216
  """
192
- q, _offset = instance.as_qubo_format()
193
- sampler = oj.SASampler()
194
- response = sampler.sample_qubo(
195
- q, # type: ignore
217
+ sampler = OMMXOpenJijSAAdapter(
218
+ instance,
196
219
  beta_min=beta_min,
197
220
  beta_max=beta_max,
198
221
  num_sweeps=num_sweeps,
@@ -204,4 +227,5 @@ def sample_qubo_sa(
204
227
  reinitialize_state=reinitialize_state,
205
228
  seed=seed,
206
229
  )
230
+ response = sampler._sample()
207
231
  return decode_to_samples(response)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: ommx_openjij_adapter
3
- Version: 1.8.6
3
+ Version: 1.9.0rc2
4
4
  Summary: OMMX Adapter for OpenJij.
5
5
  Author-email: "Jij Inc." <info@j-ij.com>
6
6
  Project-URL: Repository, https://github.com/Jij-Inc/ommx
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: License :: OSI Approved :: MIT License
15
15
  Requires-Python: <3.13,>=3.9
16
16
  Description-Content-Type: text/markdown
17
- Requires-Dist: ommx<2.0.0,>=1.8.6
17
+ Requires-Dist: ommx<2.0.0,>=1.9.0rc1
18
18
  Requires-Dist: openjij>=0.9.2
19
19
 
20
20
  OMMX Adapter for OpenJij
@@ -0,0 +1,2 @@
1
+ ommx<2.0.0,>=1.9.0rc1
2
+ openjij>=0.9.2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ommx_openjij_adapter"
7
- version = "1.8.6"
7
+ version = "1.9.0rc2"
8
8
 
9
9
  description = "OMMX Adapter for OpenJij."
10
10
  authors = [{ name = "Jij Inc.", email = "info@j-ij.com" }]
@@ -22,7 +22,7 @@ classifiers = [
22
22
  "License :: OSI Approved :: Apache Software License",
23
23
  "License :: OSI Approved :: MIT License",
24
24
  ]
25
- dependencies = ["ommx>=1.8.6,<2.0.0", "openjij>=0.9.2"]
25
+ dependencies = ["ommx>=1.9.0rc1,<2.0.0","openjij>=0.9.2"]
26
26
 
27
27
  [project.urls]
28
28
  Repository = "https://github.com/Jij-Inc/ommx"
@@ -0,0 +1,147 @@
1
+ from ommx.v1 import Instance, DecisionVariable
2
+ from ommx_openjij_adapter import OMMXOpenJijSAAdapter
3
+ import pytest
4
+
5
+
6
+ def binary_no_constraint_minimize():
7
+ x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
8
+ x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
9
+ instance = Instance.from_components(
10
+ decision_variables=[x0, x1],
11
+ objective=x0 + x1,
12
+ constraints=[],
13
+ sense=Instance.MINIMIZE,
14
+ )
15
+ ans = {(0,): 0.0, (1,): 0.0}
16
+ return pytest.param(instance, ans, id="binary_no_constraint_minimize")
17
+
18
+
19
+ def binary_no_constraint_maximize():
20
+ x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
21
+ x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
22
+ instance = Instance.from_components(
23
+ decision_variables=[x0, x1],
24
+ objective=x0 + x1,
25
+ constraints=[],
26
+ sense=Instance.MAXIMIZE,
27
+ )
28
+ ans = {(0,): 1.0, (1,): 1.0}
29
+ return pytest.param(instance, ans, id="binary_no_constraint_maximize")
30
+
31
+
32
+ def binary_equality():
33
+ x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
34
+ x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
35
+ x2 = DecisionVariable.binary(2, name="x", subscripts=[2])
36
+
37
+ instance = Instance.from_components(
38
+ decision_variables=[x0, x1, x2],
39
+ objective=x0 + 2 * x1 + 3 * x2,
40
+ constraints=[x1 * x2 == 0],
41
+ sense=Instance.MAXIMIZE,
42
+ )
43
+
44
+ # x0 = x2 = 1, x1 = 0 is maximum
45
+ ans = {(0,): 1.0, (1,): 0.0, (2,): 1.0}
46
+ return pytest.param(instance, ans, id="binary_equality")
47
+
48
+
49
+ def binary_inequality():
50
+ x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
51
+ x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
52
+ x2 = DecisionVariable.binary(2, name="x", subscripts=[2])
53
+
54
+ instance = Instance.from_components(
55
+ decision_variables=[x0, x1, x2],
56
+ objective=x0 + 2 * x1 + 3 * x2,
57
+ constraints=[x0 + x1 + x2 <= 2],
58
+ sense=Instance.MAXIMIZE,
59
+ )
60
+
61
+ # x1 = x2 = 1, x0 = 0 is maximum
62
+ ans = {(0,): 0.0, (1,): 1.0, (2,): 1.0}
63
+ return pytest.param(instance, ans, id="binary_inequality")
64
+
65
+
66
+ def integer_equality():
67
+ x0 = DecisionVariable.integer(0, name="x", lower=-1, upper=1, subscripts=[0])
68
+ x1 = DecisionVariable.integer(1, name="x", lower=-1, upper=1, subscripts=[1])
69
+
70
+ instance = Instance.from_components(
71
+ decision_variables=[x0, x1],
72
+ objective=x0 + 2 * x1,
73
+ constraints=[x0 + x1 == 0],
74
+ sense=Instance.MAXIMIZE,
75
+ )
76
+
77
+ # x1 = -x0 = 1 is maximum
78
+ ans = {(0,): -1.0, (1,): 1.0}
79
+ return pytest.param(instance, ans, id="integer_equality")
80
+
81
+
82
+ def integer_inequality():
83
+ x0 = DecisionVariable.integer(0, name="x", lower=-1, upper=1, subscripts=[0])
84
+ x1 = DecisionVariable.integer(1, name="x", lower=-1, upper=1, subscripts=[1])
85
+
86
+ instance = Instance.from_components(
87
+ decision_variables=[x0, x1],
88
+ objective=x0 + 2 * x1,
89
+ constraints=[x0 + x1 <= 0],
90
+ sense=Instance.MAXIMIZE,
91
+ )
92
+
93
+ # x1 = -x0 = 1 is maximum
94
+ ans = {(0,): -1.0, (1,): 1.0}
95
+ return pytest.param(instance, ans, id="integer_inequality")
96
+
97
+
98
+ @pytest.mark.parametrize(
99
+ "instance, ans",
100
+ [
101
+ binary_no_constraint_minimize(),
102
+ binary_no_constraint_maximize(),
103
+ binary_equality(),
104
+ binary_inequality(),
105
+ integer_equality(),
106
+ integer_inequality(),
107
+ ],
108
+ )
109
+ def test_sample(instance, ans):
110
+ sample_set = OMMXOpenJijSAAdapter.sample(
111
+ instance, num_reads=1, uniform_penalty_weight=3.0, seed=12345
112
+ )
113
+ assert sample_set.extract_decision_variables("x", 0) == ans
114
+
115
+
116
+ @pytest.mark.parametrize(
117
+ "instance, ans",
118
+ [
119
+ binary_no_constraint_minimize(),
120
+ binary_no_constraint_maximize(),
121
+ binary_equality(),
122
+ binary_inequality(),
123
+ integer_equality(),
124
+ integer_inequality(),
125
+ ],
126
+ )
127
+ def test_solve(instance, ans):
128
+ solution = OMMXOpenJijSAAdapter.solve(
129
+ instance, num_reads=1, uniform_penalty_weight=3.0, seed=12345
130
+ )
131
+ assert solution.extract_decision_variables("x") == ans
132
+
133
+
134
+ @pytest.mark.parametrize(
135
+ "instance, ans",
136
+ [
137
+ binary_no_constraint_minimize(),
138
+ binary_no_constraint_maximize(),
139
+ binary_equality(),
140
+ binary_inequality(),
141
+ integer_equality(),
142
+ integer_inequality(),
143
+ ],
144
+ )
145
+ def test_sample_twice(instance, ans):
146
+ test_sample(instance, ans)
147
+ test_sample(instance, ans)
@@ -1,2 +0,0 @@
1
- ommx<2.0.0,>=1.8.6
2
- openjij>=0.9.2
@@ -1,35 +0,0 @@
1
- from ommx.v1 import Instance, DecisionVariable
2
- from ommx_openjij_adapter import OMMXOpenJijSAAdapter
3
-
4
-
5
- def test_minimize():
6
- x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
7
- x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
8
-
9
- instance = Instance.from_components(
10
- decision_variables=[x0, x1],
11
- objective=x0 + x1,
12
- constraints=[],
13
- sense=Instance.MINIMIZE,
14
- )
15
- sample_set = OMMXOpenJijSAAdapter.sample(instance, num_reads=1)
16
-
17
- # x0 = x1 = 0 is minimum
18
- assert sample_set.extract_decision_variables("x", 0) == {(0,): 0.0, (1,): 0.0}
19
-
20
-
21
- def test_maximize():
22
- x0 = DecisionVariable.binary(0, name="x", subscripts=[0])
23
- x1 = DecisionVariable.binary(1, name="x", subscripts=[1])
24
-
25
- instance = Instance.from_components(
26
- decision_variables=[x0, x1],
27
- objective=x0 + x1,
28
- constraints=[],
29
- sense=Instance.MAXIMIZE,
30
- )
31
- instance.as_minimization_problem()
32
- sample_set = OMMXOpenJijSAAdapter.sample(instance, num_reads=1)
33
-
34
- # x0 = x1 = 1 is maximum
35
- assert sample_set.extract_decision_variables("x", 0) == {(0,): 1.0, (1,): 1.0}