コード例 #1
0
ファイル: test_native.py プロジェクト: BQSKit/bqskit
def test_get_unitary(gate: Gate) -> None:
    size = gate.get_size()
    circ = Circ(size, radixes=gate.get_radixes())
    circ.append_gate(gate, list(range(size)))
    num_params = circ.get_num_params()
    x = np.random.random((num_params, ))
    circuit = Circuit(circ)
    assert np.allclose(circ.get_unitary(x).get_numpy(), circuit.get_unitary(x))
コード例 #2
0
ファイル: test_properties.py プロジェクト: BQSKit/bqskit
    def test_value(self, gate: Gate) -> None:
        circuit = Circuit(gate.get_size(), gate.get_radixes())
        assert circuit.is_differentiable()

        circuit.append_gate(gate, list(range(gate.get_size())))
        if isinstance(gate, DifferentiableUnitary):
            assert circuit.is_differentiable()
        else:
            assert not circuit.is_differentiable()
コード例 #3
0
ファイル: test_native.py プロジェクト: BQSKit/bqskit
def test_get_grad(gate: Gate) -> None:
    size = gate.get_size()
    circ = Circ(size, radixes=gate.get_radixes())
    circ.append_gate(gate, list(range(size)))
    num_params = circ.get_num_params()
    x = np.random.random((num_params, ))
    circuit = Circuit(circ)
    grad_python = circ.get_grad(x)
    grad_rust = circuit.get_grad(x)
    for py, rs in zip(grad_python, grad_rust):
        assert np.allclose(py, rs)
コード例 #4
0
    def __init__(self, gate: Gate, frozen_params: dict[int, float]) -> None:
        """
        Create a gate which fixes some of the parameters it takes.

        Args:
            gate (Gate): The Gate to fix the parameters of.
            frozen_params (dict[int, float]): A dictionary mapping parameters
                indices to the fixed value they should be.

        Raises:
            ValueError: If any of the `frozen_params` indices are greater
                than the number of parameters `gate` takes or less than 0
                or if the total amount of `frozen_params` is larger than
                the number of parameters `gate` takes.
        """
        if not isinstance(gate, Gate):
            raise TypeError('Expected gate, got %s.' % type(gate))
        if not isinstance(frozen_params, dict):
            raise TypeError(
                'Expected dict for frozen_params, '
                'got %s.' % type(frozen_params), )
        if not len(frozen_params) <= gate.get_num_params():
            raise ValueError(
                'Too many fixed parameters specified, expected at most'
                ' %d, got %d' % (gate.get_num_params(), len(frozen_params)), )
        keys = list(frozen_params.keys())
        values = list(frozen_params.values())
        if not all(isinstance(p, int) for p in keys):
            fail_idx = [isinstance(p, int) for p in keys].index(False)
            raise TypeError(
                'Expected frozen_params keys to be int, got %s.' %
                type(keys[fail_idx]), )
        if not all(isinstance(p, (int, float)) for p in values):
            typechecks = [isinstance(p, (int, float)) for p in values]
            fail_idx = typechecks.index(False)
            raise TypeError(
                'Expected frozen_params values to be float, got %s.' %
                type(values[fail_idx]), )
        if not all(0 <= p < gate.get_num_params() for p in keys):
            fail_idx = [0 <= p < gate.get_num_params()
                        for p in keys].index(False)
            raise ValueError(
                'Expected parameter index to be non-negative integer'
                ' < %d, got %d.' % (gate.get_num_params(), keys[fail_idx]), )

        self.gate = gate
        self.num_params = gate.get_num_params() - len(frozen_params)
        self.size = gate.get_size()
        self.radixes = gate.get_radixes()
        self.frozen_params = frozen_params
        self.unfixed_param_idxs = [
            i for i in range(gate.get_num_params())
            if i not in self.frozen_params.keys()
        ]
コード例 #5
0
ファイル: test_native.py プロジェクト: BQSKit/bqskit
def test_get_unitary_and_grad(gate: Gate) -> None:
    size = gate.get_size()
    circ = Circ(size, radixes=gate.get_radixes())
    circ.append_gate(gate, list(range(size)))
    num_params = circ.get_num_params()
    x = np.random.random((num_params, ))
    circuit = Circuit(circ)
    utry_python, grad_python = circ.get_unitary_and_grad(x)
    utry_rust, grad_rust = circuit.get_unitary_and_grad(x)
    assert np.allclose(utry_python.get_numpy(), utry_rust)
    for i, (py, rs) in enumerate(zip(grad_python, grad_rust)):
        assert np.allclose(py, rs)
コード例 #6
0
 def test_location_mismatch_2(self, qutrit_gate: Gate) -> None:
     circuit = Circuit(qutrit_gate.get_size(), qutrit_gate.get_radixes())
     location = list(range(qutrit_gate.get_size()))
     location[-1] += 1
     params = [0] * qutrit_gate.get_num_params()
     op = Operation(qutrit_gate, location, params)
     try:
         circuit.check_valid_operation(op)
     except ValueError:
         return
     except BaseException:
         assert False, 'Unexpected Exception'
     assert False
コード例 #7
0
ファイル: tagged.py プロジェクト: BQSKit/bqskit
    def __init__(self, gate: Gate, tag: Any) -> None:
        """Associate `tag` with `gate`."""

        if not isinstance(gate, Gate):
            raise TypeError('Expected gate object, got %s' % type(gate))

        self.gate = gate
        self.tag = tag
        self.name = 'Tagged(%s:%s)' % (gate.get_name(), tag)
        self.num_params = gate.get_num_params()
        self.size = gate.get_size()
        self.radixes = gate.get_radixes()

        # If input is a constant gate, we can cache the unitary.
        if self.num_params == 0:
            self.utry = gate.get_unitary()
コード例 #8
0
ファイル: operation.py プロジェクト: BQSKit/bqskit
    def __init__(
        self, gate: Gate,
        location: CircuitLocationLike,
        params: Sequence[float] = [],
    ) -> None:
        """
        Operation Constructor.
s
        Args:
            gate (Gate): The cell's gate.

            location (CircuitLocationLike):  The set of qudits this gate
                affects.

            params (Sequence[float]): The parameters for the gate.

        Raises:
            ValueError: If `gate`'s size doesn't match `location`'s length.

            ValueError: If `gate`'s size doesn't match `params`'s length.
        """

        if not isinstance(gate, Gate):
            raise TypeError('Expected gate, got %s.' % type(gate))

        if not CircuitLocation.is_location(location):
            raise TypeError('Invalid location.')

        location = CircuitLocation(location)

        if len(location) != gate.get_size():
            raise ValueError('Gate and location size mismatch.')

        self.num_params = gate.get_num_params()
        self.radixes = gate.get_radixes()
        self.size = gate.get_size()

        if len(params) == 0 and self.get_num_params() != 0:
            params = [0.0] * self.get_num_params()

        self.check_parameters(params)

        self._gate = gate
        self._location = location
        self._params = list(params)
コード例 #9
0
ファイル: controlled.py プロジェクト: BQSKit/bqskit
    def __init__(
        self,
        gate: Gate,
        num_controls: int = 1,
        radixes: Sequence[int] = [],
    ) -> None:
        """Construct a ControlledGate."""

        if not isinstance(gate, Gate):
            raise TypeError('Expected gate object, got %s.' % type(gate))

        if not is_integer(num_controls):
            raise TypeError(
                'Expected integer for num_controls, got %s.'
                % type(num_controls),
            )

        if num_controls < 1:
            raise ValueError(
                'Expected positive integer for num_controls, got %d.'
                % num_controls,
            )

        if len(radixes) != 0 and not is_valid_radixes(radixes, num_controls):
            raise TypeError('Invalid radixes.')

        self.gate = gate
        self.size = gate.get_size() + num_controls
        self.num_controls = num_controls
        self.radixes = tuple(radixes or [2] * self.size) + gate.get_radixes()
        self.name = '%d-Controlled(%s)' % (num_controls, gate.get_name())
        self.num_params = gate.get_num_params()

        self.Ic = np.identity(2 ** num_controls)  # TODO: General radix support
        self.It = np.identity(gate.get_dim())
        self.OneProj = np.zeros(self.Ic.shape)
        self.OneProj[-1, -1] = 1
        self.left = np.kron((self.Ic - self.OneProj), self.It)

        # If input is a constant gate, we can cache the unitary.
        if self.num_params == 0:
            U = self.gate.get_unitary()
            right = np.kron(self.OneProj, U)
            self.utry = UnitaryMatrix(self.left + right, self.get_radixes())
コード例 #10
0
ファイル: vlg.py プロジェクト: BQSKit/bqskit
    def __init__(
        self,
        gate: Gate,
        locations: Sequence[CircuitLocationLike],
        radixes: Sequence[int],
    ) -> None:
        """
        Create a gate that has parameterized location.

        Args:
            gate (Gate): The gate to parameterize location for.

            locations (Sequence[CircuitLocationLike]): A sequence of locations.
                Each location represents a valid placement for gate.

            radixes (Sequence[int]): The number of orthogonal
                states for each qudit. Defaults to qubits.

        Raises:
            ValueError: If there are not enough locations or the locations
                are incorrectly sized.

        Notes:
            The locations are calculated in their own space and are not
            relative to a circuit. This means you should consider the
            VariableLocationGate as its own circuit when deciding the
            locations. For example, if you want to multiplex the (2, 3)
            and (3, 5) placements of a CNOT on a 6-qubit circuit, then
            you would give the VariableLocationGate the (0, 1) and (1, 2)
            locations and place the VariableLocationGate on qubits
            (2, 3, 5) on the circuit.
        """
        if not isinstance(gate, Gate):
            raise TypeError('Expected gate object, got %s' % type(gate))

        if not all(CircuitLocation.is_location(l) for l in locations):
            raise TypeError('Expected a sequence of valid locations.')

        locations = [CircuitLocation(l) for l in locations]

        if not all(len(l) == gate.get_size() for l in locations):
            raise ValueError('Invalid sized location.')

        if len(locations) < 1:
            raise ValueError('VLGs require at least 1 locations.')

        self.gate = gate
        self.name = 'VariableLocationGate(%s)' % gate.get_name()
        self.locations = list(locations)

        if radixes is None:
            # Calculate radixes
            radix_map: dict[int,
                            int | None] = {i: None
                                           for i in range(self.size)}
            for l in locations:
                for radix, qudit_index in zip(gate.get_radixes(), l):
                    if radix_map[qudit_index] is None:
                        radix_map[qudit_index] = radix
                    elif radix_map[qudit_index] != radix:
                        raise ValueError(
                            'Gate cannot be applied to all locations'
                            ' due to radix mismatch.', )

            self.radixes = tuple(radix_map.values())
        else:
            for l in locations:
                for radix, qudit_index in zip(gate.get_radixes(), l):
                    if radixes[qudit_index] != radix:
                        raise ValueError(
                            'Gate cannot be applied to all locations'
                            ' due to radix mismatch.', )

            self.radixes = tuple(radixes)

        self.size = len(self.radixes)
        self.num_params = self.gate.get_num_params() + len(locations)

        self.extension_size = self.size - self.gate.get_size()
        # TODO: This needs to changed for radixes
        self.I = np.identity(2**self.extension_size)
        self.perms = np.array([
            PermutationMatrix.from_qubit_location(self.size, l)
            for l in self.locations
        ])
コード例 #11
0
 def test_valid_2(self, gate: Gate) -> None:
     circuit = Circuit(gate.get_size() + 2, (2, 2) + gate.get_radixes())
     location = [x + 2 for x in list(range(gate.get_size()))]
     params = [0] * gate.get_num_params()
     circuit.check_valid_operation(Operation(gate, location, params))
コード例 #12
0
 def test_valid_1(self, gate: Gate) -> None:
     circuit = Circuit(gate.get_size(), gate.get_radixes())
     location = list(range(gate.get_size()))
     params = [0] * gate.get_num_params()
     circuit.check_valid_operation(Operation(gate, location, params))
コード例 #13
0
ファイル: test_gate.py プロジェクト: BQSKit/bqskit
 def test_gate_size_matches_radixes(self, gate: Gate) -> None:
     assert len(gate.get_radixes()) == gate.get_size()
コード例 #14
0
ファイル: test_gate.py プロジェクト: BQSKit/bqskit
 def test_get_radixes_qutrit(self, qutrit_gate: Gate) -> None:
     assert all(radix == 3 for radix in qutrit_gate.get_radixes())
コード例 #15
0
ファイル: test_gate.py プロジェクト: BQSKit/bqskit
 def test_get_radixes(self, gate: Gate) -> None:
     assert isinstance(gate.get_radixes(), tuple)
     assert all(isinstance(radix, int) for radix in gate.get_radixes())
     assert all(radix > 0 for radix in gate.get_radixes())
コード例 #16
0
    def __init__(
        self,
        two_qudit_gate: Gate = CNOTGate(),
        single_qudit_gate_1: Gate = U3Gate(),
        single_qudit_gate_2: Gate | None = None,
        initial_layer_gate: Gate | None = None,
    ) -> None:
        """
        Construct a SimpleLayerGenerator.

        Args:
            two_qudit_gate (Gate): A two-qudit gate that starts this
                layer generator's building block. (Default: CNOTGate())

            single_qudit_gate_1 (Gate): A single-qudit gate that follows
                `two_qudit_gate` in the building block. (Default: U3Gate())

            single_qudit_gate_2 (Gate | None): An alternate single-qudit
                gate to be used as the second single-qudit gate in the
                building block. If left as None, defaults to
                `single_qudit_gate_1`. (Default: None)

            initial_layer_gate (Gate | None): An alternate single-qudit
                gate that creates the initial layer. If left as None,
                defaults to `single_qudit_gate_1`. (Default: None)

        Raises:
            ValueError: If `two_qudit_gate`'s size is not 2, or if any
                of the single-qudit gates' size is not 1.

            ValueError: If `single_qudit_gate_1`'s radix does not match
                the radix of `two_qudit_gate`'s first qudit, or if
                `single_qudit_gate_2`'s radix does not match the radix
                of `two_qudit_gate`'s second qudit.
        """

        if not isinstance(two_qudit_gate, Gate):
            raise TypeError(
                'Expected gate for two_qudit_gate, got %s.' %
                type(two_qudit_gate), )

        if two_qudit_gate.get_size() != 2:
            raise ValueError(
                'Expected two-qudit gate'
                ', got a gate that acts on %d qudits.' %
                two_qudit_gate.get_size(), )

        if not isinstance(single_qudit_gate_1, Gate):
            raise TypeError(
                'Expected gate for single_qudit_gate_1, got %s.' %
                type(single_qudit_gate_1), )

        if single_qudit_gate_1.get_size() != 1:
            raise ValueError(
                'Expected single-qudit gate'
                ', got a gate that acts on %d qudits.' %
                single_qudit_gate_1.get_size(), )

        if single_qudit_gate_2 is None:
            single_qudit_gate_2 = single_qudit_gate_1

        if initial_layer_gate is None:
            initial_layer_gate = single_qudit_gate_1

        if not isinstance(single_qudit_gate_2, Gate):
            raise TypeError(
                'Expected gate for single_qudit_gate_2, got %s.' %
                type(single_qudit_gate_2), )

        if single_qudit_gate_2.get_size() != 1:
            raise ValueError(
                'Expected single-qudit gate'
                ', got a gate that acts on %d qudits.' %
                single_qudit_gate_2.get_size(), )

        if not isinstance(initial_layer_gate, Gate):
            raise TypeError(
                'Expected gate for initial_layer_gate, got %s.' %
                type(initial_layer_gate), )

        if initial_layer_gate.get_size() != 1:
            raise ValueError(
                'Expected single-qudit gate'
                ', got a gate that acts on %d qudits.' %
                initial_layer_gate.get_size(), )

        two_radix_1 = two_qudit_gate.get_radixes()[0]
        two_radix_2 = two_qudit_gate.get_radixes()[1]

        if two_radix_1 != single_qudit_gate_1.get_radixes()[0]:
            raise ValueError(
                'Radix mismatch between two_qudit_gate and single_qudit_gate_1'
                ': %d != %d.' %
                (two_radix_1, single_qudit_gate_1.get_radixes()[0]), )

        if two_radix_2 != single_qudit_gate_2.get_radixes()[0]:
            raise ValueError(
                'Radix mismatch between two_qudit_gate and single_qudit_gate_2'
                ': %d != %d.' %
                (two_radix_2, single_qudit_gate_2.get_radixes()[0]), )

        self.two_qudit_gate = two_qudit_gate
        self.single_qudit_gate_1 = single_qudit_gate_1
        self.single_qudit_gate_2 = single_qudit_gate_2
        self.initial_layer_gate = initial_layer_gate