Esempio n. 1
0
 def _create_circuit(self, size):
     parameters = pnp.random.uniform(low=-pnp.pi,
                                     high=pnp.pi,
                                     size=(size, size))
     return MaskedCircuit.full_circuit(parameters=parameters,
                                       layers=size,
                                       wires=size)
Esempio n. 2
0
def create_circuit(size: int, layer_size: int = 1):
    if layer_size == 1:
        parameters = pnp.random.uniform(low=-pnp.pi, high=pnp.pi, size=(size, size))
    else:
        parameters = pnp.random.uniform(
            low=-pnp.pi, high=pnp.pi, size=(size, size, layer_size)
        )
    return MaskedCircuit.full_circuit(parameters=parameters, layers=size, wires=size)
Esempio n. 3
0
def basic_variational_circuit(params, rotations, masked_circuit: MaskedCircuit):
    full_parameters = masked_circuit.expanded_parameters(params)
    wires = masked_circuit.wires
    dropout_mask = masked_circuit.full_mask(DropoutMask)
    for wire, _is_masked in enumerate(masked_circuit.mask(Axis.WIRES)):
        qml.RY(np.pi / 4, wires=wire)
    r = -1
    for layer, _is_layer_masked in enumerate(masked_circuit.mask(Axis.LAYERS)):
        for wire, _is_wire_masked in enumerate(masked_circuit.mask(Axis.WIRES)):
            r += 1
            if dropout_mask[layer][wire]:
                continue
            if rotations[r] == 0:
                rotation = qml.RX
            elif rotations[r] == 1:
                rotation = qml.RY
            else:
                rotation = qml.RZ
            rotation(full_parameters[layer][wire], wires=wire)

        for wire in range(0, wires - 1, 2):
            if (
                Axis.ENTANGLING in masked_circuit.masks
                and masked_circuit.mask(Axis.ENTANGLING)[layer, wire]
            ):
                continue
            qml.CZ(wires=[wire, wire + 1])
        for wire in range(1, wires - 1, 2):
            if (
                Axis.ENTANGLING in masked_circuit.masks
                and masked_circuit.mask(Axis.ENTANGLING)[layer, wire]
            ):
                continue
            qml.CZ(wires=[wire, wire + 1])
Esempio n. 4
0
    def test_mask(self):
        """
        The aggregated mask is built dynamically from the registered masks for the
        different axes. The test ensures that the mask covers the whole set of
        parameters.
        """
        size = 3
        # test circuit with all masks
        mc = MaskedCircuit.full_circuit(
            parameters=pnp.random.uniform(low=0, high=1, size=(size, size)),
            layers=size,
            wires=size,
        )
        assert mc.full_mask(DropoutMask).size == size * size

        # test circuit with no masks
        mc = MaskedCircuit(
            parameters=pnp.random.uniform(low=0, high=1, size=(size, size)),
            layers=size,
            wires=size,
        )
        assert mc.full_mask(DropoutMask).size == size * size

        # test circuit containing only layer mask
        mc = MaskedCircuit(
            parameters=pnp.random.uniform(low=0, high=1, size=(size, size)),
            layers=size,
            wires=size,
            masks=[(Axis.LAYERS, DropoutMask)],
        )
        assert mc.full_mask(DropoutMask).size == size * size
Esempio n. 5
0
 def _branch(
     self, masked_circuit: MaskedCircuit
 ) -> Optional[Dict[str, MaskedCircuit]]:
     if not self.perturb or self.dropout is None:
         return None
     branches = {}
     for key in self.dropout:
         branches[key] = MaskedCircuit.execute(masked_circuit, self.dropout[key])
     return branches
Esempio n. 6
0
 def _create_circuit_with_entangling_gates(self, size):
     parameters = pnp.random.uniform(low=-pnp.pi,
                                     high=pnp.pi,
                                     size=(size, size))
     return MaskedCircuit.full_circuit(
         parameters=parameters,
         layers=size,
         wires=size,
         entangling_mask=DropoutMask(shape=(size, size - 1)),
     )
Esempio n. 7
0
 def test_default_value_shrink(self):
     mp = MaskedCircuit.full_circuit(
         parameters=pnp.random.uniform(low=-pnp.pi,
                                       high=pnp.pi,
                                       size=(4, 3, 2)),
         layers=4,
         wires=3,
         default_value=0,
     )
     mp.mask(Axis.LAYERS)[:] = True
     mp.shrink(axis=Axis.LAYERS)
     assert pnp.sum(mp.parameters == 0) == 6
Esempio n. 8
0
 def test_default_value_perturb(self):
     mp = MaskedCircuit.full_circuit(
         parameters=pnp.random.uniform(low=-pnp.pi,
                                       high=pnp.pi,
                                       size=(4, 3, 2)),
         layers=4,
         wires=3,
         default_value=0,
     )
     mp.mask(Axis.PARAMETERS)[:] = True
     mp.perturb(axis=Axis.PARAMETERS, amount=0.5, mode=Mode.INVERT)
     assert pnp.sum(mp.parameters == 0) == round(0.5 * 4 * 3 * 2)
Esempio n. 9
0
 def test_execute(self):
     mp = self._create_circuit(3)
     perturb_operation = {
         "perturb": {
             "amount": 1,
             "axis": Axis.PARAMETERS,
             "mode": Mode.SET,
         }
     }
     # test empty operations
     assert MaskedCircuit.execute(mp, []) == mp
     # test existing method
     MaskedCircuit.execute(mp, [perturb_operation])
     assert pnp.sum(mp.full_mask(DropoutMask)) == 1
     # test existing method with copy
     new_mp = MaskedCircuit.execute(mp, [{
         "clear": {}
     }, {
         "copy": {}
     }, perturb_operation])
     assert mp != new_mp
     assert pnp.sum(new_mp.full_mask(DropoutMask)) == 1
     # test non-existing method
     with pytest.raises(AttributeError):
         MaskedCircuit.execute(mp, [{"non_existent": {"test": 1}}])
Esempio n. 10
0
def variational_circuit(params, masked_circuit: MaskedCircuit = None):
    full_parameters = masked_circuit.expanded_parameters(params)
    for layer, layer_hidden in enumerate(masked_circuit.mask(Axis.LAYERS)):
        if not layer_hidden:
            for wire, wire_hidden in enumerate(masked_circuit.mask(Axis.WIRES)):
                if not wire_hidden:
                    if not masked_circuit.mask(Axis.PARAMETERS)[layer][wire][0]:
                        qml.RX(full_parameters[layer][wire][0], wires=wire)
                    if not masked_circuit.mask(Axis.PARAMETERS)[layer][wire][1]:
                        qml.RY(full_parameters[layer][wire][1], wires=wire)
            for wire in range(0, masked_circuit.mask(Axis.LAYERS).size - 1, 2):
                qml.CZ(wires=[wire, wire + 1])
            for wire in range(1, masked_circuit.mask(Axis.LAYERS).size - 1, 2):
                qml.CZ(wires=[wire, wire + 1])
    return qml.probs(wires=range(len(masked_circuit.mask(Axis.WIRES))))
Esempio n. 11
0
def create_freezable_circuit(size: int, layer_size: int = 1):
    if layer_size == 1:
        parameters = pnp.random.uniform(low=-pnp.pi, high=pnp.pi, size=(size, size))
    else:
        parameters = pnp.random.uniform(
            low=-pnp.pi, high=pnp.pi, size=(size, size, layer_size)
        )
    return MaskedCircuit(
        parameters=parameters,
        layers=size,
        wires=size,
        masks=(
            (axis, mask_type)
            for axis in Axis
            if axis is not Axis.ENTANGLING
            for mask_type in [DropoutMask, FreezeMask]
        ),
    )
Esempio n. 12
0
def init_parameters(
    layers: int,
    current_layers: int,
    wires: int,
    default_value: Optional[float],
    dynamic_parameters: bool = True,
    mask_type: Type[Mask] = DropoutMask,
) -> MaskedCircuit:
    params_uniform = np.random.uniform(low=-np.pi,
                                       high=np.pi,
                                       size=(current_layers, wires))
    params_zero = np.zeros((layers - current_layers, wires))
    params_combined = np.concatenate((params_uniform, params_zero))
    mc = MaskedCircuit.full_circuit(
        parameters=params_combined,
        layers=layers,
        wires=wires,
        default_value=default_value,
        entangling_mask=DropoutMask(shape=(layers, wires - 1)),
        dynamic_parameters=dynamic_parameters,
        mask_type=mask_type,
    )
    mc.mask(Axis.LAYERS, mask_type=mask_type)[current_layers:] = True
    return mc
Esempio n. 13
0
    def step(
        self,
        masked_circuit: MaskedCircuit,
        optimizer,
        objective_fn,
        *args,
        ensemble_steps: int = 0,
    ) -> EnsembleResult:
        """
        The parameter `ensemble_steps` defines the number of training steps that are
        executed for each ensemble branch in addition to one training step
        that is done before the branching.
        """
        # first one trainingstep
        params, _cost, _gradient = optimizer.step_cost_and_grad(
            objective_fn,
            masked_circuit.differentiable_parameters,
            *args,
            masked_circuit=masked_circuit,
        )
        masked_circuit.differentiable_parameters = params

        # then branching
        branches = self._branch(masked_circuit=masked_circuit)
        basic_active_gates = masked_circuit.active().unwrap()
        if branches is None:
            return EnsembleResult(
                branch=masked_circuit,
                branch_name="center",
                active=basic_active_gates,
                cost=objective_fn(
                    masked_circuit.differentiable_parameters,
                    masked_circuit=masked_circuit,
                ).unwrap(),
                gradient=_gradient,
                brutto_steps=1,
                netto_steps=1,
                brutto=basic_active_gates,
                netto=basic_active_gates,
                ensemble=False,
            )
        branch_costs = []
        branch_gradients = []
        for branch in branches.values():
            for _ in range(ensemble_steps):
                params, _cost, _gradient = optimizer.step_cost_and_grad(
                    objective_fn,
                    *args,
                    branch.differentiable_parameters,
                    masked_circuit=branch,
                )
                branch.differentiable_parameters = params
            branch_costs.append(
                objective_fn(branch.differentiable_parameters, masked_circuit=branch)
            )
            branch_gradients.append(_gradient)
        minimum_index = branch_costs.index(min(branch_costs))
        branch_name = list(branches.keys())[minimum_index]
        selected_branch = branches[branch_name]
        # FIXME: as soon as real (in terms of masked) parameters are used,
        #   no mask has to be applied
        #   until then real gradients must be calculated as gradients also
        #   contain values from dropped gates
        return EnsembleResult(
            branch=selected_branch,
            branch_name=branch_name,
            active=selected_branch.active(),
            cost=branch_costs[minimum_index].unwrap(),
            gradient=branch_gradients[minimum_index],
            brutto_steps=1 + len(branches) * ensemble_steps,
            netto_steps=1 + ensemble_steps,
            brutto=(
                basic_active_gates
                + sum(
                    [branch.active() * ensemble_steps for branch in branches.values()]
                )
            ).unwrap(),
            netto=(
                basic_active_gates + selected_branch.active() * ensemble_steps
            ).unwrap(),
            ensemble=True,
        )
Esempio n. 14
0
    def test_init(self):
        mp = self._create_circuit(3)
        assert mp
        assert len(mp.mask(Axis.WIRES)) == 3
        assert len(mp.mask(Axis.LAYERS)) == 3
        assert mp.mask(Axis.PARAMETERS).shape == (3, 3)

        size = 3
        with pytest.raises(AssertionError):
            MaskedCircuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size - 1,
                wires=size,
            )
        with pytest.raises(AssertionError):
            MaskedCircuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size + 1,
                wires=size,
            )
        with pytest.raises(AssertionError):
            MaskedCircuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size,
                wires=size - 1,
            )
        with pytest.raises(AssertionError):
            MaskedCircuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size,
                wires=size + 1,
            )
        with pytest.raises(AssertionError):
            MaskedCircuit.full_circuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size,
                wires=size,
                entangling_mask=DropoutMask(shape=(size + 1, size)),
            )
        with pytest.raises(NotImplementedError):
            MaskedCircuit(
                parameters=pnp.random.uniform(low=0, high=1,
                                              size=(size, size)),
                layers=size,
                wires=size,
                masks=[(Axis.ENTANGLING, DropoutMask)],
            )
        mc = MaskedCircuit.full_circuit(
            parameters=pnp.random.uniform(low=0, high=1, size=(size, size)),
            layers=size,
            wires=size,
            wire_mask=DropoutMask(shape=(size, ),
                                  mask=pnp.ones((size, ), dtype=bool)),
        )
        assert pnp.array_equal(mc.mask(Axis.WIRES),
                               pnp.ones((size, ), dtype=bool))