Source code for QHyper.constraint

"""This module contains the Constraint class which is used to represent a, well, 
constraint. It is used in the QUBO formulation to define the left and right
hand sides of the constraints, and the operator.

.. rubric:: Main class

.. autosummary::
    :toctree: generated

    Constraint  -- implementation of the constraint.

.. rubric:: Enum Classes

.. autoclass:: MethodsForInequalities


.. rubric:: Functions

.. autofunction:: get_number_of_constraints

"""

import uuid
from enum import Enum

from QHyper.polynomial import Polynomial, PolynomialType


[docs] class MethodsForInequalities(Enum): """Enum class with different methods for handling inequalities. There are two available methods for handling inequalities: .. list-table:: * - SLACKS_LOG_2 - UNBALANCED_PENALIZATION * - the method uses slack variables in number of log2(n) - the method uses unbalanced penalization """ SLACKS_LOG_2 = 0 UNBALANCED_PENALIZATION = 1
SLACKS_LOG_2 = MethodsForInequalities.SLACKS_LOG_2 UNBALANCED_PENALIZATION = MethodsForInequalities.UNBALANCED_PENALIZATION class Operator(Enum): """Enum class with different operators. """ EQ = "==" GE = ">=" LE = "<="
[docs] class Constraint: """ A class representing the constraint. Attributes ---------- lhs : PolynomialType The left-hand side of the constraint. rhs : PolynomialType, default 0 The right-hand side of the constraint. operator : Operator, default Operator.EQ The operator of the constraint. It can be ==, >=, <=. method_for_inequalities : MethodsForInequalities, optional The method to be used for inequalities. It can be SLACKS_LOG_2 or UNBALANCED_PENALIZATION. It is required when the operator is not ==. label : str, optional The label of the constraint. If not provided, it will be set to a random string. group : int, default -1 The group of the constraint. It is used to group constraints together. Example use is assigning same weight to the constraints with the same group when creating qubo. """ def __init__( self, lhs: PolynomialType, rhs: PolynomialType = 0, operator: Operator = Operator.EQ, method_for_inequalities: MethodsForInequalities | None = None, label: str = "", group: int = -1, ) -> None: self.lhs = lhs if isinstance(lhs, Polynomial) else Polynomial(lhs) self.rhs = rhs if isinstance(rhs, Polynomial) else Polynomial(rhs) self.operator: Operator = operator if operator != Operator.EQ and method_for_inequalities is None: raise Exception( "Method for inequalities must be " "provided when operator is not ==" ) self.method_for_inequalities = method_for_inequalities self._set_label(label) self.group = group def _set_label(self, label: str) -> None: self.label = label or f"s{uuid.uuid4().hex}" def __repr__(self) -> str: return f"{self.lhs} {self.operator.value} {self.rhs}" def get_variables(self) -> set[str]: return self.lhs.get_variables() | self.rhs.get_variables()
[docs] def get_number_of_constraints(constraints: list[Constraint]) -> int: """Returns the number of unique groups in the constraints list. """ counter = 0 visited = set() for c in constraints: if c.group == -1: counter += 1 elif c.group not in visited: visited.add(c.group) counter += 1 return counter