kaiwu.core package#

Module contents#

Module: core

Function: Definition of Baseses

class kaiwu.core.OptimizerBase#

Bases: object

Bases for Ising solvers

set_matrix(ising_matrix)#

Set matrix and update related content

on_matrix_change()#

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

solve(ising_matrix=None)#

Solve

class kaiwu.core.SolverBase(optimizer)#

Bases: object

Bases for Solvers

Args:

optimizer (OptimizerBase): Ising solver

solve_qubo(*args, **kwargs)#
exception kaiwu.core.KaiwuError#

Bases: Exception

Bases for exceptions in this module.

args#
with_traceback()#

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

class kaiwu.core.ConstraintDefinition(expr_left, relation, expected_value=0)#

Bases: object

Constraint Definition Args:

expr_left (Expression): Left operator of the constraint term

relation (string): Relational operator

expected_value(float): Right operator of the constraint term, default is 0

is_satisfied(solution_dict)#

Verify constraint satisfaction

kaiwu.core.get_min_penalty(obj, cons)#

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("b"+str(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)#

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)#

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("b"+str(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')#

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("b"+str(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)#

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: ConstraintDefinition, parent_model)#

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)#

Set penalty coefficient

penalize_more()#

Increase penalty coefficient

penalize_less()#

Decrease penalty coefficient

is_satisfied(solution_dict)#

Verify constraint satisfaction

kaiwu.core.get_sol_dict(solution, vars_dict)#

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.qubo.QuboModel(d)
>>> d_ising = kw.conversion.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_array_val(array, sol_dict)#

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 = kw.qubo.QuboModel(y)
>>> y_ising = kw.conversion.qubo_model_to_ising_model(y)
>>> ising_vars = y_ising.get_variables()
>>> s = np.array([1, -1, 1, -1])
>>> sol_dict = kw.core.get_sol_dict(s, ising_vars)
>>> kw.core.get_array_val(x, sol_dict)
array([[1., 0.],
       [1., 0.]])
kaiwu.core.get_val(qubo, 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
>>> qubo_model = kw.qubo.QuboModel(d)
>>> d_ising = kw.conversion.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)
kaiwu.core.update_constraint(qubo_origin, qubo_result)#

Update the constraints and reduced-order constraint information of qexp to q

class kaiwu.core.Expression(coefficient: dict | None = None, offset: float = 0)#

Bases: dict

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

clear() None.  Remove all items from D.#
get_variables()#

Get the set of variable names

Returns:

variables: (tuple) Returns the set of variables composing the expression

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.

fromkeys(value=None, /)#

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

get_average_coefficient()#

Return the average value of coefficients

kaiwu.core.expr_add(expr_left, expr_right, expr_result)#

Addition of universal quadratic expressions

kaiwu.core.expr_mul(expr_left, expr_right, expr_result)#

Multiplication of universal quadratic expressions

kaiwu.core.expr_neg(expr_origin, expr_result)#

Negation of universal quadratic expressions

kaiwu.core.expr_pow(expr_left, expr_right, expr_result)#

Exponentiation of universal quadratic expressions; requires expr_right to be 1 or 2 only

class kaiwu.core.BinaryModel(objective=None)#

Bases: object

Binary model class

Args:

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

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

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

Add constraint terms (supports single or multiple constraints)

Args:

constraint_in (ConstraintDefinition or iterable): The constraint expression or its iterable object.

name (str or list, optional): Constraint name or list of names; automatically named by default.

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

penalty (float): Default penalty coefficient

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

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

initialize_penalties()#

Automatically initialize all penalty coefficients

get_constraints_expr_list()#

Get all current constraints.

Returns:

List of all constraints.

compile_constraints()#

Convert constraint terms to Expression according to different styles. For inequality constraints, the penalty function method is currently supported.

class kaiwu.core.BinaryExpression(coefficient: dict | None = None, offset: float = 0, name='')#

Bases: Expression

Basic data structure for QUBO expressions

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'
clear() None.  Remove all items from D.#
fromkeys(value=None, /)#

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

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_variables()#

Get the set of variable names

Returns:

variables: (tuple) Returns the set of variables composing the expression

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

Bases: BinaryExpression

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

clear() None.  Remove all items from D.#
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'
fromkeys(value=None, /)#

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

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_variables()#

Get the set of variable names

Returns:

variables: (tuple) Returns the set of variables composing the expression

kaiwu.core.quicksum(qubo_expr_list: list)#

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("b"+str(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 = '')#

Bases: BinaryExpression

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

get_placeholder_set()#

Get the set of placeholders

clear() None.  Remove all items from D.#
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'
fromkeys(value=None, /)#

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

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_variables()#

Get the set of variable names

Returns:

variables: (tuple) Returns the set of variables composing the expression

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

Bases: BinaryExpression

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

clear() None.  Remove all items from D.#
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'
fromkeys(value=None, /)#

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

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_variables()#

Get the set of variable names

Returns:

variables: (tuple) Returns the set of variables composing the expression

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

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.dot(mat_left, mat_right)#

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#

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)#

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)#

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