PyQUBO Documentation

repository·master·Indexed 42 days ago

https://github.com/recruit-communications/pyqubo

A Python library with a C++ backend for creating QUBO (Quadratic Unconstrained Binary Optimization) and Ising models using flexible mathematical expressions. It integrates with the D-Wave Ocean SDK and provides tools for defining Hamiltonians with Binary and Spin variables, handling integer encoding, and managing logical constraints.

Tokens
12.1K
Snippets
46
Records
63
Agent score
51%

What's inside PyQUBO

  1. Create custom penalty terms with WithPenalty

    master

    To define complex penalty terms that are automatically added to a Hamiltonian (similar to how OneHotEncInteger works), inherit from WithPenalty. The constructor should call super().__init__(hamiltonian, penalty, label), where penalty is the expression to be added to the total Hamiltonian.

    from pyqubo import WithPenalty, Binary
    
    class CustomPenalty(WithPenalty):
        def __init__(self, hamiltonian, label, strength):
            # Define the penalty term: strength * (h - 1)^2
            penalty = strength * (hamiltonian - 1)**2
            super().__init__(hamiltonian, penalty, label)
    
    a, b = Binary("a"), Binary("b")
    p = CustomPenalty(a + b, label="penalty", strength=2.0)
    model = (p + 1).compile()
    qubo, offset = model.to_qubo()
  2. Use logical gates in PyQUBO

    master

    PyQUBO provides logical gate classes to construct complex Boolean expressions within a Quadratic Unconstrained Binary Optimization (QUBO) model. You can use these gates to combine variables or other logical expressions.

    Supported gates include:

    • Not: Negates the input expression.
    • And: Performs a logical AND operation on the inputs.
    • Or: Performs a logical OR operation on the inputs.
    • Xor: Performs a logical XOR operation on the inputs.
  3. Use Placeholders to update values without re-compiling

    master

    A Placeholder(label) allows you to inject values into an expression at the time of QUBO generation rather than at compilation time. This is highly efficient for tasks like gradually increasing the strength of a constraint, as you can call .to_qubo(feed_dict={'label': value}) multiple times without the overhead of .compile().

    from pyqubo import Binary, Placeholder
    
    x, y, a = Binary('x'), Binary('y'), Placeholder('a')
    exp = a*x*y + 2.0*x
    model = exp.compile()
    
    # Update 'a' dynamically via feed_dict
    qubo1, offset1 = model.to_qubo(feed_dict={'a': 3.0})
    qubo2, offset2 = model.to_qubo(feed_dict={'a': 5.0})
  4. How the Model class works in PyQUBO

    master

    A Model object represents a binary quadratic optimization problem. You do not create it directly; instead, you obtain it by calling .compile() on an Express object (such as a Hamiltonian constructed from Binary, Constraint, or SubH objects).

    The Model serves two primary purposes:

    1. Generating mathematical representations: It can convert your expression into QUBO, Ising models, or D-Wave dimod.BinaryQuadraticModel (BQM) formats.
    2. Interpreting solver results: It provides methods to decode raw samples from solvers back into the original variable structure, including energy calculations and constraint satisfaction checks.
    from pyqubo import Binary
    
    # Create an expression
    H = Binary("a") + 2*Binary("b")
    
    # Compile to get a Model object
    model = H.compile()
  5. Use Placeholders to avoid re-compiling

    master

    If your Hamiltonian contains parameters that change (e.g., penalty strengths for constraints), use Placeholder. This allows you to update parameter values via the feed_dict argument in .to_qubo() or .to_ising() without the expensive overhead of re-compiling the model.

    from pyqubo import Binary, Placeholder
    
    a, b = Binary('a'), Binary('b')
    M = Placeholder('M')
    H = 2*a + b + M*(a+b-1)**2
    model = H.compile()
    
    # Get QUBO with M=5.0
    qubo_5 = model.to_qubo(feed_dict={'M': 5.0})
    
    # Get QUBO with M=6.0 without re-compiling
    qubo_6 = model.to_qubo(feed_dict={'M': 6.0})
  6. Compare integer encoding methods in PyQUBO

    master

    PyQUBO provides several ways to encode an integer value in the range $[0, n]$ using binary variables. Choosing the right encoding depends on your constraints on the number of variables used and the maximum coefficient magnitude allowed in the resulting QUBO.

    EncodingValueConstraint#varsMax abs. coeff of value
    UnaryEncInteger$\sum_{i=1}^{n}x_{i}$No constraint$n$$1$
    LogEncInteger$\sum_{i=1}^{d}2^i x_{i}$No constraint$\lceil\log_{2}n\rceil(=d)$$2^d$
    OneHotEncInteger$\sum_{i=0}^{n}ix_{i}$$(\sum_{i=0}^{n}x_{i}-1)^2$$n+1$$n$
    OrderEncInteger$\sum_{i=1}^{n}x_{i}$$\sum_{i=1}^{n-1}x_{i+1}(1-x_{i})$$n$$1$
  7. Extend expressions with UserDefinedExpress

    master

    You can create custom logical or mathematical operators by inheriting from UserDefinedExpress. You must call super().__init__(expression) in your constructor, where expression is the underlying PyQUBO expression representing your custom logic.

    from pyqubo import UserDefinedExpress, Binary
    
    class LogicalAnd(UserDefinedExpress):
        def __init__(self, bit_a, bit_b):
            # Define the logic (AND is multiplication for binary variables)
            express = bit_a * bit_b
            super().__init__(express)
    
    a, b = Binary('a'), Binary('b')
    logical_and = LogicalAnd(a, b)
  8. Use the Array class for QUBO modeling

    master
    The Array class is the fundamental structure in PyQUBO for representing collections of variables (qubits) and performing algebraic operations on them. It allows you to define variables that can be used to construct Quadratic Unconstrained Binary Optimization (QUBO) problems through arithmetic and matrix operations.
  9. How to construct QUBO and Ising models

    master

    PyQUBO allows you to convert combinatorial optimization problems into QUBO (Quadratic Unconstrained Binary Optimization) or Ising model formats.

    QUBO uses binary variables $x_i \in {0, 1}$. Ising model uses spin variables $s_i \in {-1, 1}$.

    To generate these models, follow these three steps:

    1. Define the Hamiltonian using Spin or Binary variables.
    2. Compile the Hamiltonian using the .compile() method to get a Model object.
    3. Convert to coefficients using either .to_qubo() or .to_ising().
    from pyqubo import Spin
    s1, s2, s3, s4 = Spin("s1"), Spin("s2"), Spin("s3"), Spin("s4")
    H = (4*s1 + 2*s2 + 7*s3 + s4)**2
    
    model = H.compile()
    
    # For QUBO
    qubo, offset = model.to_qubo()
    
    # For Ising
    linear, quadratic, offset = model.to_ising()
  10. Use logical constraints in PyQUBO

    master

    PyQUBO provides logical constraint classes to build complex Boolean expressions within a QUBO or Ising model. These constraints allow you to combine existing constraints or variables using standard logical operators: NotConst (NOT), AndConst (AND), OrConst (OR), and XorConst (XOR).

    These classes are part of the pyqubo module.