diff --git a/quantum.py b/quantum.py index 1c34477..07ef9cc 100644 --- a/quantum.py +++ b/quantum.py @@ -8,22 +8,22 @@ import sympy.physics.quantum pi = sympy.pi -#E = sympy.E I = sympy.I exp = sympy.exp sqrt = sympy.sqrt -log = sympy.log -eye = sympy.eye -zeros = sympy.zeros -#ones = sympy.ones abs = sympy.Abs -kron = sympy.physics.quantum.TensorProduct +#log = sympy.log real = sympy.re imag = sympy.im +eye = sympy.eye +zeros = sympy.zeros +#ones = sympy.ones +kron = sympy.physics.quantum.TensorProduct Matrix = sympy.Matrix start_time = time.time() +last_time = start_time def process_memory(): process = psutil.Process(os.getpid()) @@ -45,25 +45,38 @@ def __init__(self, num_qubits): self.num_qubits = num_qubits self.state = zeros(2**num_qubits, 1) - self.state[0] = 1.0 # Initialize to |0> + self.state[0] = 1 # Initialize to |0> - def apply_gate(self, gate, target_qubit=None, control_qubits=None): + def apply_gate(self, gate, target_qubits=None, control_qubits=None): + if target_qubits is None: + raise ValueError("Target qubit must be specified for uncontrolled gate.") + if isinstance(target_qubits, int): + target_qubits = [target_qubits] + target_qubits = sorted(target_qubits) + a = [0] * self.num_qubits + for q in target_qubits: + a[q] = 1 + #print(target_qubits, a, control_qubits) #print("gate", gate) - if control_qubits is None: + #if control_qubits is None or control_qubits == []: # Uncontrolled gate - if target_qubit is None: - raise ValueError("Target qubit must be specified for uncontrolled gate.") #if isinstance(target_qubits, int): # target_qubits = [target_qubits] #target_qubits = sorted(target_qubits) - gate_matrix = kron(eye(int(2**(self.num_qubits - target_qubit - 1))), kron(gate, eye(2**target_qubit))) - else: + gate_matrix = eye(1) + for i in range(self.num_qubits): + if a[i]: + gate_matrix = kron(gate, gate_matrix) + else: + gate_matrix = kron(eye(2), gate_matrix) + #gate_matrix_b = kron(eye(int(2**(self.num_qubits - target_qubits[0] - 1))), kron(gate, eye(2**target_qubits[0]))) + #print(gate_matrix) + #print(gate_matrix_b) + if control_qubits != None and control_qubits != []: # Controlled gate - if target_qubit is None or control_qubits is None: - raise ValueError("Both target and control qubits must be specified for controlled gates.") if isinstance(control_qubits, int): control_qubits = [control_qubits] - gate_matrix = kron(eye(int(2**(self.num_qubits - target_qubit - 1))), kron(gate, eye(2**target_qubit))) + #gate_matrix = kron(eye(int(2**(self.num_qubits - target_qubits[0] - 1))), kron(gate, eye(2**target_qubits[0]))) #print_gate("init gate_matrix", gate_matrix) controlled_gate = zeros(2**self.num_qubits, 2**self.num_qubits) for i in range(2**(self.num_qubits)): @@ -76,6 +89,7 @@ #print_gate("controlled_gate", controlled_gate) #print_gate("gate_matrix", gate_matrix) self.state = gate_matrix @ self.state + def measure(self): probabilities = abs(self.state).applyfunc(lambda x: x ** 2) probabilities = np.array(probabilities, dtype=np.float64).flatten() @@ -85,6 +99,7 @@ self.state[outcome] = 1.0 #print(self.state) return bin(outcome)[2:].zfill(self.num_qubits) + def measure_qubit(self, target_qubit): num_states = len(self.state) probabilities = abs(self.state)**2 @@ -114,6 +129,7 @@ self.state /= normalization_factor return outcome + def list_states(self, percentages = True): num_states = len(self.state) states_with_probabilities = {} @@ -129,6 +145,7 @@ probability = abs(probability)**2 states_with_probabilities[binary_state] = probability return states_with_probabilities + def probabilities(self, percentages = True): num_states = len(self.state) if percentages: @@ -227,6 +244,7 @@ return parsed_instructions def quantum_interpreter(quantum_code, qreg=None): + global last_time parsed_instructions = quantum_parse(quantum_code) if qreg is None: num_qubits = int(parsed_instructions[0][1]) @@ -234,18 +252,30 @@ print(f"initialized qreg with {num_qubits} qubits") parsed_instructions = parsed_instructions[1:] for instruction in parsed_instructions: - #print(f"{time.time() - start_time:8.3f}s:", *instruction) - cmd = re.findall(r'(C*)(\d*)(\w+)', instruction[0])[0] + instruction[0] = instruction[0].upper() + print(f"{time.time() - start_time:8.3f}s:", *instruction) + cmd = re.findall(r'(C*)(\d*)([A-Za-z_]+)(\d*)', instruction[0]) + if cmd == []: + cmd = ('', '', '', '') + else: + cmd = cmd[0] if cmd[2] in GATES.keys(): control_qubits = [] + target_qubits = [] if cmd[1] != '': num_control_qubits = int(cmd[1]) else: num_control_qubits = len(cmd[0]) for q in range(num_control_qubits): control_qubits.append(int(instruction[q + 1])) - target_qubit = int(instruction[num_control_qubits + 1]) - qreg.apply_gate(GATES[cmd[2]], target_qubit, control_qubits) + if cmd[3] != '': + num_target_qubits = int(cmd[3]) + else: + num_target_qubits = 1 + for q in range(num_target_qubits): + target_qubits.append(int(instruction[q + num_control_qubits + 1])) + #target_qubit = int(instruction[num_control_qubits + 1]) + qreg.apply_gate(GATES[cmd[2]], target_qubits, control_qubits) elif instruction[0] == 'Q': filename = instruction[1].lower() if not os.path.isfile(filename): @@ -291,9 +321,18 @@ result = qreg.measure_qubit(int(instruction[1])) print("measured state: |{}>".format(result)) elif instruction[0] == 'TIME': - print("time: ", time.time() - start_time) + this_time = time.time() + print("time: ", this_time - last_time) + last_time = this_time elif instruction[0] == 'PRINT': print(*instruction[1:]) + elif instruction[0] == 'CONSOLE': + while True: + print(f' Q{qreg.num_qubits}> ', end='') + instruction = input().upper() + if instruction.startswith('BREAK'): + break + qreg = quantum_interpreter(f'QREG 8\n{instruction}', qreg) elif os.path.isfile(instruction[0].lower() + ".q"): with open(instruction[0].lower() + ".q") as file: code = file.read() @@ -303,16 +342,11 @@ print("No command", instruction[0]) return qreg -filename = sys.argv[1] -if os.path.isfile(filename): - with open(filename) as file: - quantum_code = file.read() -else: - quantum_code = """ -QREG 2 -H 0 -CX 0 1 -MEASURE -""" +quantum_code = "QREG 4\nCONSOLE" +if len(sys.argv) > 1: + filename = sys.argv[1] + if os.path.isfile(filename): + with open(filename) as file: + quantum_code = file.read() result = quantum_interpreter(quantum_code)