def circuit17(params, wires): """Circuit template #17 in 1905.10876 Args: params (array): An array of shapes (2N + floor(N/2) + floor((N-1)/2), ). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape( params, target_shape=(2 * size + floor(size / 2) + floor((size - 1) / 2), ), msg= f"params must be of shape {(2*size + floor(size/2) + floor((size-1)/2),)}." ) # Define the circuit AngleEmbedding(params[:size], wires, rotation='X') AngleEmbedding(params[size:2 * size], wires, rotation='Z') pattern = [[i + 1, i] for i in range(0, len(wires) - 1, 2)] qml.broadcast(unitary=qml.CRX, pattern=pattern, wires=wires, parameters=params[2 * size:2 * size + floor(size / 2)]) pattern = [[i + 1, i] for i in range(1, len(wires) - 1, 2)] qml.broadcast(unitary=qml.CRX, pattern=pattern, wires=wires, parameters=params[2 * size + floor(size / 2):])
def circuit12(params, wires): """Circuit template #12 in 1905.10876 Args: params (array): An array of shapes (4N-4,). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape(params, target_shape=(4 * size - 4, ), msg=f"params must be of shape {(4 * size - 4, )}.") # Define the circuit AngleEmbedding(params[:size], wires, rotation='Y') AngleEmbedding(params[size:2 * size], wires, rotation='Z') pattern = [[i + 1, i] for i in range(0, len(wires) - 1, 2)] qml.broadcast(unitary=qml.CZ, pattern=pattern, wires=wires) AngleEmbedding(params[2 * size:3 * size - 2], wires=wires[1:-1], rotation='Y') AngleEmbedding(params[3 * size - 2:4 * size - 4], wires=wires[1:-1], rotation='Z') pattern = [[i + 1, i] for i in range(1, len(wires) - 1, 2)] qml.broadcast(unitary=qml.CZ, pattern=pattern, wires=wires)
def circuit(params): """Parametrized circuit.""" for layer in range(n): qml.broadcast(qml.RX, pattern="single", wires=self.all_wires, parameters=params[layer]) for _layer in range(n): qml.broadcast(qml.CNOT, pattern="double", wires=self.all_wires) return [bu.expval(qml.PauliZ(w)) for w in self.all_wires]
def circuit15(params, wires): """Circuit template #15 in 1905.10876 Args: params (array): An array of shapes (2N, ). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape(params, target_shape=(2 * size, ), msg=f"params must be of shape {(2*size,)}.") # Define the circuit AngleEmbedding(params[:size], wires, rotation='Y') pattern = [[i, (i + 1) % len(wires)] for i in reversed(range(len(wires)))] qml.broadcast(unitary=qml.CNOT, pattern=pattern, wires=wires) AngleEmbedding(params[size:], wires, rotation='Y') pattern = [[(i - 1) % len(wires), (i - 2) % len(wires)] for i in range(len(wires))] qml.broadcast(unitary=qml.CNOT, pattern=pattern, wires=wires)
def mera(params, wires): # Reformat the parameters list into a list of lists. # Each two-qubit gate should receive a list of parameters. # Apply the two qubit gates into the pattern of a tree. num_gates = len(pattern) if fix_layers: gate_size = len(params) // (2 * depth - 1 ) #determine 2qubit gate size parameters = [] parameters.append(params[:gate_size]) for layer in range(1, depth): gates_per_layer = 2**layer #isometry for i in range(gates_per_layer): parameters.append( params[gate_size * (2 * layer - 1):gate_size * 2 * layer]) #unitary for i in range(gates_per_layer - int(not periodic)): parameters.append(params[gate_size * 2 * layer:gate_size * (2 * layer + 1)]) else: parameters = params gate_size = len(params) // num_gates # determine 2qubit gate size parameters = np.reshape(parameters, [num_gates, gate_size]) qml.broadcast(unitary=two_qubit_gate, pattern=pattern, wires=wires, parameters=parameters,\ kwargs=None)
def ttn(params, wires): # Reformat the parameters list into a list of lists. # Each two-qubit gate should receive a list of parameters. parameters = [] if fix_layers: num_params_per_layer = len(params) // depth for layer in range(depth): num_gates_in_layer = 2**layer params_gate = [ params[j] for j in range(layer * num_params_per_layer, (layer + 1) * num_params_per_layer) ] parameters.extend([params_gate] * num_gates_in_layer) else: num_params_per_gate = len(params) // len(pattern) parameters = [[ params[i * num_params_per_gate + j] for j in range(num_params_per_gate) ] for i in range(len(pattern))] # Apply the two qubit gates into the pattern of a tree. qml.broadcast(two_qubit_gate, wires, pattern, parameters=parameters, kwargs=None)
def circuit06(params, wires): """Circuit template #06 in 1905.10876 Args: params (array): An array of shapes (N^2 + 3N, 1). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape(params, target_shape=(size * (size + 3), ), msg=f"params must be of shape {(size * (size + 3), )}.") # Define the circuit AngleEmbedding(params[:size], wires, rotation='X') AngleEmbedding(params[size:2 * size], wires, rotation='Z') idx_start = 2 * size for cnt, controlled in enumerate(reversed(range(len(wires)))): pattern = [[controlled, j] for j in reversed(range(len(wires))) if j != controlled] qml.broadcast(unitary=qml.CRX, pattern=pattern, wires=wires, parameters=params[idx_start:idx_start + (size - 1)]) idx_start += size - 1 AngleEmbedding(params[idx_start:idx_start + size], wires, rotation='X') AngleEmbedding(params[idx_start + size:idx_start + 2 * size], wires, rotation='Z')
def layer(self, features, weights): for k in range(self.n_qubits): upload = weights[k * 6:k * 6 + 3] + weights[k * 6 + 3:(k + 1) * 6] * features[k * 3:(k + 1) * 3] qml.Rot(*upload, wires=self.wires[k]) qml.broadcast(unitary=qml.CNOT, wires=self.wires, pattern='ring')
def random_embed(x, wires, n_layers=1): """random enbedding circuit Args: weights: trainable weights x: input, len(x) is <= len(wires) wires: list of wires on which the feature map acts n_layers: number of repetitions of the first layer (Default value = 1) Returns: """ n_wires = len(wires) weights = pars_random(x, n_wires, n_layers) n_weights_needed = n_layers * n_wires if len(weights) != n_weights_needed: raise ValueError("Feat map needs {} weights, got {}.".format( n_weights_needed, len(weights))) gate_set = [qml.RX, qml.RY, qml.RZ] for l in range(n_layers): i = 0 while i < len(x): gate = np.random.choice(gate_set) gate(x[i], wires=wires[i]) i = i + 1 for i in range(n_wires): gate = np.random.choice(gate_set) gate(weights[l * n_wires + i - n_wires], wires=wires[i]) qml.broadcast(qml.CNOT, wires=range(n_wires), pattern="ring")
def hea(params, wires): n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits #n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits:layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. #extra_params = params[-n_extra_rots:, :] #extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] #qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def layer(self, features, weights): for k in range(self.n_qubits): qml.RY(weights[k] * features[k], wires=self.wires[k]) qml.broadcast(qml.CNOT, wires=self.wires, pattern='ring') for k in range(self.n_qubits): qml.RX(weights[self.n_qubits + k], wires=self.wires[k])
def initialize_fields(angles, wires): qml.broadcast(qml.RX, wires=wires, pattern='single', parameters=np.array(angles)[:, 0]) qml.broadcast(qml.RZ, wires=wires, pattern='single', parameters=np.array(angles)[:, 1])
def evaluate_to_ancillary(params, wires): unitary_params = np.split(params, len(wires) - 1) pattern = [[i, wires[-1]] for i in wires[:-1]] if floq: for i, used_wires in enumerate(pattern): CRX(params[i], used_wires) else: qml.broadcast(unitary=qml.CRX, pattern=pattern, wires=wires, parameters=unitary_params)
def layer(x, params, wires, i0=0, inc=1): """Building block of the embedding Ansatz""" i = i0 for j, wire in enumerate(wires): qml.Hadamard(wires=[wire]) qml.RZ(x[i % len(x)], wires=[wire]) i += inc qml.RY(params[0, j], wires=[wire]) qml.broadcast(unitary=qml.CRZ, pattern="ring", wires=wires, parameters=params[1])
def unitary_layer(all_wires, params, k=2): """ Layers of unitaries The first and last qubits are ancilla qubits Input: all_wires: list of wires to be used params: parameters for unitaries k: every kth qubit, we apply an aribtrary unitary gate to k+1 qubit """ qml.broadcast(ArbitraryUnitary, wires=all_wires, pattern="double", parameters=params)
def circuit(params): qml.RX(params[0], wires=0) qml.RY(params[1], wires=1) qml.RZ(params[2], wires=2) qml.broadcast(qml.CNOT, wires=[0, 1, 2], pattern="ring") qml.RX(params[3], wires=0) qml.RY(params[4], wires=1) qml.RZ(params[5], wires=2) qml.broadcast(qml.CNOT, wires=[0, 1, 2], pattern="ring") return qml.expval(qml.PauliY(0) @ qml.PauliZ(2))
def layer(self, features, weights): upload = features if self.angle_scaling: upload = weights[0:self.n_scaling_weights] * upload qml.broadcast(unitary=qml.RX, wires=self.feature_wires, pattern='single', parameters=upload) qml.broadcast(unitary=qml.Hadamard, wires=self.latent_wires, pattern='single') if self.n_total_qubits >= 2: qml.broadcast( unitary=qml.MultiRZ, wires=self.wires, pattern='ring', parameters=weights[self. n_scaling_weights:self.n_scaling_weights + self.n_entangling_weights]) qml.broadcast(unitary=qml.RY, wires=self.wires, pattern='single', parameters=weights[self.n_scaling_weights + self.n_entangling_weights:])
def quantum_circuit(rotation_params, coupling_params, sample=None): # Prepares the initial basis state corresponding to the sample qml.templates.BasisStatePreparation(sample, wires=range(nr_qubits)) # Prepares the variational ansatz for the circuit for i in range(0, depth): single_rotation(rotation_params[i], range(nr_qubits)) qml.broadcast(unitary=qml.CRX, pattern="ring", wires=range(nr_qubits), parameters=coupling_params[i]) # Calculates the expectation value of the Hamiltonian with respect to the prepared states return qml.expval(qml.Hermitian(ham_matrix, wires=range(nr_qubits)))
def circuit(params1, params2): """Parametrized circuit with nearest-neighbour gates.""" for layer in range(n): qml.broadcast( qml.RX, pattern="single", wires=self.all_wires, parameters=params1[layer], ) qml.broadcast( qml.CRY, pattern="chain", wires=self.all_wires, parameters=params2[layer], ) return bu.expval(qml.PauliZ(0))
def variational_circuit(params): """A layered variational circuit. The first layer comprises of x, y, and z rotations on wires 0, 1, and 2, respectively. The second layer is a ring of CNOT gates. The final layer comprises of x, y, and z rotations on wires 0, 1, and 2, respectively. """ # DO NOT MODIFY anything in this code block qml.RX(params[0], wires=0) qml.RY(params[1], wires=1) qml.RZ(params[2], wires=2) qml.broadcast(qml.CNOT, wires=[0, 1, 2], pattern="ring") qml.RX(params[3], wires=0) qml.RY(params[4], wires=1) qml.RZ(params[5], wires=2) qml.broadcast(qml.CNOT, wires=[0, 1, 2], pattern="ring")
def circuit04(params, wires): """Circuit template #04 in 1905.10876 Args: params (array): An array of shapes (3N-1, 1). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape(params, target_shape=(3 * size - 1,), msg=f"params must be of shape {(3 * size - 1,)}.") # Define the circuit AngleEmbedding(params[:size], wires, rotation='X') AngleEmbedding(params[size:2 * size], wires, rotation='Z') pattern = [[i + 1, i] for i in reversed(range(len(wires) - 1))] qml.broadcast(unitary=qml.CRX, pattern=pattern, wires=wires, parameters=params[2 * size:])
def variational_ansatz(params, wires, *, state_n): """ Args: params (np.ndarray): An array of floating-point numbers with size (n, 3), where n is the number of parameter sets required (this is determined by the problem Hamiltonian). wires (qml.Wires): The device wires this circuit will run on. """ n_qubits = len(wires) n_rotations = len(params) state = np.repeat([0], n_qubits) state[0:state_n] = 1 qml.BasisState(state, wires=wires) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits: layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.RY, wires, pattern="single", parameters=layer_params[:, 0]) qml.broadcast(qml.RZ, wires, pattern="single", parameters=layer_params[:, 1]) qml.broadcast(qml.CNOT, wires, pattern="ring") if n_extra_rots > 0: # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots: -1] qml.broadcast(qml.RY, extra_wires, pattern="single", parameters=extra_params[:, 0]) qml.broadcast(qml.RZ, extra_wires, pattern="single", parameters=extra_params[:, 1]) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def random_embed(weights, x, wires, n_layers=1): """ random enbedding circuit :param weights: trainable weights :param x: input, len(x) is <= len(wires) :param wires: list of wires on which the feature map acts :param n_layers: number of repetitions of the first layer """ n_wires = len(wires) n_weights_needed = n_layers * n_wires gate_set = [qml.RX, qml.RY, qml.RZ] for l in range(n_layers): i = 0 while i < len(x): gate = np.random.choice(gate_set) gate(x[i], wires=wires[i]) i = i + 1 for i in range(n_wires): gate = np.random.choice(gate_set) gate(weights[l * n_wires + i - n_wires], wires=wires[i]) qml.broadcast(qml.CNOT, wires=range(n_wires), pattern="ring")
def circuit09(params, wires): """Circuit template #09 in 1905.10876 Args: params (array): An array of shapes (N,). wires (Iterable): Wires that the template acts on. """ # Input Checks wires, size = Wires(wires), len(wires) check_shape(params, target_shape=(size,), msg=f"params must be of shape {(size,)}.") # Define the circuit qml.broadcast(unitary=qml.Hadamard, pattern="single", wires=wires) pattern = [[i + 1, i] for i in reversed(range(len(wires) - 1))] qml.broadcast(unitary=qml.CZ, pattern=pattern, wires=wires) AngleEmbedding(params, wires, rotation='X')
def classifier(params, wires): # qml.RZ(params, wires=wires[0]) # qml.RY(params, wires=wires[0]) n_qubits = len(wires) n_rotations = len(params) n_layers = n_rotations // n_qubits if n_rotations % n_qubits != 0: raise Exception("Last layer is incomplete, not all qubits are rotated") # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits:layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) if n_qubits > 1: qml.broadcast(qml.CNOT, wires, pattern="ring")
def variational_ansatz2(params, wires): rot = params[0] params = params[1:] n_qubits = len(wires) n_rotations = len(params) qml.PauliX(wires=0) qml.PauliX(wires=1) qml.RY(rot[2], wires=2) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits:layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") extra_params = params[-n_extra_rots:, :] extra_wires = wires[:n_qubits - 1 - n_extra_rots:-1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: qml.Rot(*params[0], wires=wires[0])
def variational_ansatz(params, wires): """ This is a custom ansatz. It applies alternating layers of rotations and CNOTs. Args: params (np.ndarray): An array of floating-point numbers with size (n, 3), where n is the number of parameter sets required (this is determined by the problem Hamiltonian). wires (qml.Wires): The device wires this circuit will run on. """ n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits : layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def variational_ansatz(params, wires): """ DO NOT MODIFY anything in this function! It is used to judge your solution. This is ansatz is used to help with the problem structure. It applies alternating layers of rotations and CNOTs. Don't worry about the contents of this function for now—you'll be designing your own ansatze in a later problem. Args: params (np.ndarray): An array of floating-point numbers with size (n, 3), where n is the number of parameter sets required (this is determined by the problem Hamiltonian). wires (qml.Wires): The device wires this circuit will run on. """ n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits # Alternating layers of unitary rotations on every qubit followed by a # ring cascade of CNOTs. for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits : layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") # There may be "extra" parameter sets required for which it's not necessarily # to perform another full alternating cycle. Apply these to the qubits as needed. extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: # For 1-qubit case, just a single rotation to the qubit qml.Rot(*params[0], wires=wires[0])
def generator(w): qml.broadcast(unitary=qml.RY, pattern='single', wires=wires, parameters=w[0:32]) for k in range(1, 4): qml.broadcast(unitary=qml.RY, pattern='single', wires=wires, parameters=w[(32 * k):(32 * (k + 1))]) qml.broadcast(unitary=qml.CZ, pattern='ring', wires=wires)
def get_state(params, wires=w2): n_qubits = len(wires) n_rotations = len(params) if n_rotations > 1: n_layers = n_rotations // n_qubits n_extra_rots = n_rotations - n_layers * n_qubits for layer_idx in range(n_layers): layer_params = params[layer_idx * n_qubits : layer_idx * n_qubits + n_qubits, :] qml.broadcast(qml.Rot, wires, pattern="single", parameters=layer_params) qml.broadcast(qml.CNOT, wires, pattern="ring") extra_params = params[-n_extra_rots:, :] extra_wires = wires[: n_qubits - 1 - n_extra_rots : -1] qml.broadcast(qml.Rot, extra_wires, pattern="single", parameters=extra_params) else: qml.Rot(*params[0], wires=wires[0]) return qml.state()