Skip to content

Commit

Permalink
Merge pull request #441 from rawkintrevo/2203
Browse files Browse the repository at this point in the history
MAHOUT-2203 Add Cirq backend
  • Loading branch information
andrewmusselman authored Mar 27, 2024
2 parents a540bde + 613c16d commit ee35d03
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 55 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ name = "qumat"
version = "0.0.1"
description = "A library for composing quantum machine learning."
authors = ["rawkintrevo"]
license = "MIT"
license = "ASFv2"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.8"
qiskit = "^0.45.1"
qiskit-aer = "^0.13.2"
cirq = "^1.3.0"


[build-system]
Expand Down
72 changes: 72 additions & 0 deletions qumat/cirq_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import cirq

def initialize_backend(backend_config):
# Assuming 'simulator_type' specifies the type of simulator in Cirq
simulator_type = backend_config.get('backend_options', {}).get('simulator_type', 'default')
if simulator_type != 'default':
print(f"Simulator type '{simulator_type}' is not supported in Cirq. Ignoring this argument")

return cirq.Simulator()


def create_empty_circuit(num_qubits):
return cirq.Circuit()

def apply_not_gate(circuit, qubit_index):
qubit = cirq.LineQubit(qubit_index)
circuit.append(cirq.X(qubit))

def apply_hadamard_gate(circuit, qubit_index):
qubit = cirq.LineQubit(qubit_index)
circuit.append(cirq.H(qubit))

def apply_cnot_gate(circuit, control_qubit_index, target_qubit_index):
control_qubit = cirq.LineQubit(control_qubit_index)
target_qubit = cirq.LineQubit(target_qubit_index)
circuit.append(cirq.CNOT(control_qubit, target_qubit))

def apply_toffoli_gate(circuit, control_qubit_index1, control_qubit_index2, target_qubit_index):
control_qubit1 = cirq.LineQubit(control_qubit_index1)
control_qubit2 = cirq.LineQubit(control_qubit_index2)
target_qubit = cirq.LineQubit(target_qubit_index)
circuit.append(cirq.CCX(control_qubit1, control_qubit2, target_qubit))

def apply_swap_gate(circuit, qubit_index1, qubit_index2):
qubit1 = cirq.LineQubit(qubit_index1)
qubit2 = cirq.LineQubit(qubit_index2)
circuit.append(cirq.SWAP(qubit1, qubit2))

def apply_pauli_x_gate(circuit, qubit_index):
qubit = cirq.LineQubit(qubit_index)
circuit.append(cirq.X(qubit))

def apply_pauli_y_gate(circuit, qubit_index):
qubit = cirq.LineQubit(qubit_index)
circuit.append(cirq.Y(qubit))

def apply_pauli_z_gate(circuit, qubit_index):
qubit = cirq.LineQubit(qubit_index)
circuit.append(cirq.Z(qubit))

def execute_circuit(circuit, backend, backend_config):
# This is a simplified example. You'll need to adjust this based on how you're handling backend configuration.
simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=backend_config['backend_options'].get('shots', 1))
return result.histogram(key='result')

75 changes: 75 additions & 0 deletions qumat/qiskit_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import qiskit

def initialize_backend(backend_config):
backend_options = backend_config['backend_options']
simulator_type = backend_options['simulator_type']
shots = backend_options['shots']
backend = qiskit.Aer.get_backend(simulator_type)
backend.shots = shots
return backend


def create_empty_circuit(num_qubits):
return qiskit.QuantumCircuit(num_qubits)

def apply_not_gate(circuit, qubit_index):
# Apply a NOT gate (X gate) on the specified qubit
circuit.x(qubit_index)

def apply_hadamard_gate(circuit, qubit_index):
# Apply a Hadamard gate on the specified qubit
circuit.h(qubit_index)

def apply_cnot_gate(circuit, control_qubit_index, target_qubit_index):
# Apply a CNOT gate (controlled-X gate) with the specified control and
# target qubits
circuit.cx(control_qubit_index, target_qubit_index)

def apply_toffoli_gate(circuit, control_qubit_index1,
control_qubit_index2,
target_qubit_index):
# Apply a Toffoli gate (controlled-controlled-X gate) with the
# specified control and target qubits
circuit.ccx(control_qubit_index1,
control_qubit_index2,
target_qubit_index)

def apply_swap_gate(circuit, qubit_index1, qubit_index2):
# Apply a SWAP gate to exchange the states of two qubits
circuit.swap(qubit_index1, qubit_index2)

def apply_pauli_x_gate(circuit, qubit_index):
# Apply a Pauli X gate on the specified qubit
circuit.x(qubit_index)

def apply_pauli_y_gate(circuit, qubit_index):
# Apply a Pauli Y gate on the specified qubit
circuit.y(qubit_index)

def apply_pauli_z_gate(circuit, qubit_index):
# Apply a Pauli Z gate on the specified qubit
circuit.z(qubit_index)

def execute_circuit(circuit, backend, backend_config):
# Transpile and execute the quantum circuit using the chosen backend
transpiled_circuit = circuit.transpile(backend)
job = qiskit.execute(transpiled_circuit, backend,
shots=backend_config['backend_options']['shots'])
result = job.result()
return result.get_counts(transpiled_circuit)
84 changes: 31 additions & 53 deletions qumat/qumat.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,56 @@
import qiskit

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from importlib import import_module

class QuMat:
def __init__(self, backend_config):
# Initialize the quantum computer with the chosen backend configuration
self.backend_config = backend_config
# Initialize the quantum backend (Qiskit, Cirq, Bracket, etc.) based on
# the config
self.backend_name = backend_config['backend_name']
self.backend = self._initialize_backend()
# Initialize an empty quantum circuit
# Dynamically load the backend module based on the user's choice
self.backend_module = import_module(f".{self.backend_name}_backend", package="qumat")
self.backend = self.backend_module.initialize_backend(backend_config)
self.circuit = None

def _initialize_backend(self):

# Add logic to initialize the backend using the backend name
# For example, if using qiskit:
if self.backend_name == 'qiskit_simulator':
backend_options = self.backend_config['backend_options']
simulator_type = backend_options['simulator_type']
shots = backend_options['shots']
backend = qiskit.Aer.get_backend(simulator_type)
backend.shots = shots
return backend
else:
raise NotImplementedError(f"Backend '{self.backend_name}' is not "
f"supported.")

def create_empty_circuit(self, num_qubits):
# Create an empty quantum circuit with the specified number of qubits
self.circuit = qiskit.QuantumCircuit(num_qubits)
self.circuit = self.backend_module.create_empty_circuit(num_qubits)

def apply_not_gate(self, qubit_index):
# Apply a NOT gate (X gate) on the specified qubit
self.circuit.x(qubit_index)
self.backend_module.apply_not_gate(self.circuit, qubit_index)

def apply_hadamard_gate(self, qubit_index):
# Apply a Hadamard gate on the specified qubit
self.circuit.h(qubit_index)
self.backend_module.apply_hadamard_gate(self.circuit, qubit_index)

def apply_cnot_gate(self, control_qubit_index, target_qubit_index):
# Apply a CNOT gate (controlled-X gate) with the specified control and
# target qubits
self.circuit.cx(control_qubit_index, target_qubit_index)
self.backend_module.apply_cnot_gate(self.circuit, control_qubit_index, target_qubit_index)

def apply_toffoli_gate(self, control_qubit_index1,
control_qubit_index2,
target_qubit_index):
# Apply a Toffoli gate (controlled-controlled-X gate) with the
# specified control and target qubits
self.circuit.ccx(control_qubit_index1,
control_qubit_index2,
target_qubit_index)
def apply_toffoli_gate(self, control_qubit_index1, control_qubit_index2, target_qubit_index):
self.backend_module.apply_toffoli_gate(self.circuit, control_qubit_index1, control_qubit_index2, target_qubit_index)

def apply_swap_gate(self, qubit_index1, qubit_index2):
# Apply a SWAP gate to exchange the states of two qubits
self.circuit.swap(qubit_index1, qubit_index2)
self.backend_module.apply_swap_gate(self.circuit, qubit_index1, qubit_index2)

def apply_pauli_x_gate(self, qubit_index):
# Apply a Pauli X gate on the specified qubit
self.circuit.x(qubit_index)
self.backend_module.apply_pauli_x_gate(self.circuit, qubit_index)

def apply_pauli_y_gate(self, qubit_index):
# Apply a Pauli Y gate on the specified qubit
self.circuit.y(qubit_index)
self.backend_module.apply_pauli_y_gate(self.circuit, qubit_index)

def apply_pauli_z_gate(self, qubit_index):
# Apply a Pauli Z gate on the specified qubit
self.circuit.z(qubit_index)
self.backend_module.apply_pauli_z_gate(self.circuit, qubit_index)

def execute_circuit(self):
# Transpile and execute the quantum circuit using the chosen backend
transpiled_circuit = self.circuit.transpile(self.backend)
job = qiskit.execute(transpiled_circuit, self.backend,
shots=self.backend_config['backend_options']['shots'])
result = job.result()
return result.get_counts(transpiled_circuit)
return self.backend_module.execute_circuit(self.circuit, self.backend, self.backend_config)
1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

0 comments on commit ee35d03

Please sign in to comment.