Skip to content

to_dimod

DimodBuilder dataclass

Dimod model builder.

Attributes:

Name Type Description
compiled_model CompiledInstance

Compiled model.

_model ConstrainedQuadraticModel

Dimod model.

_objective QuadraticModel

Objective of dimod model.

custome_penalties dict[str, BinaryQuadraticModel]

Custom penalties.

Source code in jijmodeling_transpiler/core/dimod/to_dimod.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
@dataclass
class DimodBuilder:
    """Dimod model builder.

    Attributes:
        compiled_model (CompiledInstance): Compiled model.
        _model (dimod.ConstrainedQuadraticModel): Dimod model.
        _objective (dimod.QuadraticModel): Objective of dimod model.
        custome_penalties (dict[str, dimod.BinaryQuadraticModel]): Custom penalties.
    """

    compiled_model: CompiledInstance
    _model: dimod.ConstrainedQuadraticModel
    _objective: dimod.QuadraticModel
    custome_penalties: dict[str, dimod.BinaryQuadraticModel]

    def get_model(
        self, penalty_weight: typ.Optional[dict[str, float]] = None
    ) -> dimod.BinaryQuadraticModel:
        """Get dimod model.

        Args:
            penalty_weight (dict[str, float], optional): Penalty weight. Defaults to None.

        Returns:
            dimod.BinaryQuadraticModel: Dimod model.
        """
        if penalty_weight is None:
            penalty_weight = {}
        if len(self.custome_penalties) == 0:
            self._model.set_objective(self._objective)
            return self._model

        objective = self._objective.copy()
        for label, weight in penalty_weight.items():
            if label not in self.custome_penalties:
                objective = self.custome_penalties[label]
            else:
                objective += weight * self.custome_penalties[label]
        self._model.set_objective(objective)
        return self._model

    def decode_from_cqm_result(self, sampleset: dimod.SampleSet) -> jm.SampleSet:
        """Decode sampleset from dimod model.

        Args:
            sampleset (dimod.SampleSet): Dimod sampleset.

        Returns:
            jm.SampleSet: Decoded sampleset.
        """

        # Parse dimod variables
        # Assumption: sampleset.variables -> [(label, tuple[int, ...]), ...]
        # See detail in transpile_to_dimod
        subscripts: dict[str, list[list[int]]] = {}
        for var_label, var_subscripts in sampleset.variables:  # type: ignore
            if var_label not in subscripts:
                subscripts[var_label] = []
            subscripts[var_label].append(list(var_subscripts))

        solution_set = {
            label: [] for label in self.compiled_model.deci_var_shape.keys()
        }
        for sample in sampleset.samples():
            sparse_solutions: dict = {
                label: (tuple([[] for _ in range(len(shape))]), [], shape)
                for label, shape in self.compiled_model.deci_var_shape.items()
            }
            for key, value in sample.items():
                key_label = key[0]
                key_subs = key[1]
                if value == 0.0:
                    continue
                if key_label in sparse_solutions:
                    # set coordinate
                    for index, coo in enumerate(key_subs):
                        sparse_solutions[key_label][0][index].append(coo)
                    # set value
                    sparse_solutions[key_label][1].append(value)

            for label, sparse_solution in sparse_solutions.items():
                solution_set[label].append(sparse_solution)

        jm_record = jm.Record(
            solution=solution_set,  # type: ignore
            num_occurrences=sampleset.record["num_occurrences"].tolist(),
        )

        # Check feasibility and evaluate violation
        const_violation = {label: [] for label in self.compiled_model.constraint.keys()}
        for index, is_feasible in enumerate(sampleset.record["is_feasible"]):
            if is_feasible:
                for label in self.compiled_model.constraint.keys():
                    const_violation[label].append(0.0)
            else:
                formatted_solution = {}
                sparse_solution: dict = jm_record.solution  # type: ignore
                for label, _solutions in sparse_solution.items():
                    subs, _values, _shape = _solutions[index]
                    _subs_array = np.array(list(subs)).T
                    for _ind, value in enumerate(_values):
                        _s = tuple(_subs_array[_ind].tolist())
                        var_index = self.compiled_model.var_map.var_map[label][_s]
                        formatted_solution[var_index] = value
                violations = eval_constraint(formatted_solution, self.compiled_model)
                for label, violation in violations.items():
                    const_obj = self.compiled_model.problem.constraints[label]
                    cond = const_obj.condition
                    if cond.kind == subs_expr.ConstraintKind.EQUAL:
                        violation_sum = np.sum(np.abs(list(violation.values())))
                    else:
                        abs_value = np.array(list(violation.values()))
                        violation_sum = np.sum(abs_value[abs_value > 0])
                    const_violation[label].append(violation_sum)

        # In CQM solver, energy == objective
        energy = sampleset.record["energy"]
        if self.compiled_model.problem.sense == ProblemSense.MINIMIZE:
            objective = sampleset.record["energy"]
        else:
            objective = -1 * sampleset.record["energy"]
        evaluation = jm.Evaluation(
            energy=energy.tolist(),  # type: ignore
            objective=objective.tolist(),
            constraint_violations=const_violation,
        )

        return jm.SampleSet(
            record=jm_record,  # type: ignore
            evaluation=evaluation,
            measuring_time=jm.MeasuringTime(),
        )

decode_from_cqm_result(sampleset)

Decode sampleset from dimod model.

Parameters:

Name Type Description Default
sampleset SampleSet

Dimod sampleset.

required

Returns:

Type Description
SampleSet

jm.SampleSet: Decoded sampleset.

Source code in jijmodeling_transpiler/core/dimod/to_dimod.py
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def decode_from_cqm_result(self, sampleset: dimod.SampleSet) -> jm.SampleSet:
    """Decode sampleset from dimod model.

    Args:
        sampleset (dimod.SampleSet): Dimod sampleset.

    Returns:
        jm.SampleSet: Decoded sampleset.
    """

    # Parse dimod variables
    # Assumption: sampleset.variables -> [(label, tuple[int, ...]), ...]
    # See detail in transpile_to_dimod
    subscripts: dict[str, list[list[int]]] = {}
    for var_label, var_subscripts in sampleset.variables:  # type: ignore
        if var_label not in subscripts:
            subscripts[var_label] = []
        subscripts[var_label].append(list(var_subscripts))

    solution_set = {
        label: [] for label in self.compiled_model.deci_var_shape.keys()
    }
    for sample in sampleset.samples():
        sparse_solutions: dict = {
            label: (tuple([[] for _ in range(len(shape))]), [], shape)
            for label, shape in self.compiled_model.deci_var_shape.items()
        }
        for key, value in sample.items():
            key_label = key[0]
            key_subs = key[1]
            if value == 0.0:
                continue
            if key_label in sparse_solutions:
                # set coordinate
                for index, coo in enumerate(key_subs):
                    sparse_solutions[key_label][0][index].append(coo)
                # set value
                sparse_solutions[key_label][1].append(value)

        for label, sparse_solution in sparse_solutions.items():
            solution_set[label].append(sparse_solution)

    jm_record = jm.Record(
        solution=solution_set,  # type: ignore
        num_occurrences=sampleset.record["num_occurrences"].tolist(),
    )

    # Check feasibility and evaluate violation
    const_violation = {label: [] for label in self.compiled_model.constraint.keys()}
    for index, is_feasible in enumerate(sampleset.record["is_feasible"]):
        if is_feasible:
            for label in self.compiled_model.constraint.keys():
                const_violation[label].append(0.0)
        else:
            formatted_solution = {}
            sparse_solution: dict = jm_record.solution  # type: ignore
            for label, _solutions in sparse_solution.items():
                subs, _values, _shape = _solutions[index]
                _subs_array = np.array(list(subs)).T
                for _ind, value in enumerate(_values):
                    _s = tuple(_subs_array[_ind].tolist())
                    var_index = self.compiled_model.var_map.var_map[label][_s]
                    formatted_solution[var_index] = value
            violations = eval_constraint(formatted_solution, self.compiled_model)
            for label, violation in violations.items():
                const_obj = self.compiled_model.problem.constraints[label]
                cond = const_obj.condition
                if cond.kind == subs_expr.ConstraintKind.EQUAL:
                    violation_sum = np.sum(np.abs(list(violation.values())))
                else:
                    abs_value = np.array(list(violation.values()))
                    violation_sum = np.sum(abs_value[abs_value > 0])
                const_violation[label].append(violation_sum)

    # In CQM solver, energy == objective
    energy = sampleset.record["energy"]
    if self.compiled_model.problem.sense == ProblemSense.MINIMIZE:
        objective = sampleset.record["energy"]
    else:
        objective = -1 * sampleset.record["energy"]
    evaluation = jm.Evaluation(
        energy=energy.tolist(),  # type: ignore
        objective=objective.tolist(),
        constraint_violations=const_violation,
    )

    return jm.SampleSet(
        record=jm_record,  # type: ignore
        evaluation=evaluation,
        measuring_time=jm.MeasuringTime(),
    )

get_model(penalty_weight=None)

Get dimod model.

Parameters:

Name Type Description Default
penalty_weight dict[str, float]

Penalty weight. Defaults to None.

None

Returns:

Type Description
BinaryQuadraticModel

dimod.BinaryQuadraticModel: Dimod model.

Source code in jijmodeling_transpiler/core/dimod/to_dimod.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def get_model(
    self, penalty_weight: typ.Optional[dict[str, float]] = None
) -> dimod.BinaryQuadraticModel:
    """Get dimod model.

    Args:
        penalty_weight (dict[str, float], optional): Penalty weight. Defaults to None.

    Returns:
        dimod.BinaryQuadraticModel: Dimod model.
    """
    if penalty_weight is None:
        penalty_weight = {}
    if len(self.custome_penalties) == 0:
        self._model.set_objective(self._objective)
        return self._model

    objective = self._objective.copy()
    for label, weight in penalty_weight.items():
        if label not in self.custome_penalties:
            objective = self.custome_penalties[label]
        else:
            objective += weight * self.custome_penalties[label]
    self._model.set_objective(objective)
    return self._model

transpile_to_dimod_cqm(compiled_model)

Transpile compiled model to dimod CQM.

Parameters:

Name Type Description Default
compiled_model CompiledInstance

Compiled model.

required

Returns:

Name Type Description
DimodBuilder DimodBuilder

Dimod CQM builder.

Source code in jijmodeling_transpiler/core/dimod/to_dimod.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def transpile_to_dimod_cqm(
    compiled_model: CompiledInstance,
) -> DimodBuilder:
    """Transpile compiled model to dimod CQM.

    Args:
        compiled_model (CompiledInstance): Compiled model.

    Returns:
        DimodBuilder: Dimod CQM builder.
    """
    var_map = compiled_model.var_map.var_map
    variable_object = {}
    for label, _varmap in var_map.items():
        if label in compiled_model.var_map.integer_bound:
            for subscripts, index in _varmap.items():
                lower = compiled_model.var_map.integer_bound[label][subscripts].lower
                upper = compiled_model.var_map.integer_bound[label][subscripts].upper
                var_label = (label, subscripts)
                variable = dimod.Integer(
                    var_label, lower_bound=lower, upper_bound=upper
                )
                variable_object[index] = variable
        else:
            for subscripts, index in _varmap.items():
                var_label = (label, subscripts)
                variable = dimod.Binary(var_label)
                variable_object[index] = variable

    cqm = dimod.ConstrainedQuadraticModel()

    for label, constraint in compiled_model.constraint.items():
        for subs, cons in constraint.items():
            const_expr = _expr_conversion(cons, variable_object)
            if (
                compiled_model.problem.constraints[label].condition
                == subs_expr.ConstraintKind.EQUAL
            ):
                cqm.add_constraint(const_expr == 0, label=label + "_" + str(subs))
            elif (
                compiled_model.problem.constraints[label].condition
                == subs_expr.ConstraintKind.LESSTHANEQUAL
            ):
                cqm.add_constraint(const_expr <= 0, label=label + "_" + str(subs))
            elif (
                compiled_model.problem.constraints[label].condition
                == subs_expr.ConstraintKind.GREATERTHANEQUAL
            ):
                cqm.add_constraint(const_expr >= 0, label=label + "_" + str(subs))
            else:
                raise ValueError("unknown condition")

    custome_penalty = {}
    for label, penalty in compiled_model.penalty.items():
        penalty_bqm = dimod.QuadraticModel(offset=0.0)
        for subs, penalty_expr in penalty.items():
            penalty_expr = _expr_conversion(penalty_expr, variable_object)
            penalty_bqm += penalty_expr
        custome_penalty[label] = penalty_bqm

    objective = _expr_conversion(compiled_model.objective, variable_object)
    if compiled_model.problem.sense == ProblemSense.MINIMIZE:
        pass
    else:
        objective *= -1

    return DimodBuilder(compiled_model, cqm, objective, custome_penalty)