FoundryProductsTechnologyCompanyInvestor relationsResource libraryNews
Contact us
Resource library
    Resource library home
    Developer resources
      Entropy quantum optimization
        Dirac Quick Start
        Dirac-3 Developer Beginner Guide
        Multibody formulation
        QUBO formulation
        QLCBO formulation
        QBoost formulation
        qci-client software package
        eqc-direct software package
        eqc-models software package
          Getting Started
          Basic Usage
          eqc_models
          Dependencies
      Quantum random number generation
      Reservoir computing
    Applications
    Lessons
    Research and publications
    Support

Couldn’t find what you are looking for? Reach out to technical support.

Contact support
Privacy PolicyCookie PolicyTerms of UseForward Looking StatementsAccessibility Statement
Terms and Conditions of SaleEnd User License Agreement

© 2018-2026 Quantum Computing Inc.

Download

Default

Source code for eqc_models.base.operators

  • """
  • QUBO and Polynomial operators are used in EQC Models to pass the appropriate
  • format to the solver. All models must output one or both of QUBO or Polynomial
  • types. Each Solver checks for the appropriate type. If a model does not provide
  • the type, then it must raise OperatorNotAvailableError.
  • >>> Q = np.array([[1, 2], [0, 1]])
  • >>> qubo = QUBO(Q)
  • >>> (qubo.Q == np.array([[1, 1], [1, 1]])).all()
  • True
  • >>> coefficients = [1, 1, 2]
  • >>> indices = [(1, 1), (2, 2), (1, 2)]
  • >>> poly = Polynomial(coefficients, indices)
  • >>> indices = [(1, 1), (2, 2), (2, 1)]
  • >>> poly = Polynomial(coefficients, indices)
  • Traceback (most recent call last):
  • File "<stdin>", line 1, in <module>
  • ValueError: Input data to polynomial is not correct: index order must be monotonic
  • >>> s = np.array([1, 1])
  • >>> (poly.evaluate(s)==qubo.evaluate(s)).all()
  • True
  • """
  • from typing import List
  • from dataclasses import dataclass
  • import numpy as np
  • # polyeval module is a Cython module useful for speeding up computation
  • # of an operator's value at a solution. If the Cython module is not
  • # available, the poly_eval variable will be set to None, triggering the
  • # use of a pure Python method for evaluation
  • try:
  • from .polyeval import poly_eval
  • except ImportError:
  • poly_eval = None
  • class OperatorNotAvailableError(Exception):
  • """ General error to raise when an operator type is not implemented """
  • [docs]
  • @dataclass
  • class QUBO:
  • """
  • 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: np.ndarray
  • def __post_init__(self):
  • Q2 = (self.Q + self.Q.T) / 2
  • self.Q = Q2
  • [docs]
  • def evaluate(self, solution : np.ndarray):
  • return solution.T@self.Q@solution
  • [docs]
  • @dataclass
  • class Polynomial:
  • """
  • 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):
  • - :math:`x_1^2`: :code:`(0, 0, 1, 1)`
  • - :math:`x_1 x_2 x_3`: :code:`(0, 1, 2, 3)`
  • - :math:`x_2^2 x_3^2`: :code:`(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 :code:`(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
  • def __post_init__(self):
  • issues = set()
  • degree_count = None
  • if len(self.coefficients)!=len(self.indices):
  • issues.add("coefficients and indices must be the same length")
  • # ensure indices are not numpy
  • self.indices = [[int(val) for val in index] for index in self.indices]
  • for i in range(len(self.coefficients)):
  • if degree_count is None:
  • degree_count = len(self.indices[i])
  • elif len(self.indices[i])!=degree_count:
  • issues.add("term rank is not consistent")
  • for j in range(1, degree_count):
  • if self.indices[i][j] < self.indices[i][j-1]:
  • issues.add("index order must be monotonic")
  • try:
  • coeff = float(self.coefficients[i])
  • except TypeError:
  • issues.add("coefficient data types must be coercible to float type")
  • except ValueError:
  • issues.add("coefficient values must be coercible to float values")
  • if len(issues) > 0:
  • msg = "Input data to polynomial is not correct: "
  • msg += "; ".join([issue for issue in issues])
  • raise ValueError(msg)
  • [docs]
  • def pure_evaluate(self, solution : np.ndarray) -> np.ndarray:
  • """
  • Evaluation in pure python
  • Parameters
  • ----------
  • solution : np.array
  • Solution to evaluate, is optionally 2-d, which results in multiple evaluations
  • Returns
  • -------
  • np.array
  • """
  • if len(solution.shape) == 1:
  • solution = solution.reshape((1, solution.shape[0]))
  • objective = [0 for k in range(solution.shape[0])]
  • for k in range(solution.shape[0]):
  • for i in range(len(self.coefficients)):
  • term = self.coefficients[i]
  • for j in self.indices[i]:
  • if j > 0:
  • term *= solution[k, j-1]
  • objective[k] += term
  • return objective
  • [docs]
  • def evaluate(self, solution: np.ndarray):
  • """
  • 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.
  • Returns
  • -------
  • 1-d array of values which match the coerced dtype of the inputs.
  • """
  • if poly_eval is None:
  • return self.pure_evaluate(solution)
  • else:
  • return poly_eval(np.array(self.coefficients, dtype=np.float64),
  • np.array(self.indices, dtype=np.int64), solution)
Previous page
Next page

Content

  • Source code for eqc_models.base.operators