qrisp.qaoa.constrained_mixer_gen#

constrained_mixer_gen(constraint_oracle, winner_state_amount)[source]#

Generates a customized mixer function that leaves arbitrary constraints intact. The constraints are specified via a constraint_oracle function, which is taking a QuantumVariable or QuantumArray and apply a phase \(\phi\) (specified by the keyword argument phase) to the states that are allowed by the constraints.

Additionally the amount of winner states needs to be known. For this the user needs to provide the function winner_state_amount, that returns the number of winner states for a given qubit amount. This number can be an approximation, however faulty values can cause leakage into the state-space that is forbidden by the constraints.

For more details regarding implementation specifics please check the corresponding tutorial.

Parameters:
constraint_oraclefunction

A function of a QuantumVariable or QuantumArray. Also needs to support the keyword argument phase. This function should apply the phase specified by the keyword argument to the allowed states.

winner_state_amountfunction

A function of a QuantumVariable or QuantumArray, that returns the amount of winner states for that QuantumVariable.

Returns:
constrained_mixerfunction

A mixer function that does not leave the allowed space specified by the oracle.

Examples

We create a mixer function that only mixes among the states where the first and the last qubit disagree. In more mathematical terms - they satisfy the following constraint function.

\[f: \mathbb{F}_2^n \rightarrow \mathbb{F}_2, x \rightarrow (x_{n-1} \neq x_0)\]
from qrisp.qaoa import constrained_mixer_gen
from qrisp import QuantumVariable, auto_uncompute, cx, p

@auto_uncompute
def constraint_oracle(qarg, phase):

    predicate = QuantumBool()        

    cx(qarg[0], predicate)
    cx(qarg[-1], predicate)
    p(phase, predicate)

def winner_state_amount(qarg):
    return 2**(len(qarg) - 1)

mixer = constrained_mixer_gen(constraint_oracle, winner_state_amount)

To test the mixer, we create a QuantumVariable:

import numpy as np
beta = np.pi

qv = QuantumVariable(3)
qv[:] = "101"
mixer(qv, beta)
print(qv)
#Yields: {'101': 1.0} 
#Leaves forbidden states invariant

qv = QuantumVariable(3)
qv[:] = "100"
mixer(qv, beta)
print(qv)
#Yields: {'100': 0.25, '110': 0.25, '001': 0.25, '011': 0.25}
#Only mixes among allowed states