FoundryProductsTechnologyCompanyInvestor relationsResource libraryNews
Contact us
Resource library
    Resource library home
    Developer resources
    Applications
    Lessons
    Research and publications
    Support
      Software packages
        eqc-direct software package
        qci-client software package
        uqrng-direct software package
        emucore-direct software package
        eqc-models software package
          Getting Started
          Basic Usage
          eqc_models
          Dependencies
      Spec sheets
      User guides

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.polynomial

  • # (C) Quantum Computing Inc., 2024.
  • from typing import Tuple, Union, List
  • import numpy as np
  • from eqc_models.base.base import EqcModel
  • from eqc_models.base.operators import Polynomial
  • from eqc_models.base.constraints import ConstraintsMixIn
  • class PolynomialMixin:
  • """This class provides an instance method and property that
  • manage polynomial models.
  • """
  • @property
  • def H(self) -> Tuple[np.ndarray, np.ndarray]:
  • """
  • Hamiltonian specified as a polynomial : 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].
  • """
  • return self.coefficients, self.indices
  • @H.setter
  • def H(self, value : Tuple[np.ndarray, np.ndarray]):
  • """ Set H directly as coefficients, indices """
  • coefficients, indices = value
  • self.coefficients = coefficients
  • self.indices = indices
  • @property
  • def sparse(self) -> Tuple[np.ndarray, np.ndarray]:
  • return self.H
  • def evaluate(self, solution : np.ndarray) -> float:
  • """
  • Evaluate polynomial at solution
  • :solution: 1-d numpy array with the same length as the number of variables
  • returns a floating point value
  • """
  • value = self.polynomial.evaluate(np.array(solution))
  • return value
  • @property
  • def dynamic_range(self) -> float:
  • """
  • Dynamic range is a measure in decibels of the ratio of the largest
  • magnitude coefficient in a problem to the smallest non-zero magnitude
  • coefficient.
  • The possible range of values are all greater than or equal to 0. The
  • calculation is performed by finding the lowest non-zero of the
  • absolute value of all the coefficients, which could be empty. In that
  • case, the dynamic range is undefined, so an exception is raised. If
  • it is positive, then the maximum of the absolute values is divided
  • by the lowest. The base-10 logarithm of that value is taken and mul-
  • tiplied by 10. This is the dynamic range.
  • Returns
  • ----------
  • float
  • """
  • H = self.H
  • coefficients = np.array(H[0])
  • try:
  • lowest = np.min(np.abs(coefficients[coefficients!=0]))
  • except IndexError:
  • raise ValueError("Dynamic range of a Hamiltonian of all 0 is undefined")
  • highest = np.max(np.abs(coefficients))
  • return 10*np.log10(highest / lowest)
  • [docs]
  • class PolynomialModel(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 # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
  • (array([1, 2, 3]), array([[0, 0, 1],
  • [0, 1, 1],
  • [1, 1, 1]]))
  • """
  • def __init__(self, coefficients : Union[List, np.ndarray], indices : Union[List, np.ndarray]) -> None:
  • self.coefficients = coefficients
  • self.indices = indices
  • @property
  • def polynomial(self) -> Polynomial:
  • coefficients, indices = self.H
  • return Polynomial(coefficients=coefficients, indices=indices)
  • [docs]
  • class ConstrainedPolynomialModel(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.
  • """
  • def __init__(self, coefficients : Union[List, np.ndarray], indices : Union[List, np.ndarray],
  • lhs : np.ndarray, rhs: np.ndarray):
  • self.coefficients = np.array(coefficients)
  • self.indices = np.array(indices).astype(np.int64)
  • self.max_order = self.indices.shape[1]
  • self.lhs = lhs
  • self.rhs = rhs
  • @property
  • def penalties(self):
  • """
  • Penalty terms specified as a polynomial: 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.
  • """
  • indices = []
  • coefficients = []
  • def lpad(index):
  • missing = self.max_order - len(index)
  • if missing > 0:
  • index = (0,) * missing + index
  • assert len(index) > 0
  • return np.array(index)
  • Pl, Pq = super(ConstrainedPolynomialModel, self).penalties
  • for i in range(Pl.shape[0]):
  • if Pl[i] != 0:
  • indices.append(lpad((0, i+1)))
  • coefficients.append(Pl[i])
  • for j in range(i, Pq.shape[1]):
  • if Pq[i, j] != 0:
  • indices.append(lpad((i+1, j+1)))
  • value = Pq[i, j]
  • if i!=j:
  • value += Pq[j, i]
  • coefficients.append(value)
  • return coefficients, indices
  • [docs]
  • def evaluatePenalties(self, solution : np.ndarray, include_offset=False) -> float:
  • """
  • 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 : 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
  • """
  • # get the coefficients and indices for the penalty polynomial
  • # use the Polynomial operator to evaluate the solution
  • coefficients, indices = self.penalties
  • solution = np.array(solution, dtype=np.float64)
  • polynomial = Polynomial(coefficients, indices)
  • if include_offset:
  • value = self.offset
  • else:
  • value = 0
  • value += polynomial.evaluate(solution)
  • return value
  • [docs]
  • def evaluateObjective(self, solution : np.ndarray) -> float:
  • """
  • 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 : float
  • """
  • coefficients = self.coefficients
  • indices = self.indices
  • solution = np.array(solution, dtype=np.float64)
  • polynomial = Polynomial(coefficients, indices)
  • return polynomial.evaluate(solution)
  • @property
  • def H(self) -> Tuple[np.ndarray, np.ndarray]:
  • """ Provide the sparse format for the Hamiltonian """
  • p_coeff, p_indices = self.penalties
  • coefficients, indices = self.coefficients, self.indices
  • terms = {}
  • alpha = self.alpha
  • for index, coeff in zip(p_indices, p_coeff):
  • index = tuple(index)
  • assert len(index) > 1
  • if index not in terms:
  • terms[index] = alpha * coeff
  • else:
  • terms[index] += alpha * coeff
  • for index, coeff in zip(indices, coefficients):
  • index = tuple(index)
  • if index not in terms:
  • terms[index] = coeff
  • else:
  • terms[index] += coeff
  • indices = [index for index in terms.keys()]
  • indices.sort()
  • coefficients = [terms[tuple(index)] for index in indices]
  • return coefficients, indices
Previous page

Content

  • Source code for eqc_models.base.polynomial