eqc_models

eqc_models.base

This subpackage contains the building blocks for formulating and solving models with EQC devices. Many well known models in the space of quantum computing use quadratic operators. Two generally accepted formats for quadratic models are Ising Hamiltonian and QUBO operators. Ising models are not explicitly supported because of the simple equivalence to QUBO models. Converters from Ising to QUBO are readily available and may be added as a utility function in the future, but for now are left out of the package. Other quadratic models, such as integer or floating point models are supported using the domain and upper bound of the model variables and the solver choice.

Polynomial models are used to support higher order interactions between variables. These models are defined over non-negative variables with the highest power interaction being the only restriction on variable interactions. This is also known as all-to-all connectivity.

Subpackages

constraints

This module defines support for linear equality and inequality constraints. It can be paired with the penalty multiplier algorithm to choose multiplier values which satisfy the enforcement of constraints as penalties. The mixin pattern is used to allow more complex classes to be built from these bases.

  • ConstraintMixIn
  • ConstraintModel
  • InequalitiesMixIn
  • InequalityConstraintModel
quadratic

This module defines the methods required to convert a linear vector and quadratic matrix into the required operator, either QUBO or Polynomial, for solving with EQC. The support for constraints is also incorporated.

  • ConstrainedQuadraticModel
  • QuadraticModel
polynomial

This module defines the classes and methods for conversion from arrays of coefficients and indices to operators for solving with EQC. The support for constriants is also incorporated.

  • PolynomialModel
  • ConstrainedPolynomialModel
base

This module defines abstract base classes for models and solvers.

  • EqcModel
  • ModelSolver
operators

This module defines the operator types to use for passing problems to EQC devices.

  • Polynomial
  • QUBO
class eqc_models.base.ConstraintsMixIn[source]

Bases: object

This mixin class contains methods and attributes which transform linear constraints into penalties.

lhs = None
rhs = None
alpha = 1
linear_objective = None
quad_objective = None
property penalties: Tuple[ndarray, ndarray]
Returns two numpy arrays, one linear and one quadratic pieces of an operator
property penalty_multiplier: float
property constraints
property offset: float
Calculate the offset due to the conversion of constraints to penalties
evaluate(solution: ndarray, alpha: float | None = None, includeoffset: bool = False)[source]

Compute the objective value plus penalties for the given solution. Including the offset will ensure the penalty contribution is non-negative.

Parameters:
  • solution (np.array) – The solution vector for the problem.
  • alpha (float) – Penalty multiplier, optional. This can be used to test different multipliers for determination of sufficiently large values.
evaluatePenalties(solution) float[source]

Evaluate penalty function without alpha or offset

Parameters:
solution (np.array) – The solution vector for the problem.
checkPenalty(solution: ndarray)[source]

Get the penalty of the solution.

Parameters:
solution (np.array) – The solution vector for the problem.
class eqc_models.base.ConstraintModel[source]

Bases: ConstraintsMixIn, EqcModel

Abstract class for representing linear constrained optimization problems as EQC models.

class eqc_models.base.ConstrainedQuadraticModel(C_obj: array, J_obj: array, lhs: array, rhs: array)[source]

Bases: ConstraintsMixIn, QuadraticModel

Provides a constrained quadratic operator and device sum constraint support.

Parameters:
  • J (Quadratic hamiltonian array.)
  • C (Linear hamiltonian array.)
  • lhs (Left hand side of the linear constraints.)
  • rhs (Right hand side of the linear constraints.)

Examples

  • >>> C = np.array([1, 2])
  • >>> J = np.array([[2, 1], [1, 2]])
  • >>> lhs = np.array([[1, 1], [1, 1]])
  • >>> rhs = np.array([1, 1])
  • >>> from eqc_models.base.quadratic import ConstrainedQuadraticModel
  • >>> model = ConstrainedQuadraticModel(C, J, lhs, rhs)
  • >>> model.penalty_multiplier = 1
  • >>> model.upper_bound = np.array([1, 1])
  • >>> qubo = model.qubo
  • >>> qubo.Q
  • array([[1., 3.],
  • [3., 2.]])
property H: Tuple[ndarray, ndarray]

Return a pair of arrays, the linear and quadratic portions of a quadratic operator that has the objective plus penalty functions multiplied by the penalty multiplier. The linear terms are the first array and the quadratic are the second.

Return type:
np.ndarray, np.nedarray
property penalty_multiplier: float
property constraints
evaluateObjective(solution: ndarray) float[source]
class eqc_models.base.QuadraticModel(C: ndarray, J: ndarray)[source]

Bases: QuadraticMixIn, EqcModel

Provides a quadratic operator and device sum constraint support.

Parameters:
  • J (Quadratic hamiltonian array.)
  • C (Linear hamiltonian array.)

Examples

  • >>> C = np.array([1, 2])
  • >>> J = np.array([[2, 1], [1, 2]])
  • >>> from eqc_models.base.quadratic import QuadraticModel
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1])
  • >>> qubo = model.qubo
  • >>> qubo.Q
  • array([[3., 1.],
  • [1., 4.]])
class eqc_models.base.PolynomialModel(coefficients: List | ndarray, indices: List | ndarray)[source]

Bases: PolynomialMixin, EqcModel

Polynomial model base class.

Parameters:
  • coefficients (An array of polynomial coeffients.)
  • indices (An array of polynomial indices.)

Examples

  • >>> coeffs = np.array([1, 2, 3])
  • >>> indices = np.array([[0, 0, 1], [0, 1, 1], [1, 1, 1]])
  • >>> from eqc_models.base.polynomial import PolynomialModel
  • >>> polynomial = PolynomialModel(coeffs, indices)
  • >>> solution = np.array([1, 1, 1])
  • >>> value = polynomial.evaluate(solution)
  • >>> int(value)
  • 6
  • >>> polynomial.H
  • (array([1, 2, 3]), array([[0, 0, 1],
  • [0, 1, 1],
  • [1, 1, 1]]))
property polynomial: Polynomial
class eqc_models.base.ConstrainedPolynomialModel(coefficients: List | ndarray, indices: List | ndarray, lhs: ndarray, rhs: ndarray)[source]

Bases: ConstraintsMixIn, PolynomialModel

Constrained Polynomial model base class.

Parameters:
  • coefficients (An array of polynomial coeffients.)
  • indices (An array of polynomial indices.)
  • lhs (Left hand side of the linear constraints.)
  • rhs (Right hand side of the linear constraints.)
property penalties

coefficients, indices

indices are of the format [0, idx-1, …, idx-d] which must be non-decreasing and each idx-j is a 1-based index of the variable which is a power in the term. For a polynomial where the highest degree is 3 and specifying a term such as x_1x_2, the index array is [0, 1, 2]. Another example, x_1^2x_2 is [1, 1, 2].

Only linear equality constraints are supported. Translate Ax=b into penalties using the superclass.

Type:
Penalty terms specified as a polynomial
evaluatePenalties(solution: ndarray, include_offset=False) float[source]

Take the polynomial form of the penalties from the penalties property and evaluate the solution. The offset can be included by passing a True value to the include_offset keyword argument.

Parameters:
  • solution (np.ndarray) – Solution to evaluate for a penalty value
  • include_offset (bool) – Optional argument indicating whether or not to include the offset value.
Returns:
Penalty value
Return type:
float

Examples

  • >>> coeff = np.array([-1.0, -1.0])
  • >>> indices = np.array([(0, 1), (0, 2)])
  • >>> lhs = np.array([[1.0, 1.0]])
  • >>> rhs = np.array([1.0])
  • >>> model = ConstrainedPolynomialModel(coeff, indices, lhs, rhs)
  • >>> sol = np.array([1.0, 1.0])
  • >>> lhs@sol - rhs
  • array([1.])
  • >>> model.evaluatePenalties(sol)+model.offset
  • 1.0
  • >>> model.evaluatePenalties(sol)
  • 0.0
  • >>> model.evaluatePenalties(sol, include_offset=True)
  • 1.0
evaluateObjective(solution: ndarray) float[source]

Take the polynomial coeff and indices from constructor and evalute the solution with it.

Parameters:
solution (np.ndarray) – Soluttion to evaluate the objective value
Returns:
objective value
Return type:
float
property H: Tuple[ndarray, ndarray]
Provide the sparse format for the Hamiltonian
class eqc_models.base.InequalitiesMixin[source]

Bases: object

This mixin enables inequality constraints by automatically generating slack variables for each inequality

This mixin adds a senses attribute which has a value for each constraint. The values are one of ‘EQ’, ‘LE’ or ‘GE’ for equal to, less than or equal to or greater than or equal to. The effect of the value is to control whether a slack is added and what the sign of the slack variable in the constraint is. Negative is used for GE, positive is used for LE and all slack variables get a coefficient magnitude of 1.

The constraints are modified on demand, so the class members, lhs and rhs remain unmodified.

property senses: List[str]
Comparison operator by constraint
property num_slacks: int

The number of slack variables. Will match the number of inequality constraints.

Returns:
number
Return type:
int
property constraints: Tuple[ndarray, ndarray]
Get the general form of the constraints, add slacks where needed and return a standard, equality constraint form.
class eqc_models.base.InequalityConstraintModel[source]

Bases: InequalitiesMixin, ConstraintModel

Abstract class for a linear constrained optimization model with inequality constraints

class eqc_models.base.EqcModel[source]

Bases: object

EqcModel subclasses must provide these properties/methods.

Decode:
takes a raw solution and translates it into the original problem formulation
H:
property which returns a Hamiltonian operator
Upper_bound:
Let D be an array of length n which contains the largest possible value allowed for x[i], which is the variable at index i, 0<=i<n. This means that a x[i] is in the domain [0,D[i]]. If the solution type of x[i] is integer, then x[i] is in the set of integers, Z, and also 0<=x[i]<=floor(D[i]).
Qudit_limits:
maximum value permitted for each qudit
  • >>> model = EqcModel()
  • >>> ub = np.array([1, 1.5, 2])
  • >>> model.upper_bound = ub
  • Traceback (most recent call last):
  • ...
  • ValueError: ...
  • >>> model.upper_bound = np.ones((3,))
  • >>> (model.upper_bound==np.ones((3,))).all()
  • True
  • >>> model.upper_bound = 2*np.ones((3,))
  • >>> (model.upper_bound==2).all()
  • True
decode(solution: ndarray) ndarray[source]
Manipulate the solution to match the variable count
property upper_bound: array
An array of upper bound values for every variable in the model. Must be integer.
property domains: array
property n: int
Return the number of variables
property H
Hamiltonian operator of unknown type
property sparse: Tuple[ndarray, ndarray]
property machine_slacks
Number of slack qudits to add to the model
evaluateObjective(solution: ndarray) float[source]
createConfigElements() Dict[source]
createBenchmarkConfig(fname: str) None[source]
property dynamic_range: float
property polynomial: Polynomial
property qubo: QUBO
class eqc_models.base.ModelSolver[source]

Bases: object

Provide a common interface for solver implementations. Store a model, implement a solve method.

solve(model: EqcModel, *args, **kwargs) Dict[source]
class eqc_models.base.QUBO(Q: ndarray)[source]

Bases: object

Contains a QUBO in a symmetric matrix

If the matrix Q is not symmetric already, it will be after __post_init__

Parameters:
qubo (np.array) – 2d symmetric matrix of values which describe a quadratic unconstrained binary optimization problem.
Q: ndarray
evaluate(solution: ndarray)[source]
class eqc_models.base.Polynomial(coefficients: List, indices: List)[source]

Bases: object

Represents an operator and evalute the operator at a point or set of points. The operator must be a polynomial, possibly multivariate, with powers of up to 5, at the time of this version. The representation of a polynomial uses a sparse method with two components per term. A term is described by the coefficient and a tuple of integers which indicate the variable indexes of the term. The coefficients can be any value which fits in 32-bit floating point representation, but the dynamic range of the coefficients should be within the limit of the hardware’s sensitivity for best results. The term index tuple length must be consistent across all terms. If a term does not have a variable index for all positions, such as with a term which is the square of a variable when other terms have third-order powers, then there must be a placeholder of 0 for the unused power. The variable indexes must be in the tuple in ascending order. Here are some examples (suppose the max degree is 4):

  • x12x_1^2: (0, 0, 1, 1)
  • x1x2x3x_1 x_2 x_3: (0, 1, 2, 3)
  • x22x32x_2^2 x_3^2: (2, 2, 3, 3)

while it does not affect the optimiztion, a constant term can be applied to the polynomial by using an index of all zeros (0, 0, 0, 0). When listing the coefficients, the position in the array must correspond to the position in the array of indexes. Also, the indices must be ordered with linear terms first, quadratic terms next and so forth. A polynomial operator does not have an explicit domain. It could be evaluated on an array of any real numbers.

Parameters:
  • coefficients (List, np.array) – Floating point values for the coefficients of a polynomial. Must correspond to the entries in the indices array.
  • indices (List, np.array) – List of tuples or 2d np.array with integer values describing the term which the corresponding coefficient value is used for.

Examples

  • >>> coefficients = [-1, -1, 2]
  • >>> indices = [(0, 1), (0, 2), (1, 2)]
  • >>> polynomial = Polynomial(coefficients, indices)
  • >>> test_solution = np.array([1, 1])
  • >>> polynomial.evaluate(test_solution)
  • [0]
  • >>> test_solution = np.array([1, 0])
  • >>> polynomial.evaluate(test_solution)
  • [-1]
  • >>> test_solution = np.array([5, -1])
  • >>> polynomial.evaluate(test_solution)
  • [-14]
  • >>> test_solution = np.array([2.5, -2.5])
  • >>> polynomial.evaluate(test_solution)
  • [-12.5]
coefficients: List
indices: List
pure_evaluate(solution: ndarray) ndarray[source]

Evaluation in pure python

Parameters:
solution (np.array) – Solution to evaluate, is optionally 2-d, which results in multiple evaluations
Return type:
np.array
evaluate(solution: ndarray)[source]

Evaluate the polynomial at the solution point. If the Cython module is available, use that for speedup, otherwise evaluate with Python loops.

Parameters:
solution (np.array) – Solution to evaluate. Is optinoally 2-d, which results in multiple exaluations.
Return type:
1-d array of values which match the coerced dtype of the inputs.

eqc_models.solvers

class eqc_models.solvers.Dirac1CloudSolver(url=None, api_token=None)[source]

Bases: Dirac1Mixin, QuboSolverMixin, QciClientSolver

Overview

Dirac1CloudSolver is a class that encapsulates the different calls to Qatalyst for Dirac-1 jobs, which are quadratic binary optimization problems.

Examples

  • >>> C = np.array([[-1], [-1]])
  • >>> J = np.array([[0, 1.0], [1.0, 0]])
  • >>> from eqc_models.base.quadratic import QuadraticModel
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> solver = Dirac1CloudSolver()
  • >>> response = solver.solve(model, num_samples=5)
  • 2... submitted... COMPLETED...
  • >>> response["results"]["energies"][0] <= 1.0
  • True
class eqc_models.solvers.Dirac3CloudSolver(url=None, api_token=None)[source]

Bases: Dirac3Mixin, QciClientSolver

Dirac3CloudSolver is a class that encapsulates the different calls to Qatalyst for Dirac-3 jobs. Currently, there are two different jobs, one for integer and another for continuous solutions. Calling the solve method with different arguments controls which job is submitted. The continuous job requires sum_constraint and optionally takes the solution_precision argument. The integer job does not accept either of these parameters, so specifying a sum constraint forces the job type to be continuous and not specifying it results in the integer job being called.

Continuous Solver

Utilizing Dirac-3 as a continuous solver involves encoding the variables in single time bins with the values of each determined by a normalized photon count value.

Integer Solver

Utilizing Dirac-3 as an integer solver involves encoding the variables in multiple time bins, each representing a certain value for that variable, or “qudit”.

Examples

  • >>> C = np.array([[1], [1]])
  • >>> J = np.array([[-1.0, 0], [0, -1.0]])
  • >>> from eqc_models.base.quadratic import QuadraticModel
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> solver = Dirac3CloudSolver()
  • >>> response = solver.solve(model, sum_constraint=1, relaxation_schedule=1,
  • ... solution_precision=None)
  • 2... submitted... COMPLETED...
  • >>> response["results"]["energies"][0] <= 1.0
  • True
  • >>> C = np.array([-1, -1], dtype=np.float32)
  • >>> J = np.array([[0, 1], [1, 0]], dtype=np.float32)
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> response = solver.solve(model, relaxation_schedule=1)
  • 2... submitted... COMPLETED...
  • >>> response["results"]["energies"][0] == -1.0
  • True
job_type = 'hamiltonian'
job_params_names = ['num_samples', 'solution_precision', 'relaxation_schedule', 'mean_photon_number', 'normalized_loss_rate', 'num_levels', 'sum_constraint']
solve(model: EqcModel, name: str | None = None, tags: List | None = None, sum_constraint: float | None = None, relaxation_schedule: int | None = None, solution_precision: float | None = None, num_samples: int = 1, wait: bool = True, mean_photon_number: float | None = None, normalized_loss_rate: int | None = None, **job_kwargs)[source]
Parameters:
  • model (EqcModel) – a model object which supplies a hamiltonian operator for the device to sample. Must support the polynomial operator property.
  • tags (List) – a list of strings to save with the job
  • sum_constraint (float) – a value which applies a constraint to the solution, forcing all variables to sum to this value, changes method to continuous solver
  • relaxation_schedule (int) – a predefined schedule indicator which sets parameters on the device to control the sampling through photon measurement
  • solution_precision (float) – a value which, when not None, indicates the numerical precision desired in the solution: 1 for integer, 0.1 for tenths place, 0.01 for hundreths and None for raw, only used with continuous solver
  • num_samples (int) – the number of samples to take, defaults to 1
  • wait (bool) – a flag for waiting for the response or letting it run asynchronously. Asynchronous runs must retrieve results directly using qci-client and the job_id.
  • mean_photon_number (float) – an optional decimal value which sets the average number of photons that are present in a given quantum state. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values are decimals between 0.1 and 2.
  • normalized_loss_rate (int) – an integer value which Sets the amount of loss introduced into the system for each loop during the measurement process. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values range from 1 to 50.
class eqc_models.solvers.QciClientSolver(url=None, api_token=None)[source]

Bases: QciClientMixin, ModelSolver

Parameters:
  • url (string) – optional value specifying the QCi API URL
  • api_token (string) – optional value specifying the authentication token for the QCi API
  • the (QCi API client wrapper for solving an EQC model. This class provides)
  • file (common method for uploading a file to the API for solving. Since the)
  • types (types change for the job)
  • are (the specific files required for the job)
  • method. (specified in subclasses within the uploadFiles)
static uploadFile(file_data: ndarray, file_name: str | None = None, file_type: str | None = None, client: OptimizationClient | None = None) str[source]

Upload the operator file, return the file ID.

Parameters:
  • file_data (numpy array, dictionary or list) – contains file data to be uploaded
  • file_name (str) – Name of the file to be uploaded.
  • file_type (str) – Type of the file to be uploaded.
  • client (QciClient) – QciClient instance
uploadJobFiles(client: OptimizationClient, model: EqcModel)[source]
solve(model: EqcModel, name: str | None = None, tags: List | None = None, num_samples: int = 1, wait=True, job_type=None, **job_kwargs) Dict[source]
Parameters:
  • model (EqcModel) – Instance of a model for solving.
  • name (str) – Name of the job; default is None.
  • tags (list) – A list of job tags; default is None.
  • num_samples (int) – Number of samples used; default is 1.
  • wait (bool) – The wait flag indicating whether to wait for the job to complete before returning the complete job data otherwise return a job ID as soon as a job is submitted; default is True.
  • job_type (str) – Type of the job; default is None. When None, it is constructed from the instance job_type property.
Returns:
  • job response dictionary
  • This method takes the particulars of the instance model and handles
  • the QciClient.solve call.
getResults(response: Dict) Dict[str, List][source]

Extract the results from response.

Parameters:
response (The responce from QciClient.)
Return type:
The results json object.
class eqc_models.solvers.Dirac3IntegerCloudSolver(url=None, api_token=None)[source]

Bases: Dirac3Mixin, QciClientSolver

  • >>> C = np.array([-1, -1], dtype=np.float32)
  • >>> J = np.array([[0, 1], [1, 0]], dtype=np.float32)
  • >>> from eqc_models.base.quadratic import QuadraticModel
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> solver = Dirac3IntegerCloudSolver()
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> response = solver.solve(model, relaxation_schedule=1)
  • 2... submitted... COMPLETED...
  • >>> response["results"]["energies"][0] == -1.0
  • True
job_type = 'hamiltonian-integer'
job_params_names = ['num_samples', 'solution_precision', 'relaxation_schedule', 'mean_photon_number', 'normalized_loss_rate', 'num_levels']
solve(model: EqcModel, name: str | None = None, tags: List | None = None, relaxation_schedule: int | None = None, num_samples: int = 1, wait: bool = True, mean_photon_number: float | None = None, normalized_loss_rate: int | None = None, **job_kwargs)[source]
Parameters:
  • model (EqcModel) – a model object which supplies a hamiltonian operator for the device to sample. Must support the polynomial operator property.
  • tags (List) – a list of strings to save with the job
  • relaxation_schedule (int) – a predefined schedule indicator which sets parameters on the device to control the sampling through photon measurement
  • num_samples (int) – the number of samples to take, defaults to 1
  • wait (bool) – a flag for waiting for the response or letting it run asynchronously. Asynchronous runs must retrieve results directly using qci-client and the job_id.
  • mean_photon_number (float) – an optional decimal value which sets the average number of photons that are present in a given quantum state. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values are decimals between 0.1 and 2.
  • normalized_loss_rate (int) – an integer value which Sets the amount of loss introduced into the system for each loop during the measurement process. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values range from 1 to 50.

Dirac3IntegerCloudSolver is a class that encapsulates the different calls to Qatalyst for Dirac-3 jobs. Utilizing Dirac-3 as an integer solver involves encoding the variables in multiple time bins, each representing a certain value for that variable, or “qudit”.

class eqc_models.solvers.Dirac3ContinuousCloudSolver(url=None, api_token=None)[source]

Bases: Dirac3Mixin, QciClientSolver

  • >>> C = np.array([[1], [1]])
  • >>> J = np.array([[-1.0, 0], [0, -1.0]])
  • >>> from eqc_models.base.quadratic import QuadraticModel
  • >>> model = QuadraticModel(C, J)
  • >>> model.upper_bound = np.array([1, 1]) # set the domain maximum per variable
  • >>> solver = Dirac3ContinuousCloudSolver()
  • >>> response = solver.solve(model, sum_constraint=1, relaxation_schedule=1,
  • ... solution_precision=None)
  • 2... submitted... COMPLETED...
  • >>> response["results"]["energies"][0] <= 1.0
  • True
job_type = 'hamiltonian'
job_params_names = ['num_samples', 'solution_precision', 'relaxation_schedule', 'mean_photon_number', 'normalized_loss_rate', 'sum_constraint']
solve(model: EqcModel, name: str | None = None, tags: List | None = None, sum_constraint: float | None = None, relaxation_schedule: int | None = None, solution_precision: float | None = None, num_samples: int = 1, wait: bool = True, mean_photon_number: float | None = None, normalized_loss_rate: int | None = None, **job_kwargs)[source]
Parameters:
  • model (EqcModel) – a model object which supplies a hamiltonian operator for the device to sample. Must support the polynomial operator property.
  • tags (List) – a list of strings to save with the job
  • sum_constraint (float) – a value which applies a constraint to the solution, forcing all variables to sum to this value
  • relaxation_schedule (int) – a predefined schedule indicator which sets parameters on the device to control the sampling through photon measurement
  • solution_precision (float) – a value which, when not None, indicates the numerical precision desired in the solution: 1 for integer, 0.1 for tenths place, 0.01 for hundreths and None for raw
  • num_samples (int) – the number of samples to take, defaults to 1
  • wait (bool) – a flag for waiting for the response or letting it run asynchronously. Asynchronous runs must retrieve results directly using qci-client and the job_id.
  • mean_photon_number (float) – an optional decimal value which sets the average number of photons that are present in a given quantum state. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values are decimals between 0.1 and 2.
  • normalized_loss_rate (int) – an integer value which Sets the amount of loss introduced into the system for each loop during the measurement process. Modify this value to control the relaxation schedule more precisely than the four presets given in schedules 1 through 4. Allowed values range from 1 to 50.

eqc_models.ml

class eqc_models.ml.QBoostClassifier(relaxation_schedule=2, num_samples=1, lambda_coef=0, weak_cls_schedule=2, weak_cls_type='lg', weak_max_depth=10, weak_min_samples_split=100)[source]

Bases: ClassifierBase

An implementation of QBoost classifier that uses QCi’s Dirac-3.

Parameters:
  • relaxation_schedule (Relaxation schedule used by Dirac-3;)
  • default (dct.)
  • num_samples (Number of samples used by Dirac-3; default: 1.)
  • lambda_coef (A penalty multiplier; default: 0.)
  • weak_cls_schedule (Weak classifier schedule. Is either 1, 2,)
  • default
  • weak_cls_type (Type of weak classifier) –

    • dct: Decison tree classifier
    • nb: Naive Baysian classifier
    • lg: Logistic regression
    • gp: Gaussian process classifier
  • default
  • weak_max_depth (Max depth of the tree. Applied only when)
  • Default (weak_cls_type="dct".)
  • weak_min_samples_split (The minimum number of samples required)
  • when (to split an internal node. Applied only)
  • Default

Examples

  • >>> from sklearn import datasets
  • >>> from sklearn.preprocessing import MinMaxScaler
  • >>> from sklearn.model_selection import train_test_split
  • >>> iris = datasets.load_iris()
  • >>> X = iris.data
  • >>> y = iris.target
  • >>> scaler = MinMaxScaler()
  • >>> X = scaler.fit_transform(X)
  • >>> for i in range(len(y)):
  • ... if y[i] == 0:
  • ... y[i] = -1
  • ... elif y[i] == 2:
  • ... y[i] = 1
  • >>> X_train, X_test, y_train, y_test = train_test_split(
  • ... X,
  • ... y,
  • ... test_size=0.2,
  • ... random_state=42,
  • ... )
  • >>> from eqc_models.ml.classifierqboost import QBoostClassifier
  • >>> obj = QBoostClassifier(
  • ... relaxation_schedule=2,
  • ... num_samples=1,
  • ... lambda_coef=0.0,
  • ... )
  • >>> from contextlib import redirect_stdout
  • >>> import io
  • >>> f = io.StringIO()
  • >>> with redirect_stdout(f):
  • ... obj = obj.fit(X_train, y_train)
  • ... y_train_prd = obj.predict(X_train)
  • ... y_test_prd = obj.predict(X_test)
fit(X, y)[source]

Build a QBoost classifier from the training set (X, y).

Parameters:
  • X ({array-like, sparse matrix} of shape (n_samples, n_features))
  • samples. (The training input)
  • y (array-like of shape (n_samples,))
  • values. (The target)
Return type:
Response of Dirac-3 in JSON format.
predict_raw(X: array)[source]

Predict raw output of the classifier for input X.

Parameters:
X ({array-like, sparse matrix} of shape (n_samples, n_features))
Returns:
  • y (ndarray of shape (n_samples,))
  • The predicted raw output of the classifier.
predict(X: array)[source]

Predict classes for X.

Parameters:
X ({array-like, sparse matrix} of shape (n_samples, n_features))
Returns:
  • y (ndarray of shape (n_samples,))
  • The predicted classes.
get_hamiltonian(X: array, y: array)[source]
convert_sol_to_params(sol)[source]
class eqc_models.ml.QSVMClassifier(relaxation_schedule=2, num_samples=1, upper_limit=1.0, gamma=1.0, eta=1.0, zeta=1.0)[source]

Bases: ClassifierBase

An implementation of QSVM classifier that uses QCi’s Dirac-3.

Parameters:
  • relaxation_schedule (Relaxation schedule used by Dirac-3; default:)
  • 2.
  • num_samples (Number of samples used by Dirac-3; default: 1.)
  • upper_limit (Coefficient upper limit; a regularization parameter;)
  • default (1.0.)
  • gamma (Gaussian kernel parameter; default: 1.0.)
  • eta (A penalty multiplier; default: 1.0.)
  • zeta (A penalty multiplier; default: 1.0.)

Examples

  • >>> from sklearn import datasets
  • >>> from sklearn.preprocessing import MinMaxScaler
  • >>> from sklearn.model_selection import train_test_split
  • >>> iris = datasets.load_iris()
  • >>> X = iris.data
  • >>> y = iris.target
  • >>> scaler = MinMaxScaler()
  • >>> X = scaler.fit_transform(X)
  • >>> for i in range(len(y)):
  • ... if y[i] == 0:
  • ... y[i] = -1
  • ... elif y[i] == 2:
  • ... y[i] = 1
  • >>> X_train, X_test, y_train, y_test = train_test_split(
  • ... X,
  • ... y,
  • ... test_size=0.2,
  • ... random_state=42,
  • ... )
  • >>> from eqc_models.ml.classifierqsvm import QSVMClassifier
  • >>> obj = QSVMClassifier(
  • ... relaxation_schedule=2,
  • ... num_samples=1,
  • ... upper_limit=1.0,
  • ... gamma=1.0,
  • ... eta=1.0,
  • ... zeta=1.0,
  • ... )
  • >>> from contextlib import redirect_stdout
  • >>> import io
  • >>> f = io.StringIO()
  • >>> with redirect_stdout(f):
  • ... obj = obj.fit(X_train, y_train)
  • ... y_train_prd = obj.predict(X_train)
  • ... y_test_prd = obj.predict(X_test)
kernel(vec1, vec2)[source]
fit(X, y)[source]

Build a QSVM classifier from the training set (X, y).

Parameters:
  • X ({array-like, sparse matrix} of shape (n_samples, n_features))
  • samples. (The training input)
  • y (array-like of shape (n_samples,))
  • values. (The target)
Return type:
Response of Dirac-3 in JSON format.
predict(X: array)[source]

Predict classes for X.

Parameters:
X ({array-like, sparse matrix} of shape (n_samples, n_features))
Returns:
  • y (ndarray of shape (n_samples,))
  • The predicted classes.
get_hamiltonian(X: array, y: array)[source]
convert_sol_to_params(sol)[source]
class eqc_models.ml.PCA(n_components=None, relaxation_schedule=2, num_samples=1)[source]

Bases: DecompBase

An implementation of Principal component analysis (PCA) that uses QCi’s Dirac-3.

Linear dimensionality reduction using Singular Value Decomposition of the data to project it to a lower dimensional space.

Parameters:
  • n_components (Number of components to keep; if n_components is not)
  • default (set all components are kept;)
  • relaxation_schedule (Relaxation schedule used by Dirac-3; default:)
  • 2.
  • num_samples (Number of samples used by Dirac-3; default: 1.)

Examples

  • >>> from sklearn import datasets
  • >>> iris = datasets.load_iris()
  • >>> X = iris.data
  • >>> from sklearn.preprocessing import StandardScaler
  • >>> scaler = StandardScaler()
  • >>> X = scaler.fit_transform(X)
  • >>> from eqc_models.ml.decomposition import PCA
  • >>> from contextlib import redirect_stdout
  • >>> import io
  • >>> f = io.StringIO()
  • >>> with redirect_stdout(f):
  • ... obj = PCA(
  • ... n_components=4,
  • ... relaxation_schedule=2,
  • ... num_samples=1,
  • ... )
  • ... X_pca = obj.fit_transform(X)
fit(X)[source]

Build a PCA object from the training set X.

Parameters:
  • X ({array-like, sparse matrix} of shape (n_samples, n_features))
  • samples. (The training input)
Returns:
  • responses.
  • A dirct containing Dirac responses.
transform(X: array)[source]

Apply dimensionality reduction to X.

X is projected on the first principal components previously extracted from a training set.

Parameters:
  • X (array-like of shape (n_samples, n_features))
  • data (New)
  • samples (where n_samples is the number of)
  • features. (and n_features is the number of)
Returns:
  • X_new (array-like of shape (n_samples, n_components))
  • Projection of X in the first principal components, where n_samples
  • is the number of samples and n_components is the number of the components.
fit_transform(X)[source]

Fit the model with X and apply the dimensionality reduction on X.

Parameters:
  • X (array-like of shape (n_samples, n_features))
  • data (Training)
  • samples (where n_samples is the number of)
  • features. (and n_features is the number of)
Returns:
  • X_new (ndarray of shape (n_samples, n_components))
  • Transformed values.
class eqc_models.ml.ReservoirForecastModel(ip_addr, num_nodes, feature_scaling, num_pads: int = 0, reg_coef: float = 0.0, device: str = 'EmuCore')[source]

Bases: BaseForecastModel, QciReservoir

A reservoir based forecast model.

Parameters:
  • ip_addr (The IP address of the device.)
  • num_nodes (Number of reservoir network nodes.)
  • feature_scaling (The factor used to scale the reservoir output.)
  • num_pads (Size of the pad used in the reservoir input;)
  • default (supported;)
  • reg_coef (L2 regularization coefficient for linear regression;)
  • default
  • device (The QCi reservoir device. Currently only 'EmuCore' is)
  • default

Examples

  • >>> MAX_TRAIN_DAY = 800
  • >>> IP_ADDR = "172.22.19.49"
  • >>> FEATURE_SCALING = 0.1
  • >>> NUM_NODES = 1000
  • >>> NUM_PADS = 100
  • >>> LAGS = 2
  • >>> from contextlib import redirect_stdout
  • >>> import io
  • >>> f = io.StringIO()
  • >>> from eqc_models.ml import ReservoirForecastModel
  • >>> with redirect_stdout(f):
  • ... model = ReservoirForecastModel(
  • ... ip_addr=IP_ADDR,
  • ... num_nodes=NUM_NODES,
  • ... feature_scaling=FEATURE_SCALING,
  • ... num_pads=NUM_PADS,
  • ... device="EmuCore",
  • ... )
  • ... model.fit(
  • ... data=train_df,
  • ... feature_fields=["norm_cell_prod"],
  • ... target_fields=["norm_cell_prod"],
  • ... lags=LAGS,
  • ... horizon_size=1,
  • ... )
  • ... y_train_pred = model.predict(train_df, mode="in_sample")
  • ... y_test_pred = model.predict(test_df, mode="in_sample")
  • >>> model.close()
close()[source]
fit(data: DataFrame, feature_fields: list, target_fields: list, lags: int = 0, horizon_size: int = 1)[source]

A function to train a forecast model.

Parameters:
  • data (A pandas data frame that contain the time series.)
  • feature_fields (A list of fields in the data frame that are as)
  • reservoir. (inputs to the)
  • target_fields (A list of fields in teh data frame that are to be)
  • forecasted.
  • lags (Number of lags used; default = 0.)
  • horizon_size (Size of the horizon, e.g. number of forecast)
  • steps.
predict(data: DataFrame, pad_mode: str = 'zero', mode: str = 'in_sample')[source]

A function to get predictions from forecast model.

Parameters:
  • data (A pandas data frame that contain the time series.)
  • pad_mode (Mode of the reservoir input padding, either)
  • default (sample (used for testing);)
  • mode (A value of 'out_of_sample' predicts the horizon)
  • in (following the time series. A value of 'in_sample' predicts)
  • default
Returns:
The predictions
Return type:
numpy.array((horizon_size, num_dims)).

eqc_models.allocation

class eqc_models.allocation.AllocationModel(resources: List, tasks: List, resource_usage: List, resource_limits: List, cost_per_task: List)[source]

Bases: ConstrainedQuadraticModel

Parameters:
  • resources (List) – names of available resources.
  • tasks (List) – names of tasks.
  • resource_usage (List of Lists or 2D np.ndarray) – rows represent tasks and columns represent resources, specifying the amount of each resource required per task.
  • resource_limits (1D array or List) – specifying the limit on each resource.
  • cost_per_task (1D array List) – specifying the cost per task (or benefit with negative of value).
penalty_multiplier

value for weighting the penalties formed from the equality constraints

Type:
float
qubo

QUBO operator representation

Type:
eqc_models.base.operators.QUBO
polynomial

Polynomial operator representation

Type:
eqc_models.base.operators.Polynomial

This class represents a resource allocation model for maximizing total benefit. In other words, Given a list of resources and a list of tasks, allocate the resources among the tasks so as to maximize the economic benefit.

Here’s an example. Five tasks must share 4 resources. Each task can use a different amount of each resource.

Spam

Eggs

Coconut

Sparrow

Benefit

Breakfast

1

2

0

0

3

Countryside Stroll

0

0

1

0

1

Storm Castle

0

12

1

1

10

Availability

1

12

2

1

  • >>> resources = ["Spam", "Eggs", "Coconut", "Sparrow"]
  • >>> tasks = ["Breakfast", "Countryside Stroll", "Storm Castle"]
  • >>> resource_usage = [[1, 2, 0, 0], [0, 0, 1, 0], [0, 12, 1, 1]]
  • >>> resource_limits = [1, 12, 2, 1]
  • >>> cost_per_task = [-3, -1, -10.]
  • >>> allocation_model = AllocationModel(resources, tasks, resource_usage, resource_limits, cost_per_task)
  • >>> allocation_model.penalty_multiplier = 1
  • >>> C, J = allocation_model.H
  • >>> C # -3 -2 * (12 * 2 + 1 * 1), -1 -2 * 2*1, -10 -2 * (12 * 12 + 1 * 2 + 1 * 1)
  • ...
  • array([ -53., -5., -304.])
  • >>> J
  • array([[ 5., 0., 24.],
  • [ 0., 1., 1.],
  • [ 24., 1., 146.]])
property upper_bound: array
An array of upper bound values for every variable in the model. Must be integer.
property variables
add_task(task: str, task_resource_usage: List, task_cost: float)[source]
task: str
Name of task to add
task_resource_usage: List
Quantity of resource used for task for all tasks
task_cost: float
Quantity indicating the cost or benefit (negative) of the task

Add a task to the problem, modifying the resource usage and task cost arrays.

property H: Tuple[ndarray, ndarray]
Return linear, quadratic portions of the (quadratic) Hamiltonian
class eqc_models.allocation.AllocationModelX(resources: List, tasks: List, resource_usage: List, resource_limits: List, resource_rule: List[ResourceRuleEnum], cost_per_task: List)[source]

Bases: InequalitiesMixin, AllocationModel

Parameters:
  • resources (List) – names of available resources.
  • tasks (List) – names of tasks.
  • resource_usage (List of Lists or 2D np.ndarray) – rows represent tasks and columns represent resources, specifying the amount of each resource required per task.
  • resource_limits (1D array or List) – specifying the limit on each resource.
  • resource_rule (List) – ResourceRuleEnum values for each resource
  • cost_per_task (1D array List) – specifying the cost per task (or benefit with negative of value).
penalty_multiplier

value for weighting the penalties formed from the equality constraints

Type:
float
qubo

QUBO oeprator representation

Type:
eqc_models.base.operators.QUBO
polynomial

Polynomial operator representation

Type:
eqc_models.base.operators.Polynomial
variables

names of variables formed from tasks and assignments

Type:
List

This class represents a resource allocation model for maximizing total benefit. In other words, Given a list of resources and a list of tasks, allocate the resources among the tasks so as to maximize the economic benefit.

Adds resource_rule as an argument. This must be a list of strings specifying constraints for each resource (LE, GE, or EQ).

Here’s an example. Five tasks must share 4 resources. Each task can use a different amount of each resource.

Spam

Eggs

Coconut

Sparrow

Benefit

Breakfast

1

2

0

0

3

Countryside Stroll

0

0

1

0

1

Storm Castle

0

12

1

1

10

Availability

1

12

2

1

  • >>> resources = ["Spam", "Eggs", "Coconut", "Sparrow"]
  • >>> tasks = ["Breakfast", "Countryside Stroll", "Storm Castle"]
  • >>> resource_usage = [[1, 2, 0, 0], [0, 0, 1, 0], [0, 12, 1, 1]]
  • >>> resource_limits = [1, 12, 2, 1]
  • >>> cost_per_task = [-3, -1, -10.]
  • >>> resource_rules = [ResourceRuleEnum.MAXIMUM for i in range(len(resources))]
  • >>> allocation_model = AllocationModelX(resources, tasks, resource_usage, resource_limits, resource_rules, cost_per_task)
  • >>> allocation_model.penalty_multiplier = 1
  • >>> C, J = allocation_model.H
  • >>> C # -3 -2 * (12 * 2 + 1 * 1), -1 -2 * 2*1, -10 -2 * (12 * 12 + 1 * 2 + 1 * 1)
  • ...
  • array([ -53., -5., -304., -2., -24., -4., -2.])
  • >>> J
  • array([[ 5., 0., 24., 1., 2., 0., 0.],
  • [ 0., 1., 1., 0., 0., 1., 0.],
  • [ 24., 1., 146., 0., 12., 1., 1.],
  • [ 1., 0., 0., 1., 0., 0., 0.],
  • [ 2., 0., 12., 0., 1., 0., 0.],
  • [ 0., 1., 1., 0., 0., 1., 0.],
  • [ 0., 0., 1., 0., 0., 0., 1.]])
property upper_bound: array
An array of upper bound values for every variable in the model. Must be integer.
property linear_objective: ndarray
Returns a 1D numpy array representing the linear part of the objective function (total profit).
property quad_objective: ndarray
Returns a 2D numpy array representing the quadratic part of the objective function (always zero in this case).
property H
Overrides the parent build method to incorporate slack variables based on resource_rule.
checkResources(solution)[source]
Parameters:
solution (List or np.ndarray) – solution vector to check for resource violations
Returns:
List of violations
Return type:
(name, rule, violation quantity, message)
property n
Return the number of variables
class eqc_models.allocation.PortMomentum(stocks: list, stock_data_dir: str, adj_date: str, lookback_days: int = 60, window_days: int = 30, window_overlap_days: int = 15, weight_upper_limit: float = 0.08, r_base: float = 0.00013698630136986303, alpha: float = 5.0, beta: float = 1.0, xi: float = 1.0)[source]

Bases: PortBase

get_hamiltonian(return_df, min_date, max_date)[source]
class eqc_models.allocation.ResourceRuleEnum(value)[source]

Bases: Enum

Enumeration of the allowed resource rules, mapping to the mathematical expression:

MAXIMUM -> LE (less than or equal to) MINIMUM -> GE (greater than or equal to) EXACT -> EQ (equal to)

MAXIMUM = 'LE'
MINIMUM = 'GE'
EXACT = 'EQ'

eqc_models.assignment

class eqc_models.assignment.QAPModel(A: ndarray, B: ndarray, C: ndarray)[source]

Bases: ConstrainedQuadraticModel

Parameters:
  • A (np.array) – matrix of distances or costs between locations
  • B (np.array) – matrix of flows between facilities
  • C (np.array) – matrix pf fixed costs of assigning facilities to locations

Formulates a quadratic programming model from three inputs. The inputs are composed of: a matrix which describes the unit cost of moving a single asset between locations. This matrix can describe asynchronous costs that differ by direction of flow; a matrix which describes the quantity of flow between facilities. This matrix describes the quantity in the direction of flow; a matrix which desribes the fixed cost of assigning a facility to a location.

Using these flows and costs, an optimization problem is formulated to determine a solution which minimizes the total cost for positioning facilities at locations. The facilities do not have to be buildings or campuses and the locations do not have to be geographical locations. See Beckmann and and Koopmans (1957) for the original reference.

  • >>> A = np.array([[0, 5, 8, 0, 1],
  • ... [0, 0, 0, 10, 15],
  • ... [0, 0, 0, 13, 18],
  • ... [0, 0, 0, 0, 0.],
  • ... [0, 0, 0, 1, 0.]])
  • >>> B = np.array([[0, 8.54, 6.4, 10, 8.94],
  • ... [8.54, 0, 4.47, 5.39, 6.49],
  • ... [6.4, 4.47, 0, 3.61, 3.0],
  • ... [10, 5.39, 3.61, 0, 2.0],
  • ... [8.94, 6.49, 3.0, 2.0, 0.]])
  • >>> C = np.array([[2, 3, 6, 3, 7],
  • ... [3, 9, 2, 5, 9],
  • ... [2, 6, 4, 1, 2],
  • ... [7, 5, 8, 5, 7],
  • ... [1, 9, 2, 9, 2.]])
  • >>> model = QAPModel(A, B, C)
  • >>> model.penalty_multiplier = 105.625
  • >>> Q = model.qubo.Q
  • >>> np.sum(Q)
  • 24318.03

eqc_models.graph

class eqc_models.graph.MaxCutModel(G: Graph)[source]

Bases: TwoPartitionModel

decode(solution: ndarray) ndarray[source]
Override the default decoding to use a the max cut metric to determine a solution
property J: ndarray
property C: ndarray
property H
Hamiltonian operator of unknown type
partition(solution)[source]
Return a dictionary with the partition number of each node
getCutSize(partition)[source]
costFunction()[source]
Parameters:
None
Returns:
  • C: linear operator (vector array of coefficients) for cost function
  • J: quadratic operator (N by N matrix array of coefficients ) for cost function

eqc_models.sequence

class eqc_models.sequence.MTZTSPModel(D: Dict[Tuple[int, int], float])[source]

Bases: InequalitiesMixin, TSPModel

Using the Miller Tucker Zemlin (1960) formulation of TSP, create a model instance that contains variables for node order (to eliminate subtours) and edge choices.

  • >>> D = {(1, 2): 1, (2, 1): 1, (1, 3): 2, (3, 1): 2, (2, 3): 3, (3, 2): 3}
  • >>> model = MTZTSPModel(D)
  • >>> model.penalty_multiplier = 10
  • >>> model.distance(1, 2)
  • 1
  • >>> model.distance(3, 2)
  • 3
  • >>> solution = np.array([1, 0, 0, 1, 1, 0, 1, 2, 3, 4, 4, 2, 5])
  • >>> model.cost(solution)
  • 6
  • >>> lhs, rhs = model.constraints
  • >>> (lhs@solution - rhs == 0).all()
  • True
  • >>> poly = model.polynomial
  • >>> poly.evaluate(solution) + model.alpha * model.offset
  • 6.0
  • >>> infeasible = np.array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 2, 5])
  • >>> Pl, Pq = -2 * rhs.T@lhs, lhs.T@lhs
  • >>> Pl.T@solution + solution.T@Pq@solution + model.offset
  • 0.0
  • >>> Pl.T@infeasible + infeasible.T@Pq@infeasible + model.offset > 0
  • True
  • >>> poly.evaluate(infeasible) + model.alpha * model.offset > 0
  • True
  • >>> infeasible = 1 - np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
  • >>> poly.evaluate(infeasible) + model.alpha * model.offset > 6
  • True
  • >>> val1 = poly.evaluate(infeasible) + model.alpha * model.offset
  • >>> model.penalty_multiplier *= 2
  • >>> poly2 = model.polynomial
  • >>> val2 = poly2.evaluate(infeasible) + model.alpha * model.offset
  • >>> val1 < val2
  • True
property constraints: Tuple[ndarray, ndarray]

Two constraints for every node, one for the edge chosen to enter and another for the edge chosen to leave. One constraint for every edge not leading to the depot.

Returns: 2-Tuple of numpy arrays, one as lefthand side and the other
for the righthand side. $Ax = b$
Type:
Build the constraints
cost(solution: ndarray) float[source]

Solution cost is the sum of all D values where (i,j) is chosen

:paramsolution: np.ndarray - An array of of 0,1 values which describe a route
by setting variables representing active edges to 1.

Returns: float

property upper_bound: ndarray
For all route variables, the domain is {0, 1}. The sequence variables can take on values in [0, 1, 2, …, N].

eqc_models.algorithms

class eqc_models.algorithms.PenaltyMultiplierAlgorithm(model: ConstraintModel, solver: ModelSolver)[source]

Bases: Algorithm

Parameters:
  • model (ConstraintModel) – Instance of a model to search out a penalty multiplier value, must be constrained model.
  • solver (ModelSolver subclass) – Instance of a solver class to use to run the algorithm.

Properties

upper_boundfloat
Upper bound value for the objective function, this need not be a least upper bound, but the tighter the value, the more efficient the search
solutionsList
The solutions found during the algorithm run
alphasList
The values of multiplier found at each algorithm iteration
penaltiesList
The values for penalties found at each algorithm iteration. A penalty of 0 indicates algorithm termination.
dynamic_rangeList
The values for the dynamic range of the unconstrained problem formulation, which is useful for identifying difficulty in representation of the problem on the analog device.

The penalty multiplier search algorithm uses an infeasible solution to select the next value for the penalty multiplier. The algorithm depends upon good solutions and only guarantees termination when the solution found for a given multiplier is optimal. For this reason, the implementation will terminate when no progress is made, thus making it a heuristic. Providing an exact solver for the solver instance will guarantee that the algorithm is correct and the penalty mulktiplier found is the minimal multiplier capable of enforcing the condition that an unconstrained objective value for a feasible solution is less than an unconstrained objective value for an infeasible solution.

This example uses the quadratic assignment problem and the known multiplier to test the implementation of the algorithm.

  • >>> from eqc_models.solvers.qciclient import Dirac3CloudSolver
  • >>> from eqc_models.assignment.qap import QAPModel
  • >>> A = np.array([[0, 5, 8, 0, 1],
  • ... [0, 0, 0, 10, 15],
  • ... [0, 0, 0, 13, 18],
  • ... [0, 0, 0, 0, 0.],
  • ... [0, 0, 0, 1, 0.]])
  • >>> B = np.array([[0, 8.54, 6.4, 10, 8.94],
  • ... [8.54, 0, 4.47, 5.39, 6.49],
  • ... [6.4, 4.47, 0, 3.61, 3.0],
  • ... [10, 5.39, 3.61, 0, 2.0],
  • ... [8.94, 6.49, 3.0, 2.0, 0.]])
  • >>> C = np.array([[2, 3, 6, 3, 7],
  • ... [3, 9, 2, 5, 9],
  • ... [2, 6, 4, 1, 2],
  • ... [7, 5, 8, 5, 7],
  • ... [1, 9, 2, 9, 2.]])
  • >>> model = QAPModel(A, B, C)
  • >>> solver = Dirac3CloudSolver() # must be configured with environment variables
  • >>> algo = PenaltyMultiplierAlgorithm(model, solver)
  • >>> algo.upper_bound = 330.64
  • >>> algo.run(relaxation_schedule=2, mean_photon_number=0.15, normalized_loss_rate=4, num_samples=5)
  • 2... RUNNING... COMPLETED...
  • >>> algo.alphas[-1]
  • 106.25
  • >>> algo.penalties[-1]
  • 0.0
property upper_bound: float
run(initial_alpha: float | None = None, initial_solution: array | None = None, **kwargs)[source]
Start with a guess at alpha, iterate until alpha is sufficiently large

eqc_models.utilities

eqc_models.utilities.evaluate_polynomial(terms, solution)[source]
eqc_models.utilities.read_coefficient_file(filename)[source]
eqc_models.utilities.read_index_file(filename)[source]
eqc_models.utilities.read_config_file(filename)[source]
eqc_models.utilities.convert_hamiltonian_to_polynomial(A, B, C, D, num_vars)[source]

Converts a hamiltonian of up to fourth order to a polynomial.

D_{ijkl} x_i x_j x_k x_l + C_{ijk} x_i x_j x_k + B_{ij} x_i x_j + A_i x_i

Input:

A: First order hamiltonian. B: Second order hamiltonian. C: Third order hamiltonian. D: Fourth order hamiltonian. num_vars: Number of variables.

Output:

polynomial_indices, polynomila_coefs: Indices and coefficients of polynomial that respresents the hamiltonian.

eqc_models.utilities.qplib

Read the file format from QPLIB (https://doi.org/10.1007/s12532-018-0147-4)

The “problem type” is a string of three characters.

The first character indicates the type of objective function used. It must be one of the following:

L a linear objective function D a convex quadratic objective function whose Hessian is a diagonal matrix C a convex quadratic objective function Q a quadratic objective function whose Hessian may be indefinite

The second character indicates the types of variables that are present. It must be one of the following:

C all the variables are continuous B all the variables are binary (0-1) M the variables are a mix of continuous and binary I all the variables are integer G the variables are a mix of continuous, binary and integer

The third character indicates the type of the (most extreme) constraint function used; other constraints may be of a lesser type. It must be one of the following:

N there are no constraints B some of the variables lie between lower and upper bounds (box constraints) L the constraint functions are linear D the constraint functions are convex quadratics with diagonal Hessians C the constraint functions are convex quadratics Q the constraint functions are quadratics whose Hessians may be indefinite

Thus for continuous problems, we would have

LCL a linear program LCC or LCQ a linear program with quadratic constraints CCB or QCB a bound-constrained quadratic program CCL or QCL a quadratic program CCC or CCQ or a quadratic program with quadratic constraints QCC or QCQ

class eqc_models.utilities.qplib.QBBModel(C: ndarray, J: ndarray)

Bases: QuadraticModel

QBB - Quadratic objective, binary variable type, unconstrained

This model type is the same as a QUBO model, but the linear portion is specified separately, instead of in the diagonal.

:param : :type : C: np.ndarray - linear portion of the objective :param : :type : J: np.ndarray - quadratic portion of the objective

class eqc_models.utilities.qplib.QGLModel(C_obj: array, J_obj: array, lhs: array, rhs: array)

Bases: ConstrainedQuadraticModel

QGL - Quadratic objective, General variable type, Linear constraints Handles QCL, QIL, QBL, QML problems

:param : :type : C: np.ndarray - linear portion of the objective :param : :type : J: np.ndarray - quadratic portion of the objective :param : :type : A: np.ndarray - left hand side of the linear constraints :param : :type : b: np.ndarray - right hand side of the linear constraints

eqc_models.utilities.qplib.file_to_model(fp: ~typing.TextIO, DTYPE=<class 'numpy.float32'>) QGLModel
eqc_models.utilities.qplib.file_to_polynomial(fp: ~typing.TextIO, DTYPE=<class 'numpy.float32'>, penalty_multiplier=1) Tuple[List, List]

Create a pair of lists describing a polynomial that represents the file contained in the qplib-formatted file descriptor fp. Sets a guess for the sum constraint when constructing the model, but it has no effect on the polynomial file output.

Parameters :fp: File descriptor for qplib-formatted file :DTYPE: Default numeric datatype for non-integer numeric values

Returns
coefficients:, :indices:
eqc_models.utilities.qplib.process_file(fp, DTYPE=<class 'numpy.float32'>)
Read the file line by line, saving the parts objective (C, Q) and constraints (A, b)
eqc_models.utilities.qplib.read_line(fp: TextIO) Dict