kaiwu.core package#

Module contents#

Module: core

Function: Definition of Baseses

class kaiwu.core.IsingSolver[source]#

Bases: object

Bases for Ising solvers

set_matrix(ising_matrix)[source]#

Set matrix and update related content

on_matrix_change()[source]#

Update matrix-related information; can be implemented when inheriting from IsingSolver. When the Ising matrix being processed changes, the implementation of this function will be called to allow corresponding actions.

solve(ising_matrix=None, negtail_flip=True, sort_solutions=False)[source]#

Solve the Ising matrix

Args:

ising_matrix (np.ndarray): Isingmatrix

negtail_flip (bool): Whether to perform negative-tail flipping

sort_solutions (bool): Whether to sort solutions

Returns:

output (np.ndarray): solution vector

get_hamiltonian()[source]#
Returns:

hamiltonian (np.ndarray): Hamiltonian value of the current solution

class kaiwu.core.QuboSolver[source]#

Bases: object

Bases for Solvers

Args:

optimizer (IsingSolver): Ising solver

solve_qubo(*args, **kwargs)[source]#
kaiwu.core.get_sorted_solutions(matrix, solutions, bias=0.0, negtail_ff=True, sort_solutions=True)[source]#

Optimal solution sampling.

Args:

matrix (np.ndarray): Ising matrix.

solutions (np.ndarray): variable configurations.

bias (float): constant term.

negtail_ff (bool): negtail_flip flag for negative-tail flipping; matrices produced by quadratizing linear terms in an Ising model require negative-tail flipping.

Returns:

output (np.ndarray, np.ndarray): variable configurations sorted by energy, and energy values.

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> matrix = -np.array([[ 0. ,  1. ,  0. ,  1. ,  1. ],
...                     [ 1. ,  0. ,  0. ,  1.,   1. ],
...                     [ 0. ,  0. ,  0. ,  1.,   1. ],
...                     [ 1. ,  1.,   1. ,  0. ,  1. ],
...                     [ 1. ,  1.,   1. ,  1. ,  0. ]])
>>> solutions = np.array([[ 1, -1,  1, -1, -1],
...                   [-1, -1,  1, -1, -1],
...                   [-1, -1, -1,  1,  1],
...                   [ 1,  1,  1, -1, -1],
...                   [ 1,  1,  1, -1, -1],
...                   [ 1,  1,  1, -1, -1]])
>>> kw.core.get_sorted_solutions(matrix, solutions, 0)
(array([[-1, -1, -1,  1,  1],
       [-1, -1, -1,  1,  1],
       [-1, -1, -1,  1,  1],
       [-1, -1, -1,  1,  1],
       [-1,  1, -1,  1,  1],
       [ 1,  1, -1,  1,  1]]), array([-8., -8., -8., -8., -4.,  8.]))
exception kaiwu.core.KaiwuError[source]#

Bases: Exception

Bases for exceptions in this module.

args#
with_traceback()#

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

kaiwu.core.get_min_penalty(obj, cons)[source]#

Return the minimum penalty coefficient corresponding to the constraint term ‘cons’, with the penalty term taking priority.

Args:

obj: QUBO expression of the original objective function.

cons: QUBO expression of the constraint term

Returns:

float: Minimum penalty coefficient corresponding to the constraint term ‘cons’.

Examples:
>>> import kaiwu as kw
>>> x = [kw.core.Binary(f"b{i}") for i in range(3)]
>>> cons = kw.core.quicksum(x) - 1
>>> obj = x[1] + 2 * x[2]
>>> kw.core.get_min_penalty(obj, cons)
2.0
kaiwu.core.get_min_penalty_from_min_diff(cons, negative_delta, positive_delta)[source]#

Estimate the minimum penalty coefficient of the constraint term based on the maximum and minimum values of the objective.

Args:

cons: Constraint term

negative_delta: Minimum value of the objective

positive_delta: Maximum value of the objective

Returns:

Found minimum penalty coefficient

kaiwu.core.get_min_penalty_for_equal_constraint(obj, cons)[source]#

Return the minimum penalty coefficient corresponding to the linear equality constraint term ‘cons’: the worst-case scenario when flipping one bit of the solution that satisfies this constraint. This penalty coefficient is valid in the sense that it ensures the feasible solution of the original problem is a local optimum of the objective function (in the local sense of one-bit flip).

Args:

obj: QUBO expression of the original objective function.

cons: Linear expression in the linear equality constraint cons=0.

Returns:

float: Minimum penalty coefficient corresponding to the linear equality constraint term ‘cons’.

Examples:
>>> import kaiwu as kw
>>> x = [kw.core.Binary(f"b{i}") for i in range(3)]
>>> cons = kw.core.quicksum(x)-1
>>> obj = x[1]+2*x[2]
>>> kw.core.get_min_penalty_for_equal_constraint(obj,cons)
2.0
kaiwu.core.get_min_penalty_from_deltas(cons, neg_delta, pos_delta, obj_vars, min_delta_method='diff')[source]#

Return the minimum penalty coefficient corresponding to the constraint term ‘cons’, with the penalty term taking priority.

Args:

cons: QUBO expression of the constraint term

neg_delta: Dictionary of maximum changes when each variable is flipped from 1 to 0

pos_delta: Dictionary of maximum changes when each variable is flipped from 0 to 1

obj_vars: The third element is a list of variables

min_delta_method: Declared in. Two methods are used to find the minimum change value respectively

MIN_DELTA_METHODS = {“diff”: _get_constraint_min_deltas_diff, “exhaust”: _get_constraint_min_deltas_exhaust}

Examples:
>>> import kaiwu as kw
>>> x = [kw.core.Binary(f"b{i}") for i in range(3)]
>>> cons = kw.core.quicksum(x) - 1
>>> obj = x[1]+2*x[2]
>>> kw.core.get_min_penalty(obj, cons)
2.0
class kaiwu.core.PenaltyMethodConstraint(expr, penalty=1, parent_model=None)[source]#

Bases: object

Penalty method for converting constrained problems to unconstrained problems

Args:

expr (Expression): Compiled constraint term expression

penalty (float): Penalty coefficient of the constraint term

classmethod from_constraint_definition(name, constraint: Constraint, parent_model)[source]#

Prepare QUBO expression for the given constraint, automatically determining slack variables if needed.

Args:

name: Name of the constraint.

constraint: The relation constraint to process.

parent_model: the model it belongs to.

set_penalty(penalty)[source]#

Set penalty coefficient

penalize_more()[source]#

Increase penalty coefficient

penalize_less()[source]#

Decrease penalty coefficient

is_satisfied(solution_dict)[source]#

Verify constraint satisfaction

kaiwu.core.get_sol_dict(solution, vars_dict)[source]#

Generate result dictionary based on solution vector and variable dictionary.

Args:

solution (np.ndarray): Solution vector (spin).

vars_dict (dict): Variable dictionary, generated by cim_ising_model.get_variables().

Returns:

dict: Result dictionary. Keys are variable names, values are corresponding spin values.

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> d = kw.core.QuboModel(d)
>>> d_ising = kw.core.qubo_model_to_ising_model(d)
>>> vars = d_ising.get_variables()
>>> s = np.array([1, -1, 1])
>>> kw.core.get_sol_dict(s, vars)
{'a': np.float64(1.0), 'b': np.float64(0.0), 'c': np.float64(1.0)}
kaiwu.core.get_val(qubo, sol_dict)[source]#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (BinaryExpression or BinaryExpressionNDArray): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> qubo_model = kw.core.QuboModel(d)
>>> d_ising = kw.core.qubo_model_to_ising_model(qubo_model)
>>> ising_vars = d_ising.get_variables()
>>> s = np.array([1, -1, 1])
>>> sol_dict = kw.core.get_sol_dict(s, ising_vars)
>>> kw.core.get_val(d, sol_dict)
np.float64(5.0)
class kaiwu.core.Expression(coefficient: dict | None = None, offset: float = 0)[source]#

Bases: object

Universal Bases for QUBO/Ising expressions (provides default quadratic expression implementation)

clear() None[source]#

Set the expression to 0

get_variables()[source]#

Get the set of variable names

Returns:

dict: returnexpressionvariable

get_max_deltas()[source]#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_average_coefficient()[source]#

Return the average value of coefficients

get_val(sol_dict)[source]#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
class kaiwu.core.BinaryModel(objective=None)[source]#

Bases: object

Binary model class

Args:

objective (BinaryExpression, optional): Objective function. Defaults to None

set_constraint_handler(constraint_handler)[source]#

Set the unconstrained conversion method for constraint terms

Args:

constraint_handler: Class for setting the unconstrained representation method of constraint terms

set_objective(objective)[source]#

Set the objective function

Args:

objective (BinaryExpression): Objective function expression

add_constraint(constraint_in, name=None, constr_type: Literal['soft', 'hard'] = 'hard', penalty=1, slack_var_expr=None)[source]#

Add constraint terms; single or multiple constraints are supported

Args:

constraint_in: constraint expression; two input types are supported:

  1. Single constraint: BinaryExpression Constraint for example: quicksum(x) - 1 Constraint(quicksum(x) - 1, "==", 1)

  2. Multiple constraints: list/tuple/np.ndarray, automatically iterated and added one by one for example: [constraint1, constraint2, constraint3]

name (str or list, optional): constraint name, automatically named by default. when multiple constraints are provided,

If a string is passed, it is used as a common prefix; if a list of strings is passed, it must match the number of constraints.

penalty (float, optional): default penalty coefficient

constr_type(str, optional): Constraint type, can be set to “soft” or “hard”, defaults to “hard”

slack_var_expr (BinaryExpression, optional): slack variable expression, used only in inequality constraints,

generated automatically by default

Example1 (Single BinaryExpression):
>>> import kaiwu as kw
>>> model = kw.core.QuboModel()
>>> x = [kw.core.Binary(f"x{i}") for i in range(3)]
>>> model.add_constraint(kw.core.quicksum(x) - 1)
Example2 (Constraint with relation operator):
>>> from kaiwu.core._constraint import Constraint
>>> model.add_constraint(Constraint(kw.core.quicksum(x) - 1, "==", 1))
Examples3 (Multiple Constraints):
>>> constraints = [x[i] - 1 for i in range(3)]
>>> model.add_constraint(constraints, name="my_constraints")
get_value(solution_dict)[source]#

Substitute variable values into QUBO variables based on the result dictionary.

Args:

solution_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

verify_constraint(solution_dict, constr_type: Literal['soft', 'hard'] = 'hard')[source]#

Verify whether constraints are satisfied

Args:

solution_dict (dict): QUBO model solution dictionary

constr_type(str, optional): Constraint type, can be set to “soft” or “hard”, defaults to “hard”

Returns:
tuple: Constraint satisfaction information
  • int: Number of unsatisfied constraints

  • dict: Dictionary containing constraint values

initialize_penalties()[source]#

Automatically initialize all penalty coefficients

get_constraints_expr_list()[source]#

Get all current constraints.

Returns:

list: list of all constraints.

compile_constraints()[source]#

Convert constraint terms to Expression according to different styles

class kaiwu.core.BinaryExpression(coefficient: dict | None = None, offset: float = 0)[source]#

Bases: Expression

Basic data structure for QUBO expressions

feed(feed_dict)[source]#

Assign values to placeholders and return a new expression object after assignment

Args:

feed_dict(dict): Values for placeholders to be assigned

Examples:
>>> import kaiwu as kw
>>> p = kw.core.Placeholder('p')
>>> a = kw.core.Binary('a')
>>> y = p * a
>>> str(y)  
'(p)*a'
>>> y= y.feed({'p': 2})
>>> str(y)  
'2*a'
clear() None#

Set the expression to 0

get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

class kaiwu.core.Binary(name: str = '')[source]#

Bases: BinaryExpression

Binary variable: only stores the variable name, does not inherit QuboExpression

clear()[source]#

Set the expression to 0

feed(feed_dict)#

Assign values to placeholders and return a new expression object after assignment

Args:

feed_dict(dict): Values for placeholders to be assigned

Examples:
>>> import kaiwu as kw
>>> p = kw.core.Placeholder('p')
>>> a = kw.core.Binary('a')
>>> y = p * a
>>> str(y)  
'(p)*a'
>>> y= y.feed({'p': 2})
>>> str(y)  
'2*a'
get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

kaiwu.core.quicksum(qubo_expr_list: list)[source]#

High-performance QUBO summator.

Args:

qubo_expr_list (QUBO list): List of QUBO expressions for summation.

Returns:

BinaryExpression: Constrained QUBO.

Examples:
>>> import kaiwu as kw
>>> qubo_list = [kw.core.Binary(f"b{i}") for i in range(10)] # Variables are also QUBO
>>> output = kw.core.quicksum(qubo_list)
>>> str(output)
'b0+b1+b2+b3+b4+b5+b6+b7+b8+b9'
class kaiwu.core.Placeholder(name: str = '')[source]#

Bases: BinaryExpression

Placeholder variable: only stores the variable name, for decision-making

get_placeholder_set()[source]#

Get the set of placeholders

clear() None#

Set the expression to 0

feed(feed_dict)#

Assign values to placeholders and return a new expression object after assignment

Args:

feed_dict(dict): Values for placeholders to be assigned

Examples:
>>> import kaiwu as kw
>>> p = kw.core.Placeholder('p')
>>> a = kw.core.Binary('a')
>>> y = p * a
>>> str(y)  
'(p)*a'
>>> y= y.feed({'p': 2})
>>> str(y)  
'2*a'
get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

class kaiwu.core.Integer(name: str = '', min_value=0, max_value=127)[source]#

Bases: BinaryExpression

Integer variable: only stores the variable name and range, does not inherit QuboExpression

clear() None#

Set the expression to 0

feed(feed_dict)#

Assign values to placeholders and return a new expression object after assignment

Args:

feed_dict(dict): Values for placeholders to be assigned

Examples:
>>> import kaiwu as kw
>>> p = kw.core.Placeholder('p')
>>> a = kw.core.Binary('a')
>>> y = p * a
>>> str(y)  
'(p)*a'
>>> y= y.feed({'p': 2})
>>> str(y)  
'2*a'
get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

kaiwu.core.ndarray(shape: int | Tuple[int, ...] | List[int], name, var_func, var_func_param=None)[source]#

QUBO container based on np.ndarray. This container supports various native NumPy vectorized operations

Args:

shape (Union[int, Tuple[int, …]]): Shape

name (str): Identifier of the generated variable.

var_func (class or function): Method or class used to generate elements. The first parameter must be ‘name’

var_func_param (tuple): Parameters of var_func except ‘name’

Returns:

np.ndarray: Multi-dimensional container.

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> A = kw.core.ndarray((2,3,4), "A", kw.core.Binary)
>>> A
BinaryExpressionNDArray([[[A[0][0][0], A[0][0][1], A[0][0][2],
                           A[0][0][3]],
                          [A[0][1][0], A[0][1][1], A[0][1][2],
                           A[0][1][3]],
                          [A[0][2][0], A[0][2][1], A[0][2][2],
                           A[0][2][3]]],

                         [[A[1][0][0], A[1][0][1], A[1][0][2],
                           A[1][0][3]],
                          [A[1][1][0], A[1][1][1], A[1][1][2],
                           A[1][1][3]],
                          [A[1][2][0], A[1][2][1], A[1][2][2],
                           A[1][2][3]]]], dtype=object)
>>> A[1,2]
BinaryExpressionNDArray([A[1][2][0], A[1][2][1], A[1][2][2], A[1][2][3]],
                        dtype=object)
>>> A[:, [0,2]]
BinaryExpressionNDArray([[[A[0][0][0], A[0][0][1], A[0][0][2],
                           A[0][0][3]],
                          [A[0][2][0], A[0][2][1], A[0][2][2],
                           A[0][2][3]]],

                         [[A[1][0][0], A[1][0][1], A[1][0][2],
                           A[1][0][3]],
                          [A[1][2][0], A[1][2][1], A[1][2][2],
                           A[1][2][3]]]], dtype=object)
>>> B = kw.core.ndarray(3, "B", kw.core.Binary)
>>> B
BinaryExpressionNDArray([B[0], B[1], B[2]], dtype=object)
>>> C = kw.core.ndarray([3,3], "C", kw.core.Binary)
>>> C
BinaryExpressionNDArray([[C[0][0], C[0][1], C[0][2]],
                         [C[1][0], C[1][1], C[1][2]],
                         [C[2][0], C[2][1], C[2][2]]], dtype=object)
>>> D = 2 * B.dot(C) + 2
>>> str(D[0])
'2*B[0]*C[0][0]+2*B[1]*C[1][0]+2*B[2]*C[2][0]+2'
>>> E = B.sum()
>>> str(E)
'B[0]+B[1]+B[2]'
>>> F = np.diag(C)
>>> F
BinaryExpressionNDArray([C[0][0], C[1][1], C[2][2]], dtype=object)
kaiwu.core.zeros(shape) BinaryExpressionNDArray[source]#

Create a zero array with the same shape as the input array.

Args:

shape (tuple): matrix

Returns:

QUBOArray: array with the same shape and all elements set to 0.

Examples:
>>> import kaiwu as kw
>>> Z = kw.core.zeros((2, 3))
>>> Z
BinaryExpressionNDArray([[0, 0, 0],
                         [0, 0, 0]], dtype=object)
kaiwu.core.dot(mat_left, mat_right)[source]#

Matrix multiplication

Args:

mat_left (numpy.array): First matrix

mat_right (numpy.array): Second matrix

Raises:

ValueError: Both inputs must be np.ndarray. ValueError: Dimensions of the two inputs must match

Returns:

np.ndarray: Product matrix

class kaiwu.core.BinaryExpressionNDArray[source]#

Bases: ndarray

QUBO container based on np.ndarray. This container supports various native NumPy vectorized operations

is_array_less = <numpy.vectorize object>#
is_array_less_equal = <numpy.vectorize object>#
is_array_greater = <numpy.vectorize object>#
is_array_greater_equal = <numpy.vectorize object>#
is_array_equal = <numpy.vectorize object>#
dot(b, out=None)[source]#

Matrix multiplication using quicksum

Args:

b (BinaryExpressionNDArray): Another matrix

out: Optional output array used to store the results. It must match the expected output shape.

Returns:

BinaryExpressionNDArray: Product

sum(axis=None, dtype=None, out=None, keepdims=False, initial=0, where=True)[source]#

Summation method using quicksum

Args:

axis: Specifies the axis (dimension) for summation. The default is None, which means summing over all elements; if it is an integer or tuple, summing is performed along the specified axis.

dtype: Specifies the output data type. If not provided, the input array’s dtype is used by default, but integer types may be upgraded to platform integer precision. Not currently supported.

out: Optional output array used to store the results. It must match the expected output shape.

keepdims: Boolean value. If True, the axis being summed is retained as a dimension of length 1. Not currently supported.

initial: The initial value (scalar) for summation, which defaults to 0. Not currently supported.

where: A boolean array specifying which elements are included in the summation (supported in NumPy 1.20+). Not currently supported.

Returns:

BinaryExpressionNDArray: Product

get_val(sol_dict)[source]#

Substitute spin values into QUBO array variables based on the result dictionary.

Args:

array (QUBOArray): QUBO array

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

np.ndarray: Value array obtained after substituting into the QUBO array

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> x = kw.core.ndarray((2, 2), "x", kw.core.Binary)
>>> y = x.sum()
>>> y_vars = y.get_variables()
>>> s = np.array([1, -1, 1, -1])
>>> sol_dict = kw.core.get_sol_dict(s, y_vars)
>>> x.get_val(sol_dict)
array([[1., 0.],
       [1., 0.]])
class kaiwu.core.IsingModel(variables, ising_matrix, bias)[source]#

Bases: dict

Ising model

get_variables()[source]#

Get variables in the model

get_matrix()[source]#

Get the Ising matrix

get_bias()[source]#

Get the constant offset obtained during QUBO conversion

fromkeys(value=None, /)#

Create a new dictionary with keys from iterable and values set to value.

class kaiwu.core.IsingExpression(variables=None, quadratic=None, linear=None, bias=0)[source]#

Bases: Expression

Base class for Ising expressions; directly inherits Expression and preserves extension points.

clear() None#

Set the expression to 0

get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

class kaiwu.core.Spin(name: str = '')[source]#

Bases: IsingExpression

Spin variable; possible values are only -1 and 1.

Args:

name (str): unique identifier of the variable.

Returns:

dict: spin variable named name.

Examples:
>>> import kaiwu as kw
>>> s = kw.core.Spin("s")
>>> s
2*s-1
clear() None#

Set the expression to 0

get_average_coefficient()#

Return the average value of coefficients

get_max_deltas()#

Calculate the upper bound of the objective function change caused by flipping each variable. The return values negative_delta and positive_delta are the maximum changes caused by flipping the variable from 1->0 and 0->1, respectively.

get_val(sol_dict)#

Substitute spin values into QUBO variables based on the result dictionary.

Args:

qubo (QUBO expression): QUBO expression

sol_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

Examples:
>>> import kaiwu as kw
>>> import numpy as np
>>> a = kw.core.Binary("a")
>>> b = kw.core.Binary("b")
>>> c = kw.core.Binary("c")
>>> d = a + 2 * b + 4 * c
>>> sol_dict = {"a": 1, "b": 0, "c": 1}
>>> d.get_val(sol_dict)
5
get_variables()#

Get the set of variable names

Returns:

dict: returnexpressionvariable

class kaiwu.core.QuboModel(objective=None)[source]#

Bases: BinaryModel

QUBO model class that supports adding constraints

Args:

objective (QuboExpression, optional): objective function. defaultNone

invalidate_made_state()[source]#

Invalidate the made state when the model changes

make()[source]#

Return the merged QUBO expression

Returns:

BinaryExpression: merged constraint expression

get_matrix()[source]#

Get the QUBO matrix

Returns:

numpy.ndarray: QUBOmatrix

get_variables()[source]#

getqubomodelvariables

get_offset()[source]#

getqubomodeloffset

get_sol_dict(qubo_solution)[source]#

Generate a result dictionary from the solution vector.

add_constraint(constraint_in, name=None, constr_type: Literal['soft', 'hard'] = 'hard', penalty=1, slack_var_expr=None)#

Add constraint terms; single or multiple constraints are supported

Args:

constraint_in: constraint expression; two input types are supported:

  1. Single constraint: BinaryExpression Constraint for example: quicksum(x) - 1 Constraint(quicksum(x) - 1, "==", 1)

  2. Multiple constraints: list/tuple/np.ndarray, automatically iterated and added one by one for example: [constraint1, constraint2, constraint3]

name (str or list, optional): constraint name, automatically named by default. when multiple constraints are provided,

If a string is passed, it is used as a common prefix; if a list of strings is passed, it must match the number of constraints.

penalty (float, optional): default penalty coefficient

constr_type(str, optional): Constraint type, can be set to “soft” or “hard”, defaults to “hard”

slack_var_expr (BinaryExpression, optional): slack variable expression, used only in inequality constraints,

generated automatically by default

Example1 (Single BinaryExpression):
>>> import kaiwu as kw
>>> model = kw.core.QuboModel()
>>> x = [kw.core.Binary(f"x{i}") for i in range(3)]
>>> model.add_constraint(kw.core.quicksum(x) - 1)
Example2 (Constraint with relation operator):
>>> from kaiwu.core._constraint import Constraint
>>> model.add_constraint(Constraint(kw.core.quicksum(x) - 1, "==", 1))
Examples3 (Multiple Constraints):
>>> constraints = [x[i] - 1 for i in range(3)]
>>> model.add_constraint(constraints, name="my_constraints")
compile_constraints()#

Convert constraint terms to Expression according to different styles

get_constraints_expr_list()#

Get all current constraints.

Returns:

list: list of all constraints.

get_value(solution_dict)#

Substitute variable values into QUBO variables based on the result dictionary.

Args:

solution_dict (dict): Result dictionary generated by get_sol_dict.

Returns:

float: Value obtained after substituting into the QUBO

initialize_penalties()#

Automatically initialize all penalty coefficients

set_constraint_handler(constraint_handler)#

Set the unconstrained conversion method for constraint terms

Args:

constraint_handler: Class for setting the unconstrained representation method of constraint terms

set_objective(objective)#

Set the objective function

Args:

objective (BinaryExpression): Objective function expression

verify_constraint(solution_dict, constr_type: Literal['soft', 'hard'] = 'hard')#

Verify whether constraints are satisfied

Args:

solution_dict (dict): QUBO model solution dictionary

constr_type(str, optional): Constraint type, can be set to “soft” or “hard”, defaults to “hard”

Returns:
tuple: Constraint satisfaction information
  • int: Number of unsatisfied constraints

  • dict: Dictionary containing constraint values

kaiwu.core.calculate_qubo_value(qubo_matrix, offset, binary_configuration)[source]#

Q value calculator.

Args:

qubo_matrix (np.ndarray): QUBOmatrix.

offset (float): constant term

binary_configuration (np.ndarray): binary configuration

Returns:

output (float): Q value.

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> matrix = np.array([[1., 0., 0.],
...                    [0., 1., 0.],
...                    [0., 0., 1.]])
>>> offset = 1.8
>>> binary_configuration = np.array([0, 1, 0])
>>> qubo_value = kw.core.calculate_qubo_value(matrix, offset, binary_configuration)
>>> print(qubo_value)
2.8
kaiwu.core.qubo_matrix_to_qubo_model(qubo_mat)[source]#

Convert a QUBO matrix to a QUBO model

Args:

qubo_mat (np.ndarray): QUBOmatrix

Returns:

QuboModel: QUBO model

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> matrix = -np.array([[0, 8],
...                     [0, 0]])
>>> kw.core.qubo_matrix_to_qubo_model(matrix).objective
-8*b[0]*b[1]
kaiwu.core.ising_matrix_to_qubo_matrix(ising_mat, remove_linear_bit=True, decimal=False)[source]#

Convert an Ising matrix to a QUBO matrix

Args:

ising_mat (np.ndarray): Isingmatrix

remove_linear_bit (bool): An auxiliary variable is added to represent linear terms when converting QUBO to Ising. Whether to remove the last spin variable. Defaults to True.

decimal (bool): whether to use Decimal for high-precision computation; defaults to False.

Returns:

tuple: QUBO matrix and bias

  • qubo_mat (np.ndarray): QUBOmatrix

  • bias (float): constant term difference between QUBO and Ising

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> matrix = -np.array([[ 0. ,  1. ,  0. ,  1. ,  1. ],
...                     [ 1. ,  0. ,  0. ,  1.,   1. ],
...                     [ 0. ,  0. ,  0. ,  1.,   1. ],
...                     [ 1. ,  1.,   1. ,  0. ,  1. ],
...                     [ 1. ,  1.,   1. ,  1. ,  0. ]])
>>> _qubo_mat, _ = kw.core.ising_matrix_to_qubo_matrix(matrix)
>>> _qubo_mat
array([[-4.,  8.,  0.,  8.],
       [-0., -4.,  0.,  8.],
       [-0., -0., -0.,  8.],
       [-0., -0., -0., -8.]])
kaiwu.core.qubo_matrix_to_ising_matrix(qubo_mat, decimal=False)[source]#

Convert a QUBO matrix to an Ising matrix

Args:

qubo_mat (np.ndarray): QUBOmatrix

decimal (bool): whether to use Decimal for high-precision computation; defaults to False.

Returns:
tuple: Ising matrix and bias
  • ising_mat (np.ndarray): Isingmatrix

  • bias (float): constant term difference between QUBO and Ising

Examples:
>>> import numpy as np
>>> import kaiwu as kw
>>> matrix = -np.array([[-4.,  8.,  0.,  8.],
...                     [-0., -4.,  0.,  8.],
...                     [-0., -0., -0.,  8.],
...                     [-0., -0., -0., -8.]])
>>> _ising_mat, _ = kw.core.qubo_matrix_to_ising_matrix(matrix)
>>> _ising_mat
array([[-0.,  1., -0.,  1.,  1.],
       [ 1., -0., -0.,  1.,  1.],
       [-0., -0., -0.,  1.,  1.],
       [ 1.,  1.,  1., -0.,  1.],
       [ 1.,  1.,  1.,  1., -0.]])
kaiwu.core.qubo_model_to_ising_model(qubo_model)[source]#

Convert QUBO to a Ising model.

Args:

qubo_model (QuboModel): QUBO Model.

Returns:

CimIsing: Ising model.

Examples:
>>> import kaiwu as kw
>>> b1, b2 = kw.core.Binary("b1"), kw.core.Binary("b2")
>>> q = b1 + b2 + b1*b2
>>> q_model = kw.core.QuboModel(q)
>>> ci = kw.core.qubo_model_to_ising_model(q_model)
>>> print(str(ci))
Ising Details:
  Ising Matrix:
    [[-0.    -0.125 -0.375]
     [-0.125 -0.    -0.375]
     [-0.375 -0.375 -0.   ]]
  Ising Bias: 1.25
  Ising Variables: b1, b2, __spin__