├── .gitattributes ├── 9781484265215.jpg ├── Chapter_3 ├── listing3_1 │ ├── listing_3.1.py │ └── listing_3.1_output.txt ├── listing3_10 │ ├── listing_3.10.py │ └── listing_3.10_output.txt ├── listing3_11 │ ├── listing_3.11.py │ └── listing_3.11_output.txt ├── listing3_12 │ ├── listing_3.12.py │ └── listing_3.12_output.txt ├── listing3_2 │ ├── listing_3.2.py │ └── listing_3.2_output.txt ├── listing3_3 │ ├── listing_3.3.py │ └── listing_3.3_output.txt ├── listing3_4 │ ├── listing_3.4.py │ └── listing_3.4_output.txt ├── listing3_5 │ ├── listing_3.5.py │ └── listing_3.5_output.txt ├── listing3_6 │ ├── listing_3.6.py │ └── listing_3.6_output.txt ├── listing3_7 │ ├── listing_3.7.py │ └── listing_3.7_output.txt ├── listing3_8 │ ├── listing_3.8.py │ └── listing_3.8_output.txt └── listing3_9 │ ├── listing_3.9.py │ └── listing_3.9_output.txt ├── Chapter_4 ├── listing4_1 │ ├── listing_4.1_output.txt │ └── quantum_fourier_transform.py ├── listing4_2 │ ├── listing_4.2_output.txt │ └── quantum_phase_estimation.py ├── listing4_3 │ ├── listing_4.3_output.txt │ └── period_finding.py └── listing4_4 │ ├── factoring.py │ └── listing_4.4_output.txt ├── Chapter_5 ├── listing5_1 │ ├── EigenRotation.py │ ├── EigenValueInversion.py │ ├── Eigendiv.py │ ├── HHL.py │ ├── QuantumPhaseEstimation.py │ ├── hamiltonian_simulator.py │ └── listing_5.1_output.txt ├── listing5_2 │ ├── listing_5.2_output.txt │ └── swap_test.py ├── listing5_3 │ ├── listing_5.3_output.txt │ └── quantum_eucledian.py ├── listing5_4 │ ├── Clusters.png │ └── QuantumKmeans.py └── listing5_5 │ └── qsvm_new.py ├── Chapter_6 ├── listing6_1 │ ├── QCNN.py │ └── listing_6.1_output.txt └── listing6_2 │ ├── listing_6.2_output.txt.txt │ └── tfq_mnist.py ├── Chapter_7 ├── listing7_1 │ ├── listing_7.1_output.txt │ └── vqe_cirq.py ├── listing7_2 │ ├── Max_cut_clustering.py │ └── Maxcut_clustering.png ├── listing7_3 │ ├── QAOA.py │ └── listing_7.3_output.txt └── listing7_4 │ ├── Listing_figure_7.4.amplitude.png │ ├── listing_7.4_output.txt │ └── quantum_random_walk.py ├── Contributing.md ├── LICENSE.txt ├── README.md └── errata.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /9781484265215.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/quantum-machine-learning-python/7d22e2cebd807003ff098cc1138356d775014163/9781484265215.jpg -------------------------------------------------------------------------------- /Chapter_3/listing3_1/listing_3.1.py: -------------------------------------------------------------------------------- 1 | # Import the cirq package 2 | 3 | import cirq 4 | print('cirq version',cirq.__version__) 5 | # Define a Qubit 6 | qubit = cirq.GridQubit(0,0) 7 | 8 | # Create a Cirquit 9 | circuit = cirq.Circuit([cirq.H(qubit), 10 | cirq.measure(qubit,key='m')]) 11 | print("Circuit Follows") 12 | print(circuit) 13 | 14 | sim = cirq.Simulator() 15 | output = sim.run(circuit,repetitions=100) 16 | print("Measurement Output:") 17 | print(output) 18 | print(output.histogram(key='m')) -------------------------------------------------------------------------------- /Chapter_3/listing3_1/listing_3.1_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.1.py 2 | cirq version 0.8.2 3 | Circuit Follows 4 | (0, 0): ───H───M('m')─── 5 | Measurement Output: 6 | m=1110010010110101111000000100011000101011100101011110001010001110110101110100010110011110110111100001 7 | Counter({1: 52, 0: 48}) 8 | 9 | Process finished with exit code 0 10 | -------------------------------------------------------------------------------- /Chapter_3/listing3_10/listing_3.10.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq version',cirq.__version__) 4 | print('numpy version',np.__version__) 5 | 6 | 7 | def bell_inequality_test_circuit(): 8 | """ 9 | Define 4 qubits 10 | 0th qubit - Alice 11 | 1st qubit - contains the bit sent to Alice by the referee 12 | 2nd qubit - Bob's qubit 13 | 3rd qubit - contains the bit sent to Bob by the referee 14 | :return: 15 | """ 16 | qubits = [cirq.LineQubit(i) for i in range(4)] 17 | circuit = cirq.Circuit() 18 | # Entangle Alice and Bob to the Bell State 19 | circuit.append([cirq.H(qubits[0]), cirq.CNOT(qubits[0], qubits[2])]) 20 | # Apply X^(-0.25) on Alice's Qubit 21 | circuit.append([cirq.X(qubits[0])**(-0.25)]) 22 | # Apply Hadamard transform to the referee Qubits for Alice and Bob 23 | # This is done to randomize the qubit 24 | circuit.append([cirq.H(qubits[1]), cirq.H(qubits[3])]) 25 | # Perform a Conditional X^0.5 on Alice and Bob Qubits based on corresponding referee qubits 26 | circuit.append([cirq.CNOT(qubits[1], qubits[0])**0.5]) 27 | circuit.append([cirq.CNOT(qubits[3], qubits[2])**0.5]) 28 | # Measure all the qubits 29 | circuit.append(cirq.measure(qubits[0], key='A')) 30 | circuit.append(cirq.measure(qubits[1], key='r_A')) 31 | circuit.append(cirq.measure(qubits[2], key='B')) 32 | circuit.append(cirq.measure(qubits[3], key='r_B')) 33 | return circuit 34 | 35 | def main(iters=1000): 36 | # Build the Bell inequality test circuit 37 | circuit = bell_inequality_test_circuit() 38 | print("Bell Inequality Test Circuit") 39 | print(circuit) 40 | #Simulate for several iterations 41 | sim = cirq.Simulator() 42 | result = sim.run(circuit, repetitions=iters) 43 | A = result.measurements['A'][:, 0] 44 | r_A = result.measurements['r_A'][:, 0] 45 | B = result.measurements['B'][:, 0] 46 | r_B = result.measurements['r_B'][:, 0] 47 | 48 | win = (np.array(A) + np.array(B)) % 2 == (np.array(r_A) & np.array(r_B)) 49 | print(f"Alice and Bob won {100*np.mean(win)} % of the times") 50 | 51 | if __name__ == '__main__': 52 | main() 53 | 54 | -------------------------------------------------------------------------------- /Chapter_3/listing3_10/listing_3.10_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.10.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | Bell Inequality Test Circuit 5 | 0: ───H───@───X^-0.25───X──────────M('A')───── 6 | │ │ 7 | 1: ───H───┼─────────────@^0.5──────M('r_A')─── 8 | │ 9 | 2: ───────X───X─────────M('B')──────────────── 10 | │ 11 | 3: ───H───────@^0.5─────M('r_B')────────────── 12 | Alice and Bob won 85.9 % of the times 13 | 14 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_3/listing3_11/listing_3.11.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('cirq version',cirq.__version__) 3 | 4 | def oracle(input_qubits,target_qubits,circuit): 5 | # Oracle for Secret Code 110 6 | circuit.append(cirq.CNOT(input_qubits[2],target_qubits[1])) 7 | circuit.append(cirq.X(target_qubits[0])) 8 | circuit.append(cirq.CNOT(input_qubits[2], target_qubits[0])) 9 | circuit.append(cirq.CCNOT(input_qubits[0],input_qubits[1],target_qubits[0])) 10 | circuit.append(cirq.X(input_qubits[0])) 11 | circuit.append(cirq.X(input_qubits[1])) 12 | circuit.append(cirq.CCNOT(input_qubits[0], input_qubits[1], target_qubits[0])) 13 | circuit.append(cirq.X(input_qubits[0])) 14 | circuit.append(cirq.X(input_qubits[1])) 15 | circuit.append(cirq.X(target_qubits[0])) 16 | return circuit 17 | 18 | 19 | 20 | def simons_algorithm_circuit(num_qubits=3): 21 | """ 22 | Build the circuit for Simon's Algorithm 23 | :param num_qubits: 24 | :return: 25 | """ 26 | input_qubits = [cirq.LineQubit(i) for i in range(num_qubits)] 27 | target_qubits = [cirq.LineQubit(k) for k in range(num_qubits, 2 * num_qubits)] 28 | circuit = cirq.Circuit() 29 | # Create Equal Superposition state for the Input Qubits 30 | circuit.append([cirq.H(input_qubits[i]) for i in range(num_qubits)]) 31 | circuit = oracle(input_qubits, target_qubits, circuit) 32 | circuit.append(cirq.measure(*target_qubits, key='T')) 33 | circuit.append([cirq.H(input_qubits[i]) for i in range(num_qubits)]) 34 | circuit.append(cirq.measure(*(input_qubits + target_qubits), key='Z')) 35 | print("Circuit Diagram for Simons Algorithm follows") 36 | print(circuit) 37 | #Simulate Algorithm 38 | sim = cirq.Simulator() 39 | result = sim.run(circuit,repetitions=1000) 40 | out = dict(result.histogram(key='Z')) 41 | out_result = {} 42 | for k in out.keys(): 43 | new_key = "{0:b}".format(k) 44 | if len(new_key) < 2*num_qubits: 45 | new_key = (2*num_qubits - len(new_key))*'0' + new_key 46 | #print(new_key,k) 47 | out_result[new_key] = out[k] 48 | print(out_result) 49 | 50 | 51 | if __name__ =='__main__': 52 | simons_algorithm_circuit() 53 | -------------------------------------------------------------------------------- /Chapter_3/listing3_11/listing_3.11_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.11.py 2 | cirq version 0.8.2 3 | Circuit Diagram for Simons Algorithm follows 4 | ┌──┐ 5 | 0: ───H────────────@─────X───@───X───H────────M('Z')─── 6 | │ │ │ 7 | 1: ───H────────────@─────X───@───X───H────────M──────── 8 | │ │ │ 9 | 2: ───H───@───@────┼H────────┼────────────────M──────── 10 | │ │ │ │ │ 11 | 3: ───X───┼───X────X─────────X───X───M('T')───M──────── 12 | │ │ │ 13 | 4: ───────X──────────────────────────M────────M──────── 14 | │ │ 15 | 5: ──────────────────────────────────M────────M──────── 16 | └──┘ 17 | {'111000': 51, '000110': 61, '111010': 54, '110100': 68, '001110': 67, '110110': 59, '000000': 54, '000010': 56, '110010': 62, '111110': 62, '001100': 70, '000100': 54, '111100': 67, '001010': 79, '110000': 74, '001000': 62} 18 | 19 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_3/listing3_12/listing_3.12.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('cirq version',cirq.__version__) 3 | 4 | def oracle(input_qubits, target_qubit, circuit, secret_element='01'): 5 | print(f"Element to be searched: {secret_element}") 6 | 7 | # Flip the qubits corresponding to the bits containing 0 8 | for i, bit in enumerate(secret_element): 9 | if int(bit) == 0: 10 | circuit.append(cirq.X(input_qubits[i])) 11 | # Do a Conditional NOT using all input qubits as control 12 | circuit.append(cirq.TOFFOLI(*input_qubits, target_qubit)) 13 | # Revert the input qubits to the state prior to Flipping 14 | for i, bit in enumerate(secret_element): 15 | if int(bit) == 0: 16 | circuit.append(cirq.X(input_qubits[i])) 17 | return circuit 18 | 19 | 20 | def grovers_algorithm(num_qubits=2, copies=1000): 21 | # Define input and Target Qubit 22 | input_qubits = [cirq.LineQubit(i) for i in range(num_qubits)] 23 | target_qubit = cirq.LineQubit(num_qubits) 24 | # Define Quantum Circuit 25 | circuit = cirq.Circuit() 26 | # Create equal Superposition State 27 | circuit.append([cirq.H(input_qubits[i]) for i in range(num_qubits)]) 28 | # Take target qubit to minus state |-> 29 | circuit.append([cirq.X(target_qubit), cirq.H(target_qubit)]) 30 | # Pass the qubit through the Oracle 31 | circuit = oracle(input_qubits, target_qubit, circuit) 32 | # Construct Grover operator. 33 | circuit.append(cirq.H.on_each(*input_qubits)) 34 | circuit.append(cirq.X.on_each(*input_qubits)) 35 | circuit.append(cirq.H.on(input_qubits[1])) 36 | circuit.append(cirq.CNOT(input_qubits[0], input_qubits[1])) 37 | circuit.append(cirq.H.on(input_qubits[1])) 38 | circuit.append(cirq.X.on_each(*input_qubits)) 39 | circuit.append(cirq.H.on_each(*input_qubits)) 40 | 41 | # Measure the result. 42 | circuit.append(cirq.measure(*input_qubits, key='Z')) 43 | print("Grover's algorithm follows") 44 | print(circuit) 45 | sim = cirq.Simulator() 46 | result = sim.run(circuit, repetitions=copies) 47 | out = result.histogram(key='Z') 48 | 49 | out_result = {} 50 | for k in out.keys(): 51 | new_key = "{0:b}".format(k) 52 | if len(new_key) < num_qubits: 53 | new_key = (num_qubits - len(new_key)) * '0' + new_key 54 | # print(new_key,k) 55 | out_result[new_key] = out[k] 56 | print(out_result) 57 | 58 | 59 | 60 | 61 | if __name__ =='__main__': 62 | grovers_algorithm(2) -------------------------------------------------------------------------------- /Chapter_3/listing3_12/listing_3.12_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.13.py 2 | cirq version 0.8.2 3 | Element to be searched: 01 4 | Grover's algorithm follows 5 | 0: ───H───X───@───X───H───X───@───X───H───────M('Z')─── 6 | │ │ │ 7 | 1: ───H───────@───H───X───H───X───H───X───H───M──────── 8 | │ 9 | 2: ───X───H───X──────────────────────────────────────── 10 | {'01': 1000} 11 | 12 | Process finished with exit code 0 13 | -------------------------------------------------------------------------------- /Chapter_3/listing3_2/listing_3.2.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('circ version',cirq.__version__) 3 | import matplotlib.pyplot as plt 4 | import matplotlib 5 | print('matplotlib version', matplotlib.__version__) 6 | 7 | 8 | def hadamard_state_measurement(copies): 9 | # Define a Qubit 10 | qubit = cirq.GridQubit(0, 0) 11 | # Create a Circuit in cirq 12 | circuit = cirq.Circuit([cirq.H(qubit), cirq.measure(qubit, key='m')]) 13 | print("Circuit Follows") 14 | print(circuit) 15 | sim = cirq.Simulator() 16 | output = sim.run(circuit, repetitions=copies) 17 | res = output.histogram(key='m') 18 | prob_0 = dict(res)[0] / copies 19 | print(prob_0) 20 | return prob_0 21 | 22 | 23 | def main(copies_low=100, copies_high=1000): 24 | print("Coming") 25 | probability_for_zero_state_trace = [] 26 | copies_trace = [] 27 | for n in range(copies_low, copies_high): 28 | copies_trace.append(n) 29 | prob_0 = hadamard_state_measurement(n) 30 | probability_for_zero_state_trace.append(prob_0) 31 | plt.plot(copies_trace, probability_for_zero_state_trace) 32 | plt.xlabel('No of Measurements') 33 | plt.ylabel("Probability of the State 0") 34 | plt.title("Convergence Sequence of Probability for State 0") 35 | plt.show() 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /Chapter_3/listing3_3/listing_3.3.py: -------------------------------------------------------------------------------- 1 | """ 2 | Measure a qubit after Hadamard Transform 3 | """ 4 | import qiskit 5 | print('qiskit version', qiskit.__version__) 6 | from qiskit import QuantumCircuit, execute, Aer 7 | from qiskit.visualization import plot_histogram 8 | 9 | # Use Aer's qasm_simulator 10 | simulator = Aer.get_backend('qasm_simulator') 11 | 12 | # Create a Quantum Circuit with 1 Qubit 13 | circuit = QuantumCircuit(1, 1) 14 | 15 | # Add a H gate on Qubit 0 16 | circuit.h(0) 17 | 18 | # Map the quantum measurement to the classical register 19 | circuit.measure([0], [0]) 20 | 21 | # Execute the circuit on the qasm simulator 22 | job = execute(circuit, simulator, shots=100) 23 | 24 | # Grab results from the job 25 | result = job.result() 26 | 27 | # Returns counts 28 | counts = result.get_counts(circuit) 29 | print("\nTotal count for 0 and 1 are:",counts) 30 | 31 | # Draw the circuit 32 | print(circuit.draw(output='text')) -------------------------------------------------------------------------------- /Chapter_3/listing3_3/listing_3.3_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/qiskit.superpsotion.py 2 | qiskit version 0.15.2 3 | 4 | Total count for 0 and 1 are: {'0': 54, '1': 46} 5 | ┌───┐┌─┐ 6 | q_0: ┤ H ├┤M├ 7 | └───┘└╥┘ 8 | c: 1/══════╩═ 9 | 0 10 | 11 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_3/listing3_4/listing_3.4.py: -------------------------------------------------------------------------------- 1 | # Bell State Creation 2 | import cirq 3 | print('cirq version', cirq.__version__) 4 | #Define the two qubits using LineQubit 5 | q_register = [cirq.LineQubit(i) for i in range(2)] 6 | cirquit = cirq.Circuit([cirq.H(q_register[0]), cirq.CNOT(q_register[0], q_register[1])]) 7 | cirquit.append(cirq.measure(*q_register,key='z')) 8 | print("Circuit") 9 | print(cirquit) 10 | sim = cirq.Simulator() 11 | output = sim.run(cirquit, repetitions=100) 12 | print("Measurement Output") 13 | print(output.histogram(key='z')) -------------------------------------------------------------------------------- /Chapter_3/listing3_4/listing_3.4_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.4.py 2 | cirq version 0.8.2 3 | Circuit 4 | 0: ───H───@───M('z')─── 5 | │ │ 6 | 1: ───────X───M──────── 7 | Measurement Output 8 | Counter({3: 57, 0: 43}) 9 | 10 | Process finished with exit code 0 11 | -------------------------------------------------------------------------------- /Chapter_3/listing3_5/listing_3.5.py: -------------------------------------------------------------------------------- 1 | """ 2 | Quantum Entanglement Example with Qiskit 3 | """ 4 | import qiskit 5 | print('qiskit version', qiskit.__version__) 6 | from qiskit import QuantumCircuit, execute, Aer 7 | 8 | from qiskit.visualization import plot_histogram 9 | 10 | # Use Aer's qasm_simulator 11 | simulator = Aer.get_backend('qasm_simulator') 12 | 13 | # Create a Quantum Circuit acting on the q register 14 | circuit = QuantumCircuit(2, 2) 15 | 16 | # Add a H gate on Qubit 0 17 | circuit.h(0) 18 | 19 | # Add a CX (CNOT) gate on control qubit 0 and target qubit 1 20 | circuit.cx(0, 1) 21 | 22 | # Map the quantum measurement to the classical bits 23 | circuit.measure([0,1], [0,1]) 24 | 25 | # Execute the circuit on the qasm simulator 26 | job = execute(circuit, simulator, shots=100) 27 | 28 | # Grab results from the job 29 | result = job.result() 30 | 31 | # Returns counts 32 | counts = result.get_counts(circuit) 33 | print("\nTotal count for 00 and 11 are:",counts) 34 | 35 | # Draw the circuit 36 | print(circuit.draw(output='text')) -------------------------------------------------------------------------------- /Chapter_3/listing3_5/listing_3.5_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.4.py 2 | cirq version 0.8.2 3 | Circuit 4 | 0: ───H───@───M('z')─── 5 | │ │ 6 | 1: ───────X───M──────── 7 | Measurement Output 8 | Counter({3: 57, 0: 43}) 9 | 10 | Process finished with exit code 0 11 | -------------------------------------------------------------------------------- /Chapter_3/listing3_6/listing_3.6.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('cirq version',cirq.__version__) 3 | 4 | 5 | def quantum_teleportation(qubit_to_send_op='H'): 6 | q_register = [cirq.LineQubit(i) for i in range(3)] 7 | cirquit = cirq.Circuit() 8 | """ 9 | Qubit 0 : Alice State qubit to be sent to Bob 10 | QUbit 1: Alices control qubit 11 | Qubit 2: Bobs control qubit 12 | Set a state for Qubit 0 based on qubit_to_send_op : Implemented operators H,X,Y,Z,I 13 | """ 14 | if qubit_to_send_op == 'H': 15 | cirquit.append(cirq.H(q_register[0])) 16 | elif qubit_to_send_op == 'X': 17 | cirquit.append(cirq.X(q_register[0])) 18 | elif qubit_to_send_op == 'Y': 19 | cirquit.append(cirq.X(q_register[0])) 20 | elif qubit_to_send_op == 'I': 21 | cirquit.append(cirq.I(q_register[0])) 22 | else: 23 | raise NotImplementedError("Yet to be implemented") 24 | 25 | # Entangle Alice and Bob's control qubits : Qubit 1 and Qubit 2 26 | cirquit.append(cirq.H(q_register[1])) 27 | cirquit.append(cirq.CNOT(q_register[1],q_register[2])) 28 | # CNOT Alice data qubit with control qubit 29 | cirquit.append(cirq.CNOT(q_register[0],q_register[1])) 30 | # Tranform Alices data qubit |+> |-> basis and perform measurement 31 | # on both of Alice's qubit 32 | cirquit.append(cirq.H(q_register[0])) 33 | cirquit.append(cirq.measure(q_register[0], q_register[1])) 34 | # Do a CNOT with Alice's control qubit on Bob's control qubit 35 | cirquit.append(cirq.CNOT(q_register[1],q_register[2])) 36 | # Do a Control Z on Bob's qubit based on Alice's data qubit 37 | cirquit.append(cirq.CZ(q_register[0],q_register[2])) 38 | cirquit.append(cirq.measure(q_register[2],key='Z')) 39 | print("Circuit") 40 | print(cirquit) 41 | sim = cirq.Simulator() 42 | output = sim.run(cirquit, repetitions=100) 43 | print("Measurement Output") 44 | print(output.histogram(key='Z')) 45 | 46 | if __name__ == '__main__': 47 | quantum_teleportation(qubit_to_send_op='H') 48 | 49 | -------------------------------------------------------------------------------- /Chapter_3/listing3_6/listing_3.6_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.6.py 2 | cirq version 0.8.2 3 | Circuit 4 | 0: ───H───────@───H───M───────@──────────── 5 | │ │ │ 6 | 1: ───H───@───X───────M───@───┼──────────── 7 | │ │ │ 8 | 2: ───────X───────────────X───@───M('Z')─── 9 | Measurement Output 10 | Counter({0: 57, 1: 43}) 11 | 12 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_3/listing3_7/listing_3.7.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq verison',cirq.__version__) 4 | print('numpy version',np.__version__) 5 | 6 | def random_number_generator(low=0,high=2**10,m=20): 7 | """ 8 | 9 | :param low: lower bound of numbers to be generated 10 | :param high: Upper bound of numbers to be generated 11 | :param number m : Number of random numbers to output 12 | :return: string random numbers 13 | """ 14 | # Determine the number of Qubits required 15 | qubits_required = int(np.ceil(np.log2(high - low))) 16 | print(qubits_required) 17 | # Define the qubits 18 | Q_reg = [cirq.LineQubit(c) for c in range(qubits_required)] 19 | # Define the circuit 20 | circuit = cirq.Circuit() 21 | circuit.append(cirq.H(Q_reg[c]) for c in range(qubits_required)) 22 | circuit.append(cirq.measure(*Q_reg, key="z")) 23 | print(circuit) 24 | 25 | # Simulate the cirquit 26 | 27 | sim = cirq.Simulator() 28 | 29 | num_gen = 0 30 | output = [] 31 | while num_gen <= m : 32 | result = sim.run(circuit,repetitions=1) 33 | rand_number = result.data.get_values()[0][0] + low 34 | if rand_number < high : 35 | output.append(rand_number) 36 | num_gen += 1 37 | return output 38 | 39 | 40 | if __name__ == '__main__': 41 | output = random_number_generator() 42 | print("Sampled Random Numbers") 43 | print(output) 44 | print("Mean of the Sampled Random Numbers", np.mean(output)) 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Chapter_3/listing3_7/listing_3.7_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.7.py 2 | cirq verison 0.8.2 3 | numpy version 1.19.0 4 | 10 5 | 0: ───H───M('z')─── 6 | │ 7 | 1: ───H───M──────── 8 | │ 9 | 2: ───H───M──────── 10 | │ 11 | 3: ───H───M──────── 12 | │ 13 | 4: ───H───M──────── 14 | │ 15 | 5: ───H───M──────── 16 | │ 17 | 6: ───H───M──────── 18 | │ 19 | 7: ───H───M──────── 20 | │ 21 | 8: ───H───M──────── 22 | │ 23 | 9: ───H───M──────── 24 | Sampled Random Numbers 25 | [91, 105, 437, 570, 1009, 436, 809, 478, 696, 417, 975, 958, 564, 916, 105, 1020, 629, 263, 928, 276, 607] 26 | Mean of the Sampled Random Numbers 585.1904761904761 27 | 28 | Process finished with exit code 0 29 | -------------------------------------------------------------------------------- /Chapter_3/listing3_8/listing_3.8.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq version',cirq.__version__) 4 | print('numpy version',np.__version__) 5 | 6 | def oracle(data_reg, y_reg, circuit, is_balanced=True): 7 | if is_balanced: 8 | circuit.append([cirq.CNOT(data_reg[0], y_reg), cirq.CNOT(data_reg[1], y_reg)]) 9 | 10 | return circuit 11 | 12 | 13 | def deutsch_jozsa(domain_size: int, func_type_to_simulate: str = "balanced", copies: int = 1000): 14 | """ 15 | 16 | :param domain_size: Number of inputs to the function 17 | :param oracle: Oracle simulating the function 18 | :return: whether the function is balanced or constant 19 | """ 20 | # Define the data register and the target qubit 21 | 22 | reqd_num_qubits = int(np.ceil(np.log2(domain_size))) 23 | #Define the input qubits 24 | data_reg = [cirq.LineQubit(c) for c in range(reqd_num_qubits)] 25 | # Define the Target qubits 26 | y_reg = cirq.LineQubit(reqd_num_qubits) 27 | # Define cirq Circuit 28 | circuit = cirq.Circuit() 29 | # Define equal superposition state for the input qubits 30 | circuit.append(cirq.H(data_reg[c]) for c in range(reqd_num_qubits)) 31 | # Define Minus superposition state 32 | circuit.append(cirq.X(y_reg)) 33 | circuit.append(cirq.H(y_reg)) 34 | 35 | # Check for nature of function : balanced/constant to simulate 36 | # and implement Oracle accordingly 37 | if func_type_to_simulate == 'balanced': 38 | is_balanced = True 39 | else: 40 | is_balanced = False 41 | 42 | circuit = oracle(data_reg, y_reg, circuit, is_balanced=is_balanced) 43 | # Apply Hadamard transform on each of the input qubits 44 | circuit.append(cirq.H(data_reg[c]) for c in range(reqd_num_qubits)) 45 | # Measure the input qubits 46 | circuit.append(cirq.measure(*data_reg, key='z')) 47 | print("Circuit Diagram Follows") 48 | print(circuit) 49 | sim = cirq.Simulator() 50 | result = sim.run(circuit, repetitions=copies) 51 | print(result.histogram(key='z')) 52 | 53 | 54 | if __name__ == '__main__': 55 | print("Execute Deutsch Jozsa for a Balanced Function of Domain size 4") 56 | deutsch_jozsa(domain_size=4, func_type_to_simulate='balanced', copies=1000) 57 | 58 | print("Execute Deutsch Jozsa for a Constant Function of Domain size 4") 59 | deutsch_jozsa(domain_size=4, func_type_to_simulate='', copies=1000) 60 | -------------------------------------------------------------------------------- /Chapter_3/listing3_8/listing_3.8_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing3.8.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | Execute Deutsch Jozsa for a Balanced Function of Domain size 4 5 | Circuit Diagram Follows 6 | 0: ───H───────@───H───────M('z')─── 7 | │ │ 8 | 1: ───H───────┼───@───H───M──────── 9 | │ │ 10 | 2: ───X───H───X───X──────────────── 11 | Counter({3: 1000}) 12 | Execute Deutsch Jozsa for a Constant Function of Domain size 4 13 | Circuit Diagram Follows 14 | 0: ───H───H───M('z')─── 15 | │ 16 | 1: ───H───H───M──────── 17 | 18 | 2: ───X───H──────────── 19 | Counter({0: 1000}) 20 | 21 | Process finished with exit code 0 22 | -------------------------------------------------------------------------------- /Chapter_3/listing3_9/listing_3.9.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq version',cirq.__version__) 4 | print('numpy version',np.__version__) 5 | 6 | 7 | 8 | def func_bit_pattern(num_qubits): 9 | """ 10 | Create the Oracle function Parameters 11 | :param num_qubits: 12 | :return: 13 | """ 14 | bit_pattern = [] 15 | for i in range(num_qubits): 16 | bit_pattern.append(np.random.randint(0, 2)) 17 | print(f"Function bit pattern: {''.join([str(x) for x in bit_pattern]) }") 18 | return bit_pattern 19 | 20 | def oracle(input_qubits,target_qubit,circuit,num_qubits,bit_pattern): 21 | """ 22 | Define the oracle 23 | :param input_qubits: 24 | :param target_qubit: 25 | :param circuit: 26 | :param num_qubits: 27 | :param bit_pattern: 28 | :return: 29 | """ 30 | for i in range(num_qubits): 31 | if bit_pattern[i] == 1: 32 | circuit.append(cirq.CNOT(input_qubits[i],target_qubit)) 33 | return circuit 34 | 35 | def BV_algorithm(num_qubits, bit_pattern): 36 | """ 37 | 38 | :param num_qubits: 39 | :return: 40 | """ 41 | input_qubits = [cirq.LineQubit(i) for i in range(num_qubits)] 42 | target_qubit = cirq.LineQubit(num_qubits) 43 | circuit = cirq.Circuit() 44 | circuit.append([cirq.H(input_qubits[i]) for i in range(num_qubits)]) 45 | circuit.append([cirq.X(target_qubit), cirq.H(target_qubit)]) 46 | circuit = oracle(input_qubits, target_qubit,circuit,num_qubits,bit_pattern) 47 | circuit.append([cirq.H(input_qubits[i]) for i in range(num_qubits)]) 48 | circuit.append(cirq.measure(*input_qubits,key='Z')) 49 | print("Bernstein Vajirani Circuit Diagram") 50 | print(circuit) 51 | sim = cirq.Simulator() 52 | results = sim.run(circuit, repetitions=1000) 53 | results = dict(results.histogram(key='Z')) 54 | print(results) 55 | results_binary = {} 56 | for k in results.keys(): 57 | results_binary["{0:b}".format(k)] = results[k] 58 | print("Distribution of bit pattern output from Bernstein Vajirani Algorithm") 59 | print(results_binary) 60 | 61 | def main(num_qubits=6, bit_pattern=None): 62 | if bit_pattern is None: 63 | bit_pattern = func_bit_pattern(num_qubits) 64 | 65 | BV_algorithm(num_qubits, bit_pattern) 66 | 67 | if __name__ == '__main__': 68 | main() 69 | -------------------------------------------------------------------------------- /Chapter_3/listing3_9/listing_3.9_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/listing_3.9.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | Function bit pattern: 100011 5 | Bernstein Vajirani Circuit Diagram 6 | 0: ───H───────@───H───────────M('Z')─── 7 | │ │ 8 | 1: ───H───H───┼───────────────M──────── 9 | │ │ 10 | 2: ───H───H───┼───────────────M──────── 11 | │ │ 12 | 3: ───H───H───┼───────────────M──────── 13 | │ │ 14 | 4: ───H───────┼───@───H───────M──────── 15 | │ │ │ 16 | 5: ───H───────┼───┼───@───H───M──────── 17 | │ │ │ 18 | 6: ───X───H───X───X───X──────────────── 19 | {35: 1000} 20 | Distribution of bit pattern output from Bernstein Vajirani Algorithm 21 | {'100011': 1000} 22 | 23 | Process finished with exit code 0 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter_4/listing4_1/listing_4.1_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/quantum_fourier_transform.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | fire 0.2.1 5 | elapsedtimer 0.4 6 | Circuit after processing Qubit: 0 7 | 0: ───H─── 8 | Circuit after processing Qubit: 1 9 | 0: ───H───@──────────── 10 | │ 11 | 1: ───────@^-0.5───H─── 12 | Circuit after processing Qubit: 2 13 | ┌────────┐ 14 | 0: ───H───@──────────@─────────────────────── 15 | │ │ 16 | 1: ───────@^-0.5────H┼──────────@──────────── 17 | │ │ 18 | 2: ──────────────────@^-0.25────@^-0.5───H─── 19 | └────────┘ 20 | Circuit after processing Qubit: 3 21 | ┌────────┐ ┌──────────────┐ ┌────────┐ 22 | 0: ───H───@──────────@─────────────────@───────────────────────────────────── 23 | │ │ │ 24 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@─────────────────────── 25 | │ │ │ │ 26 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@──────────── 27 | │ │ │ 28 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H─── 29 | └────────┘ └──────────────┘ └────────┘ 30 | Circuit after qubit state swap: 31 | ┌────────┐ ┌──────────────┐ ┌────────┐ 32 | 0: ───H───@──────────@─────────────────@─────────────────────────────────────×─── 33 | │ │ │ │ 34 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@───────────────────×───┼─── 35 | │ │ │ │ │ │ 36 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@────────×───┼─── 37 | │ │ │ │ 38 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H───×─── 39 | └────────┘ └──────────────┘ └────────┘ 40 | Combined Circuit 41 | ┌────────┐ ┌──────────────┐ ┌────────┐ 42 | 0: ───H───@──────────@─────────────────@─────────────────────────────────────×─── 43 | │ │ │ │ 44 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@───────────────────×───┼─── 45 | │ │ │ │ │ │ 46 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@────────×───┼─── 47 | │ │ │ │ 48 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H───×─── 49 | └────────┘ └──────────────┘ └────────┘ 50 | measurements: (no measurements) 51 | output vector: [0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 52 | 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 53 | 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 54 | 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j 0.24999997+0.j] 55 | 21.491 ms: Execute Quantum Fourier Transform 56 | 57 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_4/listing4_1/quantum_fourier_transform.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | import fire 4 | import elapsedtimer 5 | from elapsedtimer import ElapsedTimer 6 | print('cirq version',cirq.__version__) 7 | print('numpy version',np.__version__) 8 | print('fire',fire.__version__) 9 | print('elapsedtimer',elapsedtimer.__version__) 10 | 11 | 12 | class QFT: 13 | """ 14 | Quantum Fourier Transform 15 | Builds the QFT circuit iteratively 16 | """ 17 | 18 | def __init__(self, signal_length=16, 19 | basis_to_transform='', 20 | validate_inverse_fourier=False, 21 | qubits=None): 22 | 23 | self.signal_length = signal_length 24 | self.basis_to_transform = basis_to_transform 25 | 26 | if qubits is None: 27 | self.num_qubits = int(np.log2(signal_length)) 28 | self.qubits = [cirq.LineQubit(i) for i in range(self.num_qubits)] 29 | else: 30 | self.qubits = qubits 31 | self.num_qubits = len(self.qubits) 32 | 33 | self.qubit_index = 0 34 | self.input_circuit = cirq.Circuit() 35 | 36 | self.validate_inverse_fourier = validate_inverse_fourier 37 | self.circuit = cirq.Circuit() 38 | # if self.validate_inverse_fourier: 39 | self.inv_circuit = cirq.Circuit() 40 | 41 | for k, q_s in enumerate(self.basis_to_transform): 42 | if int(q_s) == 1: 43 | # Change the qubit state from 0 to 1 44 | self.input_circuit.append(cirq.X(self.qubits[k])) 45 | 46 | def qft_circuit_iter(self): 47 | 48 | if self.qubit_index > 0: 49 | # Apply the rotations on the prior qubits 50 | # conditioned on the current qubit 51 | for j in range(self.qubit_index): 52 | diff = self.qubit_index - j + 1 53 | rotation_to_apply = -2.0 / (2.0 ** diff) 54 | self.circuit.append(cirq.CZ(self.qubits[self.qubit_index], 55 | self.qubits[j]) ** rotation_to_apply) 56 | # Apply the Hadamard Transform 57 | # on current qubit 58 | self.circuit.append(cirq.H(self.qubits[self.qubit_index])) 59 | # set up the processing for next qubit 60 | self.qubit_index += 1 61 | 62 | def qft_circuit(self): 63 | 64 | while self.qubit_index < self.num_qubits: 65 | self.qft_circuit_iter() 66 | # See the progression of the Circuit built 67 | print(f"Circuit after processing Qubit: {self.qubit_index - 1} ") 68 | print(self.circuit) 69 | # Swap the qubits to match qft definititon 70 | self.swap_qubits() 71 | print("Circuit after qubit state swap:") 72 | print(self.circuit) 73 | # Create the inverse Fourier Transform Circuit 74 | self.inv_circuit = cirq.inverse(self.circuit.copy()) 75 | 76 | def swap_qubits(self): 77 | for i in range(self.num_qubits // 2): 78 | self.circuit.append(cirq.SWAP(self.qubits[i], self.qubits[self.num_qubits - i - 1])) 79 | 80 | def simulate_circuit(self): 81 | sim = cirq.Simulator() 82 | result = sim.simulate(self.circuit) 83 | return result 84 | 85 | 86 | def main(signal_length=16, 87 | basis_to_transform='0000', 88 | validate_inverse_fourier=False): 89 | 90 | # Instantiate QFT Class 91 | _qft_ = QFT(signal_length=signal_length, 92 | basis_to_transform=basis_to_transform, 93 | validate_inverse_fourier=validate_inverse_fourier) 94 | 95 | 96 | # Build the QFT Circuit 97 | _qft_.qft_circuit() 98 | 99 | # Create the input Qubit State 100 | 101 | if len(_qft_.input_circuit) > 0: 102 | _qft_.circuit = _qft_.input_circuit + _qft_.circuit 103 | 104 | if _qft_.validate_inverse_fourier: 105 | _qft_.circuit += _qft_.inv_circuit 106 | 107 | print("Combined Circuit") 108 | print(_qft_.circuit) 109 | # Simulate the circuit 110 | 111 | output_state = _qft_.simulate_circuit() 112 | # Print the Results 113 | print(output_state) 114 | 115 | 116 | if __name__ == '__main__': 117 | with ElapsedTimer('Execute Quantum Fourier Transform'): 118 | fire.Fire(main) 119 | -------------------------------------------------------------------------------- /Chapter_4/listing4_2/listing_4.2_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/quantum_phase_estimation.py 2 | cirq version 0.8.2 3 | cirq version 0.8.2 4 | numpy version 1.19.0 5 | fire 0.2.1 6 | elapsedtimer 0.4 7 | CZ 8 | CZ 9 | Circuit after processing Qubit: 0 10 | 0: ───H─── 11 | Circuit after processing Qubit: 1 12 | 0: ───H───@──────────── 13 | │ 14 | 1: ───────@^-0.5───H─── 15 | Circuit after qubit state swap: 16 | 0: ───H───@────────────×─── 17 | │ │ 18 | 1: ───────@^-0.5───H───×─── 19 | 0: ───────H───@─────────×───────@───────H─── 20 | │ │ │ 21 | 1: ───────H───┼─────@───×───H───@^0.5─────── 22 | │ │ 23 | 2: ───X───────@^0───@─────────────────────── 24 | measurements: (no measurements) 25 | output vector: |101⟩ 26 | 27 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_4/listing4_2/quantum_phase_estimation.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('cirq version', cirq.__version__) 3 | from quantum_fourier_transform import QFT 4 | 5 | class quantum_phase_estimation: 6 | 7 | def __init__(self, num_input_state_qubits=3, 8 | num_ancillia_qubits=5, 9 | unitary_transform=None, 10 | U=None, 11 | input_state=None): 12 | 13 | 14 | self.num_ancillia_qubits = num_ancillia_qubits 15 | 16 | self.output_qubits = [cirq.LineQubit(i) for i in range(self.num_ancillia_qubits)] 17 | 18 | self.input_circuit = cirq.Circuit() 19 | self.input_state = input_state 20 | 21 | if self.input_state is not None: 22 | self.num_input_qubits = len(self.input_state) 23 | else: 24 | self.num_input_qubits = num_input_state_qubits 25 | 26 | self.input_qubits = [cirq.LineQubit(i) for i in 27 | range(self.num_ancillia_qubits, 28 | self.num_ancillia_qubits + num_input_state_qubits)] 29 | 30 | if self.input_state is not None: 31 | for i, c in enumerate(self.input_state): 32 | if int(c) == 1: 33 | self.input_circuit.append(cirq.X(self.input_qubits[i])) 34 | 35 | self.unitary_transform = unitary_transform 36 | if self.unitary_transform is None: 37 | self.U = cirq.I 38 | elif self.unitary_transform == 'custom': 39 | self.U = U 40 | elif self.unitary_transform == 'Z': 41 | self.U = cirq.CZ 42 | elif self.unitary_transform == 'X': 43 | self.U = cirq.CX 44 | else: 45 | raise NotImplementedError(f"self.unitary transform not Implemented") 46 | 47 | self.circuit = cirq.Circuit() 48 | 49 | 50 | def phase_1_create_circuit_iter(self): 51 | 52 | for i in range(self.num_ancillia_qubits): 53 | self.circuit.append(cirq.H(self.output_qubits[i])) 54 | _pow_ = 2**(self.num_ancillia_qubits - 1 - i) 55 | #_pow_ = 2 ** (i) 56 | for k in range(self.num_input_qubits): 57 | print(self.U) 58 | self.circuit.append(self.U(self.output_qubits[i], self.input_qubits[k])**_pow_) 59 | 60 | 61 | def inv_qft(self): 62 | self._qft_ = QFT(qubits=self.output_qubits) 63 | self._qft_.qft_circuit() 64 | 65 | 66 | def simulate_circuit(self,circ): 67 | sim = cirq.Simulator() 68 | result = sim.simulate(circ) 69 | return result 70 | 71 | def main(num_input_state_qubits=1, 72 | num_ancillia_qubits=2, 73 | unitary_transform='Z', 74 | U=None,input_state='1'): 75 | 76 | _QP_ = quantum_phase_estimation(num_ancillia_qubits=num_ancillia_qubits, 77 | num_input_state_qubits=num_input_state_qubits, 78 | unitary_transform=unitary_transform, 79 | input_state=input_state) 80 | _QP_.phase_1_create_circuit_iter() 81 | 82 | _QP_.inv_qft() 83 | 84 | circuit = _QP_.circuit + _QP_._qft_.inv_circuit 85 | if len(_QP_.input_circuit) > 0: 86 | circuit = _QP_.input_circuit + circuit 87 | 88 | print(circuit) 89 | result = _QP_.simulate_circuit(circuit) 90 | print(result) 91 | 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /Chapter_4/listing4_3/listing_4.3_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/period_finding.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | fire 0.2.1 5 | elapsedtimer 0.4 6 | cirq version 0.8.2 7 | numpy version 1.19.0 8 | Trying period finding of element a = 7 mod 15 9 | Circuit after processing Qubit: 0 10 | 0: ───H─── 11 | Circuit after processing Qubit: 1 12 | 0: ───H───@──────────── 13 | │ 14 | 1: ───────@^-0.5───H─── 15 | Circuit after processing Qubit: 2 16 | ┌────────┐ 17 | 0: ───H───@──────────@─────────────────────── 18 | │ │ 19 | 1: ───────@^-0.5────H┼──────────@──────────── 20 | │ │ 21 | 2: ──────────────────@^-0.25────@^-0.5───H─── 22 | └────────┘ 23 | Circuit after processing Qubit: 3 24 | ┌────────┐ ┌──────────────┐ ┌────────┐ 25 | 0: ───H───@──────────@─────────────────@───────────────────────────────────── 26 | │ │ │ 27 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@─────────────────────── 28 | │ │ │ │ 29 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@──────────── 30 | │ │ │ 31 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H─── 32 | └────────┘ └──────────────┘ └────────┘ 33 | Circuit after qubit state swap: 34 | ┌────────┐ ┌──────────────┐ ┌────────┐ 35 | 0: ───H───@──────────@─────────────────@─────────────────────────────────────×─── 36 | │ │ │ │ 37 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@───────────────────×───┼─── 38 | │ │ │ │ │ │ 39 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@────────×───┼─── 40 | │ │ │ │ 41 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H───×─── 42 | └────────┘ └──────────────┘ └────────┘ 43 | ┌───────┐ ┌────────────┐ ┌───────┐ 44 | 0: ───H───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────×─────────────────────────────────@────────────@─────────@───────H─── 45 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 46 | 1: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────────────────────────────────────────────────────────────┼───×─────────────@──────────@────┼───────────H┼─────────@^0.5─────── 47 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 48 | 2: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────┼───×───@────────H┼──────────@^0.5┼────────────@^0.25──────────────── 49 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 50 | 3: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───×───H───@^0.5─────@^0.25──────────@^(1/8)──────────────────────────── 51 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 52 | 4: ───────┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼──────────────────────────────────────────────────────────────────────── 53 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 54 | 5: ───────┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼──────────────────────────────────────────────────────────────────────── 55 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 56 | 6: ───────×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼──────────────────────────────────────────────────────────────────────── 57 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 58 | 7: ───X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X──────────────────────────────────────────────────────────────────────── 59 | └───────┘ └────────────┘ └───────┘ 60 | Measurement Histogram Results follow 61 | {'1000': 266, '0000': 259, '0100': 241, '1100': 234} 62 | 63 | 64 | --------------------------------- 65 | Measured | Real | Rational 66 | State | Phase | Phase 67 | --------------------------------- 68 | 1000 | 0.5 | 1/2 69 | --------------------------------- 70 | 0000 | 0.0 | 0 71 | --------------------------------- 72 | 0100 | 0.25 | 1/4 73 | --------------------------------- 74 | 1100 | 0.75 | 3/4 75 | --------------------------------- 76 | 77 | 78 | Period of 7 mod 15 is: 4 79 | 80 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_4/listing4_3/period_finding.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from quantum_fourier_transform import QFT 3 | import numpy as np 4 | from fractions import Fraction 5 | print('cirq version',cirq.__version__) 6 | print('numpy version',np.__version__) 7 | 8 | def euclid_gcd(a, b): 9 | if b == 0: 10 | return a 11 | else: 12 | return euclid_gcd(b, a % b) 13 | 14 | 15 | """ 16 | The Period Finding Class computes the Period of functions 17 | of the form f(x) = a^x mod N using Quantum Phase Estimation 18 | Alternately we can say the algorithm finds the period of 19 | the element a mod N 20 | """ 21 | 22 | 23 | class PeriodFinding: 24 | 25 | def __init__(self, 26 | ancillia_precision_bits=4, 27 | func_domain_size=16, 28 | a=7, 29 | N=15 30 | ): 31 | 32 | self.ancillia_precision_bits = ancillia_precision_bits 33 | self.func_domain_size = func_domain_size 34 | self.num_output_qubits = self.ancillia_precision_bits 35 | self.num_input_qubits = int(np.log2(self.func_domain_size)) 36 | self.output_qubits = [cirq.LineQubit(i) for i in range(self.num_output_qubits)] 37 | self.input_qubits = [cirq.LineQubit(i) for i in range(self.num_output_qubits, 38 | self.num_output_qubits + self.num_input_qubits)] 39 | self.a = a 40 | 41 | self.N = N 42 | if self.N is None: 43 | self.N = func_domain_size - 1 44 | 45 | self.circuit = cirq.Circuit() 46 | 47 | def periodic_oracle(self, a, m, k): 48 | """ 49 | Implement an oracle U_a that takes in the state 50 | input state |y> and outputs |ay mod N> 51 | """ 52 | 53 | for i in range(m): 54 | if a in [2, 13]: 55 | self.circuit.append(cirq.SWAP(self.input_qubits[0], 56 | self.input_qubits[1]).controlled_by(self.output_qubits[k])) 57 | self.circuit.append(cirq.SWAP(self.input_qubits[1], 58 | self.input_qubits[2]).controlled_by(self.output_qubits[k])) 59 | self.circuit.append(cirq.SWAP(self.input_qubits[2], 60 | self.input_qubits[3]).controlled_by(self.output_qubits[k])) 61 | 62 | if a in [7, 8]: 63 | self.circuit.append(cirq.SWAP(self.input_qubits[2], 64 | self.input_qubits[3]).controlled_by(self.output_qubits[k])) 65 | self.circuit.append(cirq.SWAP(self.input_qubits[1], 66 | self.input_qubits[2]).controlled_by(self.output_qubits[k])) 67 | self.circuit.append(cirq.SWAP(self.input_qubits[0], 68 | self.input_qubits[1]).controlled_by(self.output_qubits[k])) 69 | if a in [4, 11]: 70 | self.circuit.append(cirq.SWAP(self.input_qubits[1], 71 | self.input_qubits[3]).controlled_by(self.output_qubits[k])) 72 | self.circuit.append(cirq.SWAP(self.input_qubits[0], 73 | self.input_qubits[2]).controlled_by(self.output_qubits[k])) 74 | 75 | if a in [7, 11, 13]: 76 | for j in range(self.num_input_qubits): 77 | self.circuit.append(cirq.X(self.input_qubits[j]).controlled_by(self.output_qubits[k])) 78 | 79 | def build_phase_1_period_finding_circuit(self): 80 | 81 | # Apply Hadamard Transform on each output qubit 82 | 83 | self.circuit.append([cirq.H(self.output_qubits[i]) for i in range(self.num_output_qubits)]) 84 | # Set input qubit to state |0001> 85 | self.circuit.append(cirq.X(self.input_qubits[-1])) 86 | 87 | if euclid_gcd(self.N, self.a) != 1: 88 | print(f"{self.a} is not co-prime to {self.N}") 89 | co_primes = [] 90 | for elem in range(2, self.N): 91 | if euclid_gcd(self.N, elem) == 1: 92 | co_primes.append(elem) 93 | print(f"Select a from the list of co-primes to {self.N}: {co_primes} ") 94 | 95 | else: 96 | print(f"Trying period finding of element a = {self.a} mod {self.N}") 97 | a = self.a 98 | 99 | for q in range(self.num_output_qubits): 100 | _pow_ = 2 ** (self.num_output_qubits - q - 1) 101 | self.periodic_oracle(a=a, m=_pow_, k=q) 102 | 103 | def inv_qft(self): 104 | """ 105 | Inverse Fourier Transform 106 | :return: 107 | IFT circuit 108 | """ 109 | self._qft_ = QFT(qubits=self.output_qubits) 110 | self._qft_.qft_circuit() 111 | 112 | def simulate_circuit(self, circ): 113 | """ 114 | Simulates the Period Finding Algorithm 115 | :param circ: Circuit to Simulate 116 | :return: Output results of Simulation 117 | """ 118 | circ.append([cirq.measure(*self.output_qubits, key='Z')]) 119 | sim = cirq.Simulator() 120 | result = sim.run(circ, repetitions=1000) 121 | out = dict(result.histogram(key='Z')) 122 | out_result = {} 123 | for k in out.keys(): 124 | new_key = "{0:b}".format(k) 125 | if len(new_key) < self.num_output_qubits: 126 | new_key = (self.num_output_qubits - len(new_key)) * '0' + new_key 127 | # print(new_key,k) 128 | out_result[new_key] = out[k] 129 | 130 | return out_result 131 | 132 | def measurement_to_period(self, results, denom_lim=15): 133 | # Convert a state to Phase as a binary fraction 134 | # |x_1,x_2....x_n> -> x_1*2^-1 + x_2*2^-2 + .. + x_n*2^-n 135 | measured_states = list(results.keys()) 136 | 137 | measured_phase = [] 138 | measured_phase_rational = [] 139 | 140 | for s in measured_states: 141 | phase = int(s, 2) / (2 ** len(s)) 142 | phase_rational = Fraction(phase).limit_denominator(denom_lim) 143 | measured_phase.append(phase) 144 | measured_phase_rational.append(phase_rational) 145 | print(f"---------------------------------") 146 | print(f"Measured | Real | Rational") 147 | print(f"State | Phase | Phase ") 148 | print(f"---------------------------------") 149 | for i in range(len(measured_phase)): 150 | print(f" {measured_states[i]} | {measured_phase[i]} | {measured_phase_rational[i]}") 151 | print(f"---------------------------------") 152 | print('\n') 153 | 154 | max_phase_rational = measured_phase_rational[np.argmax(np.array(measured_phase))] 155 | max_phase_numerator = max_phase_rational.numerator 156 | max_phase_denominator = max_phase_rational.denominator 157 | if (max_phase_denominator - max_phase_numerator) == 1: 158 | period = max_phase_denominator 159 | else: 160 | print(f"period cannot be determined") 161 | period = np.inf 162 | 163 | return period 164 | 165 | 166 | def period_finding_routine(func_domain_size=16, 167 | ancillia_precision_bits=4, 168 | a=7, 169 | N=15): 170 | """ 171 | 172 | :param func_domain_size: 173 | States in the Domain of the function. 174 | :param ancillia_precision_bits: 175 | Precision bits for Phase Measurement 176 | :param N: Generally func_domain_size - 1 177 | :param a: Element whose periodicity mod N 178 | is to be computed 179 | :return: Period r of the element a mod N 180 | """ 181 | 182 | _PF_ = PeriodFinding(ancillia_precision_bits=ancillia_precision_bits, 183 | func_domain_size=func_domain_size, 184 | a=a, 185 | N=N) 186 | _PF_.build_phase_1_period_finding_circuit() 187 | 188 | _PF_.inv_qft() 189 | 190 | circuit = _PF_.circuit + _PF_._qft_.inv_circuit 191 | 192 | print(circuit) 193 | result = _PF_.simulate_circuit(circuit) 194 | print(f"Measurement Histogram Results follow") 195 | print(result) 196 | print('\n') 197 | period = _PF_.measurement_to_period(result, denom_lim=_PF_.N) 198 | print(f"Period of {a} mod {N} is: {period} ") 199 | return period 200 | 201 | 202 | if __name__ == '__main__': 203 | period_finding_routine() 204 | -------------------------------------------------------------------------------- /Chapter_4/listing4_4/factoring.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from period_finding import period_finding_routine 3 | from period_finding import euclid_gcd 4 | import numpy as np 5 | print('numpy version',np.__version__) 6 | 7 | 8 | class Factoring: 9 | """" 10 | Find the factorization of number N = p*q 11 | where p and q are prime to each other 12 | """ 13 | 14 | def __init__(self, N): 15 | self.N = N 16 | 17 | def factoring(self): 18 | 19 | prev_trials_for_a = [] 20 | factored = False 21 | 22 | while not factored: 23 | new_a_found = False 24 | 25 | # Sample a new "a" not already sampled 26 | while not new_a_found: 27 | a = np.random.randint(2, self.N) 28 | if a not in prev_trials_for_a: 29 | new_a_found = True 30 | 31 | # "a" not co-prime to N are not periodic 32 | if euclid_gcd(self.N, a) == 1: 33 | # Call the period_finding_routine from PeriodFinding 34 | # Implementation 35 | period = period_finding_routine(a=a, N=self.N) 36 | 37 | # Check if the period is even. 38 | # It period even (a^(r/2))^2 = 1 mod (N) 39 | # for integer a^(r/2) 40 | if period % 2 == 0: 41 | 42 | # Check if a^(r/2) != +/- 1 mod(N) 43 | # if condition satisfied number gets 44 | # factorized in this iteration 45 | if a ** (period / 2) % self.N not in [+1, -1]: 46 | prime_1 = euclid_gcd(self.N, a ** (period / 2) + 1) 47 | prime_2 = euclid_gcd(self.N, a ** (period / 2) - 1) 48 | factored = True 49 | return prime_1, prime_2 50 | else: 51 | # If we have exhausted all "a"s and 52 | # still havent got prime factors something 53 | # is off 54 | if len(prev_trials_for_a) == self.N - 2: 55 | raise ValueError(f"Check input is a product of two primes") 56 | 57 | 58 | if __name__ == '__main__': 59 | 60 | fp = Factoring(N=15) 61 | factor_1, factor_2 = fp.factoring() 62 | 63 | if factor_1 is not None: 64 | print(f"The factors of {fp.N} are {factor_1} and {factor_2}") 65 | else: 66 | print(f"Error in factoring") 67 | -------------------------------------------------------------------------------- /Chapter_4/listing4_4/listing_4.4_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/factoring.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | fire 0.2.1 5 | elapsedtimer 0.4 6 | cirq version 0.8.2 7 | numpy version 1.19.0 8 | numpy version 1.19.0 9 | Trying period finding of element a = 7 mod 15 10 | Circuit after processing Qubit: 0 11 | 0: ───H─── 12 | Circuit after processing Qubit: 1 13 | 0: ───H───@──────────── 14 | │ 15 | 1: ───────@^-0.5───H─── 16 | Circuit after processing Qubit: 2 17 | ┌────────┐ 18 | 0: ───H───@──────────@─────────────────────── 19 | │ │ 20 | 1: ───────@^-0.5────H┼──────────@──────────── 21 | │ │ 22 | 2: ──────────────────@^-0.25────@^-0.5───H─── 23 | └────────┘ 24 | Circuit after processing Qubit: 3 25 | ┌────────┐ ┌──────────────┐ ┌────────┐ 26 | 0: ───H───@──────────@─────────────────@───────────────────────────────────── 27 | │ │ │ 28 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@─────────────────────── 29 | │ │ │ │ 30 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@──────────── 31 | │ │ │ 32 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H─── 33 | └────────┘ └──────────────┘ └────────┘ 34 | Circuit after qubit state swap: 35 | ┌────────┐ ┌──────────────┐ ┌────────┐ 36 | 0: ───H───@──────────@─────────────────@─────────────────────────────────────×─── 37 | │ │ │ │ 38 | 1: ───────@^-0.5────H┼───────────@─────┼─────────────@───────────────────×───┼─── 39 | │ │ │ │ │ │ 40 | 2: ──────────────────@^-0.25─────@^-0.5┼────────────H┼──────────@────────×───┼─── 41 | │ │ │ │ 42 | 3: ────────────────────────────────────@^(-1/8)──────@^-0.25────@^-0.5───H───×─── 43 | └────────┘ └──────────────┘ └────────┘ 44 | ┌───────┐ ┌────────────┐ ┌───────┐ 45 | 0: ───H───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────×─────────────────────────────────@────────────@─────────@───────H─── 46 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 47 | 1: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────────────────────────────────────────────────────────────┼───×─────────────@──────────@────┼───────────H┼─────────@^0.5─────── 48 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 49 | 2: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───@───@───@───@───@───@───@───────────────────────────────┼───×───@────────H┼──────────@^0.5┼────────────@^0.25──────────────── 50 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 51 | 3: ───H───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───@───@───@───@───@───@───@───×───H───@^0.5─────@^0.25──────────@^(1/8)──────────────────────────── 52 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 53 | 4: ───────┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼───┼───┼───×───X───┼───┼───┼──────────────────────────────────────────────────────────────────────── 54 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 55 | 5: ───────┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼───┼───×───×───────X───┼───┼──────────────────────────────────────────────────────────────────────── 56 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 57 | 6: ───────×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼───×───×───────────────X───┼──────────────────────────────────────────────────────────────────────── 58 | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 59 | 7: ───X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X───×───────────────────────X──────────────────────────────────────────────────────────────────────── 60 | └───────┘ └────────────┘ └───────┘ 61 | Measurement Histogram Results follow 62 | {'0000': 256, '0100': 239, '1000': 243, '1100': 262} 63 | 64 | 65 | --------------------------------- 66 | Measured | Real | Rational 67 | State | Phase | Phase 68 | --------------------------------- 69 | 0000 | 0.0 | 0 70 | --------------------------------- 71 | 0100 | 0.25 | 1/4 72 | --------------------------------- 73 | 1000 | 0.5 | 1/2 74 | --------------------------------- 75 | 1100 | 0.75 | 3/4 76 | --------------------------------- 77 | 78 | 79 | Period of 7 mod 15 is: 4 80 | The factors of 15 are 5.0 and 3.0 81 | 82 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_5/listing5_1/EigenRotation.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import math 3 | 4 | 5 | 6 | class EigenValueRotation(cirq.Gate): 7 | """ 8 | EigenValueRotation rotates the an 9 | """ 10 | 11 | def __init__(self, num_qubits, C, t): 12 | super(EigenRotation, self) 13 | self._num_qubits = num_qubits 14 | self.C = C 15 | self.t = t 16 | self.N = 2**(num_qubits-1) 17 | 18 | def num_qubits(self): 19 | return self._num_qubits 20 | 21 | def _decompose_(self, qubits): 22 | for k in range(self.N): 23 | if k == 0: 24 | k_base = 2**self.N - 1 25 | else: 26 | k_base = k - 1 27 | kGate = self._ancilla_rotation(k) 28 | # xor's 1 bits correspond to X gate positions. 29 | xor = k ^ k_base 30 | Gate_apply = [] 31 | for q in qubits[-2::-1]: 32 | # Place X gates 33 | if xor % 2 == 1: 34 | yield cirq.X(q) 35 | Gate_apply.append('X') 36 | else: 37 | Gate_apply.append(' ') 38 | xor >>= 1 39 | 40 | # Build controlled ancilla rotation 41 | kGate = cirq.ControlledGate(kGate) 42 | 43 | yield kGate(*qubits) 44 | print(Gate_apply) 45 | 46 | def _ancilla_rotation(self, k): 47 | if k == 0: 48 | k = self.N 49 | theta = 2*math.asin(self.C * self.N * self.t / (2*math.pi * k)) 50 | return cirq.ry(theta) 51 | def main(register_size=4): 52 | ancilla = cirq.LineQubit(0) 53 | register = [cirq.LineQubit(i + 1) for i in range(register_size)] 54 | print(register) 55 | memory = cirq.LineQubit(register_size + 1) 56 | t = 0.358166*math.pi 57 | C = 2 * math.pi / (2 ** register_size * t) 58 | print(math.asin(C*t)) 59 | circuit = cirq.Circuit() 60 | #circuit.append(cirq.H(register[i]) for i in range(register_size)) 61 | circuit.append(cirq.X(register[-3])) 62 | circuit.append(EigenRotation(register_size + 1, C, t)(*(register + [ancilla]))) 63 | #circuit.append(cirq.measure(*(register + [ancilla]),key='m')) 64 | sim = cirq.Simulator() 65 | result = sim.simulate(circuit) 66 | #result = sim.run(circuit,repetitions=1000) 67 | print(result) 68 | print(circuit) 69 | #print(result.histogram(key='m')) 70 | 71 | 72 | 73 | if __name__ == '__main__': 74 | main() -------------------------------------------------------------------------------- /Chapter_5/listing5_1/EigenValueInversion.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | import math 4 | 5 | class EigenValueInversion(cirq.Gate): 6 | """ 7 | Rotates the ancilla bit around the Y axis 8 | by an angle theta = 2* sin inv(C/eigen value) 9 | corresponding to each Eigen value state basis |eigen value>. 10 | This rotation brings the factor (1/eigen value) in 11 | the amplitude of the basis |1> of the ancilla qubit 12 | """ 13 | 14 | def __init__(self, num_qubits, C, t): 15 | super(EigenValueInversion, self) 16 | self._num_qubits = num_qubits 17 | self.C = C 18 | self.t = t 19 | # No of possible Eigen values self.N 20 | self.N = 2**(num_qubits-1) 21 | 22 | def num_qubits(self): 23 | return self._num_qubits 24 | 25 | def _decompose_(self, qubits): 26 | """ 27 | Apply the Rotation Gate for each possible 28 | # Eigen value corresponding to the Eigen 29 | # value basis state. For each input basis state 30 | # only the Rotation gate corresponding to it would be 31 | # applied to the ancilla qubit 32 | """ 33 | base_state = 2**self.N - 1 34 | 35 | for eig_val_state in range(self.N): 36 | eig_val_gate = self._ancilla_rotation(eig_val_state) 37 | 38 | if (eig_val_state != 0): 39 | base_state = eig_val_state - 1 40 | # XOR between successive eigen value states to 41 | # determine the qubits to flip 42 | qubits_to_flip = eig_val_state ^ base_state 43 | 44 | # Apply the flips to the qubits as determined 45 | # by the XOR operation 46 | 47 | for q in qubits[-2::-1]: 48 | 49 | if qubits_to_flip % 2 == 1: 50 | yield cirq.X(q) 51 | qubits_to_flip >>= 1 52 | 53 | # Build controlled ancilla rotation 54 | eig_val_gate = cirq.ControlledGate(eig_val_gate) 55 | # Controlled Rotation Gate with the 1st (num_qubits -1) qubits as 56 | # control qubit and the last qubit as the target qubit(ancilla) 57 | 58 | yield eig_val_gate(*qubits) 59 | 60 | def _ancilla_rotation(self, eig_val_state): 61 | if eig_val_state == 0: 62 | eig_val_state = self.N 63 | theta = 2*math.asin(self.C * self.N * self.t / (2*np.pi * eig_val_state)) 64 | # Rotation around the y axis by angle theta 65 | return cirq.ry(theta) 66 | 67 | def test(num_qubits=5): 68 | num_input_qubits = num_qubits - 1 69 | # Define ancila qubit 70 | ancilla_qubit = cirq.LineQubit(0) 71 | input_qubits = [cirq.LineQubit(i) for i in range(1, num_qubits)] 72 | #Define a circuit 73 | circuit = cirq.Circuit() 74 | # Set the state to equal superposition of |00000> and |00001> 75 | circuit.append(cirq.X(input_qubits[-4])) 76 | # t is set to 1 77 | t = 0.358166*np.pi 78 | # Set C to the smallest Eigen value that can be measured 79 | C = 2 * np.pi / ((2 ** num_input_qubits) * t) 80 | circuit.append(EigenValueInversion(num_qubits,C,t)(*(input_qubits + [ancilla_qubit]))) 81 | # Simulate circuit 82 | sim = cirq.Simulator() 83 | result = sim.simulate(circuit) 84 | print(result) 85 | 86 | 87 | if __name__ == '__main__': 88 | test(num_qubits=5) 89 | 90 | -------------------------------------------------------------------------------- /Chapter_5/listing5_1/Eigendiv.py: -------------------------------------------------------------------------------- 1 | imp -------------------------------------------------------------------------------- /Chapter_5/listing5_1/HHL.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from hamiltonian_simulator import HamiltonianSimulation 3 | from QuantumPhaseEstimation import QuantumPhaseEstimation 4 | from EigenValueInversion import EigenValueInversion 5 | import numpy as np 6 | import sympy 7 | 8 | 9 | class HHL: 10 | 11 | def __init__(self, hamiltonian, initial_state=None, initial_state_transforms=None, qpe_register_size=4, C=None, t=1): 12 | """ 13 | :param hamiltonian: Hamiltonian to Simulate 14 | :param C: hyper parameter to Eigen Value Inversion 15 | :param t: Time for which Hamiltonian is simulated 16 | :param initial_state: |b> 17 | """ 18 | self.hamiltonian = hamiltonian 19 | self.initial_state = initial_state 20 | self.initial_state_transforms = initial_state_transforms 21 | self.qpe_register_size = qpe_register_size 22 | self.C = C 23 | self.t = t 24 | 25 | const = self.t/np.pi 26 | self.t = const*np.pi 27 | if self.C is None: 28 | self.C = 2*np.pi / (2**self.qpe_register_size * t) 29 | 30 | 31 | def build_hhl_circuit(self): 32 | self.circuit = cirq.Circuit() 33 | self.ancilla_qubit = cirq.LineQubit(0) 34 | self.qpe_register = [cirq.LineQubit(i) for i in range(1, self.qpe_register_size+1)] 35 | if self.initial_state is None: 36 | self.initial_state_size = int(np.log2(self.hamiltonian.shape[0])) 37 | if self.initial_state_size == 1: 38 | self.initial_state = [cirq.LineQubit(self.qpe_register_size + 1)] 39 | else: 40 | self.initial_state = [cirq.LineQubit(i) for i in range(self.qpe_register_size + 1, 41 | self.qpe_register_size + 1 + self.initial_state_size)] 42 | 43 | for op in list(self.initial_state_transforms): 44 | print(op) 45 | self.circuit.append(op(self.initial_state[0])) 46 | 47 | # Define Unitary Operator simulating the Hamiltonian 48 | self.U = HamiltonianSimulation(_H_=self.hamiltonian, t=self.t) 49 | # Perform Quantum Phase Estimation 50 | _qpe_ = QuantumPhaseEstimation(input_qubits=self.initial_state, 51 | output_qubits=self.qpe_register, U=self.U) 52 | _qpe_.circuit() 53 | print(dir(_qpe_)) 54 | print('CIRCUIT',_qpe_.circuit) 55 | self.circuit += _qpe_.circuit 56 | # Perform EigenValue Inversion 57 | _eig_val_inv_ = EigenValueInversion(num_qubits=self.qpe_register_size + 1, C=self.C, t=self.t) 58 | self.circuit.append(_eig_val_inv_(*(self.qpe_register + [self.ancilla_qubit]))) 59 | #Uncompute the qpe_register to |0..0> state 60 | print(self.circuit) 61 | #print(_qpe_.circuit**(-1)) 62 | self.circuit.append(_qpe_.circuit**(-1)) 63 | self.circuit.append(cirq.measure(self.ancilla_qubit,key='a')) 64 | self.circuit.append([ 65 | cirq.PhasedXPowGate( 66 | exponent=sympy.Symbol('exponent'), 67 | phase_exponent=sympy.Symbol('phase_exponent'))(*self.initial_state), 68 | cirq.measure(*self.initial_state, key='m') 69 | ]) 70 | 71 | #sim = cirq.Simulator() 72 | #results = sim.simulate(self.circuit) 73 | #print(results) 74 | 75 | def simulate(self): 76 | simulator = cirq.Simulator() 77 | 78 | # Cases for measuring X, Y, and Z (respectively) on the memory qubit. 79 | params = [{ 80 | 'exponent': 0.5, 81 | 'phase_exponent': -0.5 82 | }, { 83 | 'exponent': 0.5, 84 | 'phase_exponent': 0 85 | }, { 86 | 'exponent': 0, 87 | 'phase_exponent': 0 88 | }] 89 | 90 | results = simulator.run_sweep(self.circuit, params, repetitions=5000) 91 | 92 | for label, result in zip(('X', 'Y', 'Z'), list(results)): 93 | # Only select cases where the ancilla is 1. 94 | # TODO: optimize using amplitude amplification algorithm. 95 | # Github issue: https://github.com/quantumlib/Cirq/issues/2216 96 | expectation = 1 - 2 * np.mean( 97 | result.measurements['m'][result.measurements['a'] == 1]) 98 | print('{} = {}'.format(label, expectation)) 99 | 100 | def main(): 101 | """ 102 | Simulates HHL with matrix input, and outputs Pauli observables of the 103 | resulting qubit state |x>. 104 | Expected observables are calculated from the expected solution |x>. 105 | """ 106 | 107 | # Eigendecomposition: 108 | # (4.537, [-0.971555, -0.0578339+0.229643j]) 109 | # (0.349, [-0.236813, 0.237270-0.942137j]) 110 | # |b> = (0.64510-0.47848j, 0.35490-0.47848j) 111 | # |x> = (-0.0662724-0.214548j, 0.784392-0.578192j) 112 | A = np.array([[4.30213466 - 6.01593490e-08j, 113 | 0.23531802 + 9.34386156e-01j], 114 | [0.23531882 - 9.34388383e-01j, 115 | 0.58386534 + 6.01593489e-08j]]) 116 | t = 0.358166 * math.pi 117 | register_size = 4 118 | input_prep_gates = [cirq.rx(1.276359), cirq.rz(1.276359)] 119 | expected = (0.144130, 0.413217, -0.899154) 120 | 121 | # Set C to be the smallest eigenvalue that can be represented by the 122 | # circuit. 123 | C = 2 * math.pi / (2 ** register_size * t) 124 | 125 | # Simulate circuit 126 | print("Expected observable outputs:") 127 | print("X =", expected[0]) 128 | print("Y =", expected[1]) 129 | print("Z =", expected[2]) 130 | print("Actual: ") 131 | simulate(hhl_circuit(A, C, t, register_size, *input_prep_gates)) 132 | 133 | 134 | if __name__ == '__main__': 135 | A = np.array([[4.30213466 - 6.01593490e-08j, 136 | 0.23531802 + 9.34386156e-01j], 137 | [0.23531882 - 9.34388383e-01j, 138 | 0.58386534 + 6.01593489e-08j]]) 139 | t = 0.358166 * np.pi 140 | C = None 141 | qpe_register_size = 4 142 | initial_state_transforms = [cirq.rx(1.276359), cirq.rz(1.276359)] 143 | _hhl_ = HHL(hamiltonian=A,initial_state_transforms=initial_state_transforms,qpe_register_size=4) 144 | _hhl_.build_hhl_circuit() 145 | _hhl_.simulate() 146 | 147 | -------------------------------------------------------------------------------- /Chapter_5/listing5_1/QuantumPhaseEstimation.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from quantum_fourier_transform import QFT 3 | 4 | 5 | 6 | class ControlledUnitary(cirq.Gate): 7 | 8 | def __init__(self, num_qubits, num_input_qubits, U): 9 | self._num_qubits = num_qubits 10 | self.num_input_qubits = num_input_qubits 11 | self.num_control_qubits = num_qubits - self.num_input_qubits 12 | self.U = U 13 | 14 | def num_qubits(self) -> int: 15 | return self._num_qubits 16 | 17 | def _decompose_(self, qubits): 18 | qubits = list(qubits) 19 | input_state_qubit = qubits[:self.num_input_qubits] 20 | control_qubits = qubits[self.num_input_qubits:] 21 | 22 | for i,q in enumerate(control_qubits): 23 | _pow_ = 2 ** (self.num_control_qubits - i - 1) 24 | #yield self.U(q, *input_state_qubit)**_pow_ 25 | yield cirq.ControlledGate(self.U**_pow_)(q, *input_state_qubit) 26 | 27 | 28 | 29 | class QuantumPhaseEstimation: 30 | 31 | def __init__(self, 32 | U, 33 | input_qubits, 34 | num_output_qubits=None, 35 | output_qubits=None, initial_circuit=[],measure_or_sim=False): 36 | 37 | 38 | self.U = U 39 | self.input_qubits = input_qubits 40 | self.num_input_qubits = len(self.input_qubits) 41 | self.initial_circuit = initial_circuit 42 | self.measure_or_sim = measure_or_sim 43 | 44 | 45 | if output_qubits is not None: 46 | self.output_qubits = output_qubits 47 | self.num_output_qubits = len(self.output_qubits) 48 | 49 | elif num_output_qubits is not None: 50 | self.num_output_qubits = num_output_qubits 51 | self.output_qubits = [cirq.LineQubit(i) for i 52 | in range(self.num_input_qubits,self.num_input_qubits+self.num_output_qubits)] 53 | 54 | else: 55 | raise ValueError("Alteast one of num_output_qubits or output_qubits to be specified") 56 | 57 | self.num_qubits = self.num_input_qubits+self.num_output_qubits 58 | 59 | 60 | def inv_qft(self): 61 | self._qft_= QFT(qubits=self.output_qubits) 62 | self._qft_.qft_circuit() 63 | print('print',self._qft_) 64 | self.QFT_inv_circuit = self._qft_.inv_circuit 65 | 66 | 67 | def circuit(self): 68 | self.circuit = cirq.Circuit() 69 | self.circuit.append(cirq.H.on_each(*self.output_qubits)) 70 | print(self.circuit) 71 | print(self.output_qubits) 72 | print(self.input_qubits) 73 | print((self.output_qubits + self.input_qubits)) 74 | self.qubits = list(self.input_qubits + self.output_qubits) 75 | self.circuit.append(ControlledUnitary(self.num_qubits, 76 | self.num_input_qubits,self.U)(*self.qubits)) 77 | self.inv_qft() 78 | self.circuit.append(self.QFT_inv_circuit) 79 | if len(self.initial_circuit) > 0 : 80 | self.circuit = self.initial_circuit + self.circuit 81 | 82 | def measure(self): 83 | self.circuit.append(cirq.measure(*self.output_qubits,key='m')) 84 | 85 | 86 | def simulate_circuit(self,measure=True): 87 | sim = cirq.Simulator() 88 | if measure == False: 89 | result = sim.simulate(self.circuit) 90 | else: 91 | result = sim.run(self.circuit, repetitions=1000).histogram(key='m') 92 | return result 93 | 94 | 95 | 96 | def main(num_input_state_qubits=1, 97 | num_output_qubits=2, 98 | unitary_transform='Z', 99 | U=None, input_state='1', 100 | measure_or_sim=True): 101 | 102 | pauli_operators_dict = {'I':cirq.I, 103 | 'X':cirq.CX, 104 | 'Y':cirq.Y, 105 | 'Z':cirq.CZ} 106 | if U is None: 107 | U = pauli_operators_dict[unitary_transform] 108 | 109 | input_qubit = [cirq.LineQubit(i) for i in range(num_input_state_qubits)] 110 | if input_state == '1': 111 | initial_circuit = cirq.Circuit() 112 | initial_circuit.append(cirq.Ry(3.14).on(input_qubit[-1])) 113 | 114 | _QP_ = QuantumPhaseEstimation(U=U, 115 | input_qubits=input_qubit, 116 | num_output_qubits=num_output_qubits, 117 | initial_circuit=initial_circuit, 118 | measure_or_sim=measure_or_sim) 119 | _QP_.circuit() 120 | if _QP_.measure_or_sim: 121 | _QP_.measure() 122 | result = _QP_.simulate_circuit(measure=_QP_.measure_or_sim) 123 | print(result) 124 | 125 | if __name__ == '__main__': 126 | main() 127 | -------------------------------------------------------------------------------- /Chapter_5/listing5_1/hamiltonian_simulator.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | 4 | 5 | class HamiltonianSimulation(cirq.EigenGate, cirq.SingleQubitGate): 6 | """ 7 | This class simulates the Hamiltonian evolution for 8 | a Single qubit. For a Hamiltonian given by H the Unitary Operator 9 | simulated for time t is given by e**(-iHt). The Eigen vectors of the 10 | Hamiltonian H and the Unitary operator. An eigen value of lambda for 11 | the Hamiltonian H corresponds to the Eigen value of e**(-i*lambda*t) 12 | 13 | The EigenGate takes in an Eigenvalue of the form e**(i*pi*theta) as theta 14 | abd the corresponding Eigen vector as |v> 53 | ['QFT_inv_circuit', 'U', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_qft_', 'circuit', 'initial_circuit', 'input_qubits', 'inv_qft', 'measure', 'measure_or_sim', 'num_input_qubits', 'num_output_qubits', 'num_qubits', 'output_qubits', 'qubits', 'simulate_circuit'] 54 | CIRCUIT ┌───────┐ ┌────────────┐ ┌───────┐ 55 | 1: ───H───#2────────────────────────────────────────────────────────────────────×─────────────────────────────────@────────────@─────────@───────H─── 56 | │ │ │ │ │ 57 | 2: ───H───#3────────────────────────────────────────────────────────────────────┼───×─────────────@──────────@────┼───────────H┼─────────@^0.5─────── 58 | │ │ │ │ │ │ │ 59 | 3: ───H───#4────────────────────────────────────────────────────────────────────┼───×───@────────H┼──────────@^0.5┼────────────@^0.25──────────────── 60 | │ │ │ │ │ 61 | 4: ───H───#5────────────────────────────────────────────────────────────────────×───H───@^0.5─────@^0.25──────────@^(1/8)──────────────────────────── 62 | │ 63 | 5: ─────────────────────────────────────────────────────────────────────────────── 64 | └───────┘ └────────────┘ └───────┘ 65 | ┌───────┐ ┌────────────┐ ┌───────┐ 66 | 0: ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────#5─────────────────────────────────────────────────────────────────── 67 | │ 68 | 1: ─────────────────────────────H───#2────────────────────────────────────────────────────────────────────×─────────────────────────────────@────────────@─────────@───────H────── 69 | │ │ │ │ │ │ 70 | 2: ─────────────────────────────H───#3────────────────────────────────────────────────────────────────────┼───×─────────────@──────────@────┼───────────H┼─────────@^0.5───────#2─────────────────────────────────────────────────────────────────── 71 | │ │ │ │ │ │ │ │ 72 | 3: ─────────────────────────────H───#4────────────────────────────────────────────────────────────────────┼───×───@────────H┼──────────@^0.5┼────────────@^0.25────────────────#3─────────────────────────────────────────────────────────────────── 73 | │ │ │ │ │ │ 74 | 4: ─────────────────────────────H───#5────────────────────────────────────────────────────────────────────×───H───@^0.5─────@^0.25──────────@^(1/8)────────────────────────────#4─────────────────────────────────────────────────────────────────── 75 | │ 76 | 5: ───Rx(0.406π)───Rz(0.406π)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 77 | └───────┘ └────────────┘ └───────┘ 78 | X = 0.21283255086071984 79 | Y = 0.3746130030959752 80 | Z = -0.8580246913580247 81 | 82 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_5/listing5_2/listing_5.2_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/swap_test.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | 2 5 | H 6 | [cirq.LineQubit(1), cirq.LineQubit(2)] 7 | 0: ───H───@───@───H───M('m')─── 8 | │ │ 9 | 1: ───H───×───┼──────────────── 10 | │ │ 11 | 2: ───H───┼───×──────────────── 12 | │ │ 13 | 3: ───I───×───┼──────────────── 14 | │ 15 | 4: ───I───────×──────────────── 16 | Probability of zero state 0.632 17 | Sq of Dot product 0.264 18 | Dot product 0.5138093031466052 19 | 20 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_5/listing5_2/swap_test.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq version',cirq.__version__) 4 | print('numpy version',np.__version__) 5 | 6 | 7 | class SwapTest: 8 | def __init__(self,prepare_input_states=None,input_state_dim=None,nq=0,measure=False,copies=1000): 9 | self.nq = nq 10 | self.prepare_input_states = prepare_input_states 11 | self.input_state_dim = input_state_dim 12 | if input_state_dim is not None: 13 | self.num_qubits_input_states = int(np.log2(self.input_state_dim)) 14 | print(self.num_qubits_input_states) 15 | 16 | 17 | self.measure = measure 18 | self.copies = copies 19 | self.ancilla_qubit = cirq.LineQubit(self.nq) 20 | self.nq += 1 21 | 22 | 23 | if self.prepare_input_states is not None: 24 | if input_state_dim is None: 25 | raise ValueError("Please enter a valid dimension for input states to compare") 26 | else: 27 | self.num_qubits_input_states = int(np.log2(self.input_state_dim)) 28 | self.input_1 = [cirq.LineQubit(i) for i in range(self.nq, self.nq +self.num_qubits_input_states)] 29 | self.nq += self.num_qubits_input_states 30 | self.input_2 = [cirq.LineQubit(i) for i in range(self.nq, 31 | self.nq + self.num_qubits_input_states)] 32 | self.nq += self.num_qubits_input_states 33 | 34 | def build_circuit(self,input_1=None,input_2=None,input_1_transforms=None,input_2_transforms=None): 35 | 36 | self.circuit = cirq.Circuit() 37 | if input_1 is not None: 38 | self.input_1 = input_1 39 | if input_2 is not None: 40 | self.input_2 = input_2 41 | if input_1_transforms is not None: 42 | for op in input_1_transforms: 43 | print(op) 44 | print(self.input_1) 45 | self.circuit.append(op.on_each(self.input_1)) 46 | if input_2_transforms is not None: 47 | for op in input_2_transforms: 48 | self.circuit.append(op.on_each(self.input_2)) 49 | 50 | 51 | # Ancilla in + state 52 | self.circuit.append(cirq.H(self.ancilla_qubit)) 53 | # Swap states conditoned on the ancilla 54 | for i in range(len(self.input_1)): 55 | self.circuit.append(cirq.CSWAP(self.ancilla_qubit, self.input_1[i], 56 | self.input_2[i])) 57 | # Hadamard Transform on Ancilla 58 | self.circuit.append(cirq.H(self.ancilla_qubit)) 59 | if self.measure: 60 | self.circuit.append(cirq.measure(self.ancilla_qubit,key='m')) 61 | print(self.circuit) 62 | 63 | def simulate(self): 64 | sim = cirq.Simulator() 65 | results = sim.run(self.circuit,repetitions=self.copies) 66 | results = results.histogram(key='m') 67 | prob_0 = results[0]/self.copies 68 | dot_product_sq = 2*(max(prob_0 - .5,0)) 69 | return prob_0,dot_product_sq 70 | 71 | def main(prepare_input_states=True,input_state_dim=4, 72 | input_1_transforms=[cirq.H], 73 | input_2_transforms=[cirq.I],measure=True,copies=1000): 74 | st = SwapTest(prepare_input_states=prepare_input_states,input_state_dim=input_state_dim,measure=measure,copies=copies) 75 | st.build_circuit(input_1_transforms=input_1_transforms, 76 | input_2_transforms=input_2_transforms) 77 | prob_0, dot_product_sq = st.simulate() 78 | print(f"Probability of zero state {prob_0}") 79 | print(f"Sq of Dot product {dot_product_sq}") 80 | print(f"Dot product {dot_product_sq**0.5}") 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /Chapter_5/listing5_3/listing_5.3_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/quantum_eucledian.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | cirq version 0.8.2 5 | numpy version 1.19.0 6 | length 1 7 | 2 8 | 1.5707963267948968 9 | 2 10 | [cirq.LineQubit(4), cirq.LineQubit(5)] 11 | 0: ───────×─────────── 12 | │ 13 | 1: ───────┼───×─────── 14 | │ │ 15 | 4: ───────×───┼─────── 16 | │ │ 17 | 5: ───────┼───×─────── 18 | │ │ 19 | 6: ───H───@───@───H─── 20 | 0: ───H──────────@───X───@───@───X───@───────×──────────────────── 21 | │ │ │ │ │ 22 | 1: ──────────────×───────×───┼───────┼───────┼───×──────────────── 23 | │ │ │ │ │ │ 24 | 2: ───H──────────┼───────×───┼───────H───────┼───┼──────────────── 25 | │ │ │ │ 26 | 3: ───H──────────×───────────H───────────────┼───┼──────────────── 27 | │ │ 28 | 4: ───Ry(0.5π)───Z───────────────────────────×───┼──────────────── 29 | │ │ 30 | 5: ──────────────────────────────────────────┼───×──────────────── 31 | │ │ 32 | 6: ──────────────────────────────────────H───@───@───H───M('k')─── 33 | {1: 50068, 0: 49932} 34 | 0.49932 35 | Euclidean distance 0 36 | -------------------------------------------------------------------------------- /Chapter_5/listing5_3/quantum_eucledian.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | import math 4 | from swap_test import SwapTest 5 | print('cirq version', cirq.__version__) 6 | print('numpy version', np.__version__) 7 | 8 | class euclidean_distance: 9 | def __init__(self, input_state_dim, prepare_input_states=False,copies=10000): 10 | self.prepare_input_states = prepare_input_states 11 | self.input_state_dim = input_state_dim 12 | self.copies = copies 13 | self.nq = 0 14 | self.control_qubit = cirq.LineQubit(0) 15 | self.nq += 1 16 | 17 | self.num_qubits_per_state = int(np.log2(self.input_state_dim)) 18 | self.state_store_qubits = [cirq.LineQubit(i) for i 19 | in range(self.nq, self.nq +self.num_qubits_per_state)] 20 | self.nq += self.num_qubits_per_state 21 | 22 | 23 | 24 | if self.prepare_input_states: 25 | 26 | self.input_1 = [cirq.LineQubit(i) for i in range(self.nq, self.nq + self.num_qubits_per_state)] 27 | self.nq += self.num_qubits_per_state 28 | 29 | self.input_2 = [cirq.LineQubit(i) for i in range(self.nq, self.nq + self.num_qubits_per_state)] 30 | self.nq += self.num_qubits_per_state 31 | 32 | 33 | self.other_state_qubits = [cirq.LineQubit(i) for i in range(self.nq, self.nq + 1 + self.num_qubits_per_state)] 34 | self.nq += 1 + self.num_qubits_per_state 35 | self.circuit = cirq.Circuit() 36 | 37 | def dist_circuit(self, input_1_norm=1, input_2_norm=1, input_1=None, 38 | input_2=None, input_1_transforms=None, input_2_transforms=None, 39 | input_1_circuit=None, 40 | input_2_circuit=None): 41 | 42 | self.input_1_norm = input_1_norm 43 | self.input_2_norm = input_2_norm 44 | self.input_1_circuit = input_1_circuit 45 | self.input_2_circuit = input_2_circuit 46 | 47 | if input_1 is not None: 48 | self.input_1 = input_1 49 | 50 | if input_2 is not None: 51 | self.input_2 = input_2 52 | 53 | 54 | if input_1_transforms is not None: 55 | 56 | self.input_1_circuit = [] 57 | 58 | for op in input_1_transforms: 59 | #print(op) 60 | #print(self.input_1) 61 | self.circuit.append(op.on_each(self.input_1)) 62 | self.input_1_circuit.append(op.on_each(self.input_1)) 63 | if input_2_transforms is not None: 64 | self.input_2_circuit = [] 65 | for op in input_2_transforms: 66 | self.circuit.append(op.on_each(self.input_2)) 67 | self.input_2_circuit.append(op.on_each(self.input_2)) 68 | 69 | self.input_1_uncompute = cirq.inverse(self.input_1_circuit) 70 | self.input_2_uncompute = cirq.inverse(self.input_2_circuit) 71 | 72 | # Create the required state 1 73 | 74 | self.circuit.append(cirq.H(self.control_qubit)) 75 | print("length",len(self.input_2)) 76 | for i in range(len(self.input_2)): 77 | self.circuit.append(cirq.CSWAP(self.control_qubit, self.state_store_qubits[i], self.input_2[i])) 78 | #for c in self.input_1_uncompute: 79 | # self.circuit.append(c[0].controlled_by(self.control_qubit)) 80 | #self.circuit.append(cirq.X(self.input_1[0]).controlled_by(self.control_qubit)) 81 | self.circuit.append(cirq.X(self.control_qubit)) 82 | 83 | for i in range(len(self.input_1)): 84 | self.circuit.append(cirq.CSWAP(self.control_qubit, self.state_store_qubits[i], self.input_1[i])) 85 | #self.circuit.append(cirq.ControlledGate(self.input_2_uncompute)(self.control_qubit, *self.input_1)) 86 | for c in self.input_2_uncompute: 87 | self.circuit.append(c[0].controlled_by(self.control_qubit)) 88 | #self.circuit.append(cirq.X(self.input_1[0]).controlled_by(self.control_qubit)) 89 | self.circuit.append(cirq.X(self.control_qubit)) 90 | for c in self.input_1_uncompute: 91 | self.circuit.append(c[0].controlled_by(self.control_qubit)) 92 | 93 | # Prepare the other state qubit 94 | self.Z = self.input_1_norm**2 + self.input_2_norm**2 95 | print(self.Z) 96 | theta = 2*math.acos(self.input_1_norm/np.sqrt(self.Z)) 97 | print(theta) 98 | self.circuit.append(cirq.ry(theta)(self.other_state_qubits[0])) 99 | self.circuit.append(cirq.Z(self.other_state_qubits[0])) 100 | 101 | self.st = SwapTest(prepare_input_states=False, input_state_dim=4,nq=self.nq,measure=False) 102 | 103 | print(self.other_state_qubits) 104 | self.state = [self.control_qubit] + self.state_store_qubits 105 | self.st.build_circuit(input_1=self.state,input_2=self.other_state_qubits) 106 | self.circuit += self.st.circuit 107 | #print(self.circuit) 108 | #self.circuit.append(cirq.measure(*(self.input_1 + self.input_2), key='k')) 109 | self.circuit.append(cirq.measure(self.st.ancilla_qubit, key='k')) 110 | 111 | print(self.circuit) 112 | 113 | def compute_distance(self): 114 | sim = cirq.Simulator() 115 | results = sim.run(self.circuit, repetitions=self.copies).histogram(key='k') 116 | results = dict(results) 117 | #results = sim.simulate(self.circuit) 118 | print(results) 119 | results = dict(results) 120 | prob_0 = results[0]/self.copies 121 | print(prob_0) 122 | euclidean_distance = 4*self.Z*max((prob_0 - 0.5),0) 123 | print("Euclidean distance",euclidean_distance) 124 | 125 | 126 | 127 | if __name__ == '__main__': 128 | 129 | dist_obj = euclidean_distance(input_state_dim=2, prepare_input_states=True,copies=100000) 130 | theta = math.acos(1/math.sqrt(3)) 131 | dist_obj.dist_circuit(input_1_transforms=[cirq.H], input_2_transforms=[cirq.H]) 132 | dist_obj.compute_distance() 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /Chapter_5/listing5_4/Clusters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/quantum-machine-learning-python/7d22e2cebd807003ff098cc1138356d775014163/Chapter_5/listing5_4/Clusters.png -------------------------------------------------------------------------------- /Chapter_5/listing5_4/QuantumKmeans.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from swap_test import SwapTest 3 | import pandas as pd 4 | import math 5 | import numpy as np 6 | import matplotlib 7 | import matplotlib.pyplot as plt 8 | print('cirq version',cirq.__version__) 9 | print('pandas version',pd.__version__) 10 | print('numpy version',np.__version__) 11 | print('matplotlib version', matplotlib.__version__) 12 | 13 | 14 | 15 | 16 | class QuantumKMeans: 17 | 18 | def __init__(self,data_csv,num_clusters,features,copies=1000,iters=100): 19 | self.data_csv = data_csv 20 | self.num_clusters = num_clusters 21 | self.features = features 22 | self.copies = copies 23 | self.iters = iters 24 | 25 | 26 | def data_preprocess(self): 27 | df = pd.read_csv(self.data_csv) 28 | print(df.columns) 29 | df['theta'] = df.apply(lambda x: math.atan(x[self.features[1]]/x[self.features[0]]), axis=1) 30 | self.X = df.values[:,:2] 31 | self.row_norms = np.sqrt((self.X**2).sum(axis=1)) 32 | self.X = self.X/self.row_norms[:, np.newaxis] 33 | self.X_q_theta = df.values[:,2] 34 | self.num_datapoints = self.X.shape[0] 35 | 36 | def distance(self,x,y): 37 | st = SwapTest(prepare_input_states=True,input_state_dim=2, measure=True, 38 | copies=self.copies) 39 | st.build_circuit(input_1_transforms=[cirq.ry(x)], 40 | input_2_transforms=[cirq.ry(y)]) 41 | prob_0, _ = st.simulate() 42 | _distance_ = 1 - prob_0 43 | del st 44 | return _distance_ 45 | 46 | def init_clusters(self): 47 | self.cluster_points = np.random.randint(self.num_datapoints,size=self.num_clusters) 48 | self.cluster_datapoints = self.X[self.cluster_points,:] 49 | self.cluster_theta = self.X_q_theta[self.cluster_points] 50 | self.clusters = np.zeros(len(self.X_q_theta)) 51 | 52 | def assign_clusters(self): 53 | self.distance_matrix = np.zeros((self.num_datapoints, self.num_clusters)) 54 | for i,x in enumerate(list(self.X_q_theta)): 55 | for j,y in enumerate(list(self.cluster_theta)): 56 | self.distance_matrix[i, j] = self.distance(x,y) 57 | self.clusters = np.argmin(self.distance_matrix,axis=1) 58 | 59 | def update_clusters(self): 60 | updated_cluster_datapoints = [] 61 | updated_cluster_theta = [] 62 | for k in range(self.num_clusters): 63 | 64 | centroid = np.mean(self.X[self.clusters == k],axis=0) 65 | centroid_theta = math.atan(centroid[1]/centroid[0]) 66 | updated_cluster_datapoints.append(centroid) 67 | updated_cluster_theta.append(centroid_theta) 68 | 69 | self.cluster_datapoints = np.array(updated_cluster_datapoints) 70 | self.cluster_theta = np.array(updated_cluster_theta) 71 | 72 | def plot(self): 73 | fig = plt.figure(figsize=(8, 8)) 74 | colors = ['red', 'green', 'blue', 'purple','yellow','black'] 75 | plt.scatter(self.X[:,0],self.X[:,1],c=self.clusters, 76 | cmap=matplotlib.colors.ListedColormap(colors[:self.num_clusters])) 77 | plt.savefig('Clusters.png') 78 | 79 | def run(self): 80 | self.data_preprocess() 81 | self.init_clusters() 82 | for i in range(self.iters): 83 | self.assign_clusters() 84 | self.update_clusters() 85 | self.plot() 86 | 87 | 88 | if __name__ == '__main__': 89 | data_csv = '/home/santanu/Downloads/DataForQComparison.csv' 90 | num_clusters = 4 91 | qkmeans = QuantumKMeans(data_csv=data_csv,num_clusters=num_clusters, 92 | iters=10,features=['Annual Income_k$', 'Spending Score_1_to_100']) 93 | qkmeans.run() 94 | -------------------------------------------------------------------------------- /Chapter_5/listing5_5/qsvm_new.py: -------------------------------------------------------------------------------- 1 | from sklearn import datasets 2 | from sklearn.model_selection import train_test_split 3 | from sklearn.preprocessing import StandardScaler, MinMaxScaler 4 | from sklearn.decomposition import PCA 5 | from qiskit import Aer 6 | from qiskit.aqua.components.feature_maps import SecondOrderExpansion,FirstOrderExpansion 7 | from qiskit.aqua.algorithms import QSVM 8 | from qiskit.aqua import QuantumInstance 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | 12 | 13 | class QSVM_routine: 14 | 15 | def __init__(self, 16 | feature_dim=2, 17 | feature_depth=2, 18 | train_test_split=0.3, 19 | train_samples=5, 20 | test_samples=2, 21 | seed=0, 22 | copies=5): 23 | self.feature_dim = feature_dim 24 | self.feature_depth = feature_depth 25 | self.train_test_split = train_test_split 26 | self.train_samples = train_samples 27 | self.test_samples = test_samples 28 | self.seed = seed 29 | self.copies = copies 30 | 31 | # Create train test datasets 32 | 33 | def train_test_datasets(self): 34 | self.class_labels = [r'A', r'B'] 35 | data, target = datasets.load_breast_cancer(True) 36 | train_X, test_X, train_y, test_y = train_test_split(data, target, 37 | test_size=self.train_test_split, 38 | random_state=self.seed) 39 | # Mean std normalization 40 | self.z_scale = StandardScaler().fit(train_X) 41 | self.train_X_norm = self.z_scale.transform(train_X) 42 | self.test_X_norm = self.z_scale.transform(test_X) 43 | 44 | # Project the data into dimensions equal to the 45 | # number of qubits 46 | self.pca = PCA(n_components=self.feature_dim).fit(self.train_X_norm) 47 | self.train_X_norm = self.pca.transform(self.train_X_norm) 48 | self.test_X_norm = self.pca.transform(self.test_X_norm) 49 | 50 | # Scale to the range (-1,+1) 51 | X_all = np.append(self.train_X_norm, self.test_X_norm, axis=0) 52 | minmax_scale = MinMaxScaler((-1, 1)).fit(X_all) 53 | self.train_X_norm = minmax_scale.transform(self.train_X_norm) 54 | self.test_X_norm = minmax_scale.transform(self.test_X_norm) 55 | 56 | # Pick training and test number of datapoint 57 | self.train = {key: (self.train_X_norm[train_y == k, :])[:self.train_samples] for k, key in 58 | enumerate(self.class_labels)} 59 | self.test = {key: (self.test_X_norm[test_y == k, :])[:self.test_samples] for k, key in 60 | enumerate(self.class_labels)} 61 | 62 | 63 | # Train the QSVM Model 64 | def train_model(self): 65 | backend = Aer.get_backend('qasm_simulator') 66 | feature_expansion = SecondOrderExpansion(feature_dimension=self.feature_dim, 67 | depth=self.feature_depth, 68 | entangler_map=[[0, 1]]) 69 | #feature_expansion = FirstOrderExpansion(feature_dimension=self.feature_dim) 70 | 71 | # Model definition 72 | svm = QSVM(feature_expansion, self.train, self.test) 73 | #svm.random_seed = self.seed 74 | q_inst = QuantumInstance(backend, shots=self.copies) 75 | 76 | # Train the SVM 77 | result = svm.run(q_inst) 78 | return svm, result 79 | 80 | # Analyze the training and test results 81 | 82 | def analyze_training_and_inference(self, result, svm): 83 | data_kernel_matrix = result['kernel_matrix_training'] 84 | image = plt.imshow(np.asmatrix(data_kernel_matrix), 85 | interpolation='nearest', 86 | origin='upper', 87 | cmap='bone_r') 88 | plt.show() 89 | print(f"Test Accuracy: {result['testing_accuracy']}") 90 | 91 | def main(self): 92 | self.train_test_datasets() 93 | svm, result = self.train_model() 94 | self.analyze_training_and_inference(svm, result) 95 | 96 | 97 | if __name__ == '__main__': 98 | qsvm = QSVM_routine() 99 | qsvm.main() -------------------------------------------------------------------------------- /Chapter_6/listing6_1/QCNN.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | print('numpy version', np.__version__) 3 | import matplotlib 4 | print('matplotlib version', matplotlib.__version__) 5 | import matplotlib.pyplot as plt 6 | import torch 7 | print('torch version', torch.__version__) 8 | from torch.autograd import Function 9 | from torchvision import datasets, transforms 10 | import torch.optim as optim 11 | import torch.nn as nn 12 | import torch.nn.functional as F 13 | import qiskit 14 | print('qiskit version', qiskit.__version__) 15 | #from qiskit.visualizatiosn import * 16 | 17 | class QuantumCircuit: 18 | """ 19 | The class implements a simple Quantum Block 20 | """ 21 | 22 | def __init__(self, num_qubits, backend, copies: int = 1000): 23 | self._circuit_ = qiskit.QuantumCircuit(num_qubits) 24 | self.theta = qiskit.circuit.Parameter('theta') 25 | self._circuit_.h([i for i in range(num_qubits)]) 26 | self._circuit_.barrier() 27 | self._circuit_.ry(self.theta, [i for i in range(num_qubits)]) 28 | self._circuit_.measure_all() 29 | 30 | self.backend = backend 31 | self.copies = copies 32 | 33 | def run(self, theta_batch): 34 | job = qiskit.execute(self._circuit_, 35 | self.backend, 36 | shots=self.copies, 37 | parameter_binds=[{self.theta: theta} for theta in theta_batch]) 38 | result = job.result().get_counts(self._circuit_) 39 | 40 | counts = np.array(list(result.values())) 41 | states = np.array(list(result.keys())).astype(float) 42 | probs = counts / self.copies 43 | expectation = np.array([np.sum(np.multiply(probs, states))]) 44 | return expectation 45 | 46 | 47 | class QuantumFunction(Function): 48 | """ Hybrid quantum - classical function definition """ 49 | 50 | @staticmethod 51 | def forward(ctx, input, q_circuit, shift): 52 | """ Forward pass computation """ 53 | ctx.shift = shift 54 | ctx.q_circuit = q_circuit 55 | theta_batch = input[0].tolist() 56 | expectation = ctx.q_circuit.run(theta_batch=theta_batch) 57 | result = torch.tensor([expectation]) 58 | ctx.save_for_backward(input, result) 59 | 60 | return result 61 | 62 | @staticmethod 63 | def backward(ctx, grad_output): 64 | """ Backward pass computation """ 65 | input, expectation = ctx.saved_tensors 66 | theta_batch = np.array(input.tolist()) 67 | 68 | shift_right = theta_batch + np.ones(theta_batch.shape) * ctx.shift 69 | shift_left = theta_batch - np.ones(theta_batch.shape) * ctx.shift 70 | 71 | gradients = [] 72 | for i in range(len(theta_batch)): 73 | expectation_right = ctx.q_circuit.run(shift_right[i]) 74 | expectation_left = ctx.q_circuit.run(shift_left[i]) 75 | 76 | gradient = torch.tensor([expectation_right]) - torch.tensor([expectation_left]) 77 | gradients.append(gradient) 78 | gradients = np.array([gradients]).T 79 | return torch.tensor([gradients]).float() * grad_output.float(), None, None 80 | 81 | 82 | class QuantumLayer(nn.Module): 83 | """ Hybrid quantum - classical layer definition """ 84 | 85 | def __init__(self,num_qubits, backend, shift, copies=1000): 86 | super(QuantumLayer, self).__init__() 87 | self.q_circuit = QuantumCircuit(num_qubits, backend, copies) 88 | self.shift = shift 89 | 90 | def forward(self, input): 91 | return QuantumFunction.apply(input, self.q_circuit, self.shift) 92 | 93 | 94 | class QCNNet(nn.Module): 95 | def __init__(self, num_qubits=1, 96 | backend=qiskit.Aer.get_backend('qasm_simulator'), 97 | shift=np.pi/2, 98 | copies=1000): 99 | super(QCNNet, self).__init__() 100 | self.conv1 = nn.Conv2d(1, 6, kernel_size=5) 101 | self.conv2 = nn.Conv2d(6, 16, kernel_size=5) 102 | self.dropout = nn.Dropout2d() 103 | self.fc1 = nn.Linear(256, 64) 104 | self.fc2 = nn.Linear(64, 1) 105 | self.q_layer = QuantumLayer(num_qubits=num_qubits, 106 | backend=backend, 107 | shift=shift, 108 | copies=copies) 109 | 110 | def forward(self, x): 111 | x = F.relu(self.conv1(x)) 112 | x = F.max_pool2d(x, 2) 113 | x = F.relu(self.conv2(x)) 114 | x = F.max_pool2d(x, 2) 115 | x = self.dropout(x) 116 | x = x.view(1, -1) 117 | x = F.relu(self.fc1(x)) 118 | x = self.fc2(x) 119 | x = self.q_layer(x) 120 | return torch.cat((x, 1 - x), -1) 121 | 122 | 123 | 124 | 125 | 126 | 127 | # Concentrating on the first 100 samples 128 | n_samples = 100 129 | 130 | X_train = datasets.MNIST(root='./data', train=True, download=True, 131 | transform=transforms.Compose([transforms.ToTensor()])) 132 | 133 | # Leaving only labels 0 and 1 134 | idx = np.append(np.where(X_train.targets == 0)[0][:n_samples], 135 | np.where(X_train.targets == 1)[0][:n_samples]) 136 | 137 | X_train.data = X_train.data[idx] 138 | X_train.targets = X_train.targets[idx] 139 | 140 | train_loader = torch.utils.data.DataLoader(X_train, batch_size=1, shuffle=True) 141 | n_samples_show = 6 142 | 143 | data_iter = iter(train_loader) 144 | fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 3)) 145 | 146 | while n_samples_show > 0: 147 | images, targets = data_iter.__next__() 148 | 149 | axes[n_samples_show - 1].imshow(images[0].numpy().squeeze(), cmap='gray') 150 | axes[n_samples_show - 1].set_xticks([]) 151 | axes[n_samples_show - 1].set_yticks([]) 152 | axes[n_samples_show - 1].set_title("Labeled: {}".format(targets.item())) 153 | 154 | n_samples_show -= 1 155 | 156 | n_samples = 50 157 | 158 | X_test = datasets.MNIST(root='./data', train=False, download=True, 159 | transform=transforms.Compose([transforms.ToTensor()])) 160 | 161 | idx = np.append(np.where(X_test.targets == 0)[0][:n_samples], 162 | np.where(X_test.targets == 1)[0][:n_samples]) 163 | 164 | X_test.data = X_test.data[idx] 165 | X_test.targets = X_test.targets[idx] 166 | 167 | test_loader = torch.utils.data.DataLoader(X_test, batch_size=1, shuffle=True) 168 | 169 | model = QCNNet() 170 | optimizer = optim.Adam(model.parameters(), lr=0.001) 171 | loss_func = nn.NLLLoss() 172 | 173 | epochs = 20 174 | loss_list = [] 175 | 176 | model.train() 177 | for epoch in range(epochs): 178 | total_loss = [] 179 | for batch_idx, (data, target) in enumerate(train_loader): 180 | optimizer.zero_grad() 181 | # Forward pass 182 | output = model(data) 183 | # Calculating loss 184 | loss = loss_func(output, target) 185 | # Backward pass 186 | loss.backward() 187 | # Optimize the weights 188 | optimizer.step() 189 | 190 | total_loss.append(loss.item()) 191 | loss_list.append(sum(total_loss) / len(total_loss)) 192 | print('Training [{:.0f}%]\tLoss: {:.4f}'.format( 193 | 100. * (epoch + 1) / epochs, loss_list[-1])) 194 | 195 | 196 | plt.plot(loss_list) 197 | plt.title('Hybrid NN Training Convergence') 198 | plt.xlabel('Training Iterations') 199 | plt.ylabel('Neg Log Likelihood Loss') 200 | 201 | model.eval() 202 | with torch.no_grad(): 203 | correct = 0 204 | for batch_idx, (data, target) in enumerate(test_loader): 205 | output = model(data) 206 | 207 | pred = output.argmax(dim=1, keepdim=True) 208 | correct += pred.eq(target.view_as(pred)).sum().item() 209 | 210 | loss = loss_func(output, target) 211 | total_loss.append(loss.item()) 212 | 213 | print('Performance on test data:\n\tLoss: {:.4f}\n\tAccuracy: {:.1f}%'.format( 214 | sum(total_loss) / len(total_loss), 215 | correct / len(test_loader) * 100) 216 | ) 217 | 218 | n_samples_show = 6 219 | count = 0 220 | fig, axes = plt.subplots(nrows=1, ncols=n_samples_show, figsize=(10, 3)) 221 | 222 | model.eval() 223 | with torch.no_grad(): 224 | for batch_idx, (data, target) in enumerate(test_loader): 225 | if count == n_samples_show: 226 | break 227 | output = model(data) 228 | 229 | pred = output.argmax(dim=1, keepdim=True) 230 | 231 | axes[count].imshow(data[0].numpy().squeeze(), cmap='gray') 232 | 233 | axes[count].set_xticks([]) 234 | axes[count].set_yticks([]) 235 | axes[count].set_title('Predicted {}'.format(pred.item())) 236 | 237 | count += 1 -------------------------------------------------------------------------------- /Chapter_6/listing6_1/listing_6.1_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/QCNN.py 2 | numpy version 1.19.0 3 | matplotlib version 2.2.5 4 | torch version 1.2.0 5 | qiskit version 0.15.2 6 | Training [5%] Loss: -0.8083 7 | Training [10%] Loss: -0.9014 8 | Training [15%] Loss: -0.9319 9 | Training [20%] Loss: -0.9433 10 | Training [25%] Loss: -0.9485 11 | Training [30%] Loss: -0.9604 12 | Training [35%] Loss: -0.9643 13 | Training [40%] Loss: -0.9679 14 | Training [45%] Loss: -0.9754 15 | Training [50%] Loss: -0.9728 16 | Training [55%] Loss: -0.9764 17 | Training [60%] Loss: -0.9832 18 | Training [65%] Loss: -0.9802 19 | Training [70%] Loss: -0.9855 20 | Training [75%] Loss: -0.9822 21 | Training [80%] Loss: -0.9815 22 | Training [85%] Loss: -0.9885 23 | Training [90%] Loss: -0.9900 24 | Training [95%] Loss: -0.9866 25 | Training [100%] Loss: -0.9907 26 | Performance on test data: 27 | Loss: -0.9767 28 | Accuracy: 100.0% 29 | 30 | Process finished with exit code 0 -------------------------------------------------------------------------------- /Chapter_6/listing6_2/listing_6.2_output.txt.txt: -------------------------------------------------------------------------------- 1 | Number of original training examples: 60000 2 | Number of original test examples: 10000 3 | Number of filtered training examples: 12049 4 | Number of filtered test examples: 1968 5 | Initial number of examples: 12049 6 | Final number of non-contradictory examples: 11520 7 | Model: "sequential_2" 8 | _________________________________________________________________ 9 | Layer (type) Output Shape Param # 10 | ================================================================= 11 | pqc_2 (PQC) (None, 1) 32 12 | ================================================================= 13 | Total params: 32 Trainable params: 32 Non-trainable params: 0 14 | Train on 11520 samples, validate on 1968 samples 15 | Epoch 1/3 16 | 11520/11520 [==============================] - 439s 38ms/sample - 17 | loss: 0.6591 - hinge_accuracy: 0.7385 - val_loss: 0.3611 - 18 | val_hinge_accuracy: 0.8281 19 | Epoch 2/3 20 | 11520/11520 [==============================] - 441s 38ms/sample - 21 | loss: 0.3458 - hinge_accuracy: 0.8286 - val_loss: 0.3303 - 22 | val_hinge_accuracy: 0.8281 23 | Epoch 3/3 24 | Chapter 6 Quantum Deep Learning 25 | 306 26 | 11520/11520 [==============================] - 437s 38ms/sample - 27 | loss: 0.3263 - hinge_accuracy: 0.8493 - val_loss: 0.3268 - 28 | val_hinge_accuracy: 0.8564 29 | 1968/1968 [==============================] - 3s 2ms/sample - loss: 30 | 0.3268 - hinge_accuracy: 0.8564 -------------------------------------------------------------------------------- /Chapter_6/listing6_2/tfq_mnist.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | print('tensorflow version',tf.__version__) 3 | import tensorflow_quantum as tfq 4 | print('tensorflow quantum version',tfq.__version__) 5 | 6 | import cirq 7 | print('cirq version ',cirq.__version__) 8 | import sympy 9 | print('sympy version',sympy.__version__) 10 | import numpy as np 11 | print('numpy version',np.__version__) 12 | import seaborn as sns 13 | import collections 14 | 15 | # visualization tools 16 | import matplotlib.pyplot as plt 17 | from cirq.contrib.svg import SVGCircuit 18 | 19 | 20 | def extract_specific_digits(X, y, labels_to_extract): 21 | label_y1 = labels_to_extract[0] 22 | label_y2 = labels_to_extract[1] 23 | 24 | mask = (y == label_y1) | (y == label_y2) 25 | X, y = X[mask], y[mask] 26 | y = (y == label_y1) 27 | return X, y 28 | 29 | 30 | def remove_sample_with_2_labels(X, y): 31 | mapping = collections.defaultdict(set) 32 | # Determine the set of labels for each unique image: 33 | for _x_, _y_ in zip(X, y): 34 | mapping[tuple(_x_.flatten())].add(_y_) 35 | 36 | new_x = [] 37 | new_y = [] 38 | for _x_, _y_ in zip(X, y): 39 | labels = mapping[tuple(_x_.flatten())] 40 | if len(labels) == 1: 41 | new_x.append(_x_) 42 | new_y.append(list(labels)[0]) 43 | else: 44 | pass 45 | 46 | print("Initial number of examples: ", len(X)) 47 | print("Final number of non-contradictory examples: ", len(new_x)) 48 | 49 | return np.array(new_x), np.array(new_y) 50 | 51 | 52 | def data_preprocessing(labels_to_extract, resize_dim=4, binary_threshold=0.5): 53 | # Load the data 54 | (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() 55 | # Rescale the images from 0 to 1 range 56 | x_train = x_train[..., np.newaxis] / 255.0 57 | x_test = x_test[..., np.newaxis] / 255.0 58 | 59 | print("Number of original training examples:", len(x_train)) 60 | print("Number of original test examples:", len(x_test)) 61 | 62 | # Extract on the specified 2 classes in labels_to_extract 63 | x_train, y_train = extract_specific_digits(x_train, y_train, 64 | labels_to_extract=labels_to_extract) 65 | x_test, y_test = extract_specific_digits(x_test, y_test, 66 | labels_to_extract=labels_to_extract) 67 | 68 | print("Number of filtered training examples:", len(x_train)) 69 | print("Number of filtered test examples:", len(x_test)) 70 | 71 | # Resize the MNIST Images since 28x28 size image requires as 72 | # many qubits which is too much for Quantum Computers to 73 | # allocate. We resize them to 4x4 for keeping the problem 74 | # tractable in Quantum Computing realm. 75 | 76 | x_train_resize = tf.image.resize(x_train, (resize_dim, resize_dim)).numpy() 77 | x_test_resize = tf.image.resize(x_test, (resize_dim, resize_dim)).numpy() 78 | 79 | # Because of resizing to such small dimension there is a chance of images 80 | # with different classes hashing to the same label. We remove such 81 | # images below 82 | 83 | x_train_resize, y_train_resize = \ 84 | remove_sample_with_2_labels(x_train_resize, y_train) 85 | 86 | # We represent each pixel in binary by applying a threshold 87 | x_train_bin = np.array(x_train_resize > binary_threshold, dtype=np.float32) 88 | x_test_bin = np.array(x_test_resize > binary_threshold, dtype=np.float32) 89 | 90 | return x_train_bin, x_test_bin, x_train_resize, x_test_resize, \ 91 | y_train_resize, y_test 92 | 93 | 94 | # Quantum circuit to represents each 0 valued pixel by |0> state 95 | # and 1 pixel by |1> state. 96 | 97 | def classical_to_quantum_data_circuit(image): 98 | image_flatten = image.flatten() 99 | qubits = cirq.GridQubit.rect(4, 4) 100 | circuit = cirq.Circuit() 101 | for i, val in enumerate(image_flatten): 102 | if val: 103 | circuit.append(cirq.X(qubits[i])) 104 | return circuit 105 | 106 | 107 | # Define circuit for classical to quantum data for all datapoints 108 | # and transfrom those cicuits to Tensors using Tensorflow Quantum 109 | 110 | def classical_data_to_tfq_tensors(x_train_bin, x_test_bin): 111 | x_train_c = [classical_to_quantum_data_circuit(x) for x in x_train_bin] 112 | x_test_c = [classical_to_quantum_data_circuit(x) for x in x_test_bin] 113 | x_train_tfc = tfq.convert_to_tensor(x_train_c) 114 | x_test_tfc = tfq.convert_to_tensor(x_test_c) 115 | return x_train_tfc, x_test_tfc 116 | 117 | 118 | class QuantumLayer: 119 | def __init__(self, data_qubits, readout): 120 | self.data_qubits = data_qubits 121 | self.readout = readout 122 | 123 | def add_layer(self, circuit, gate, prefix): 124 | for i, q in enumerate(self.data_qubits): 125 | _w_ = sympy.Symbol(prefix + '-' + str(i)) 126 | circuit.append(gate(q, self.readout) ** _w_) 127 | 128 | 129 | def create_QNN(resize_dim=4): 130 | """Create a QNN model circuit and prediction(readout) """ 131 | data_qubits = cirq.GridQubit.rect(resize_dim, resize_dim) # a 4x4 grid. 132 | readout = cirq.GridQubit(-1, -1) # a single qubit at [-1,-1] 133 | circuit = cirq.Circuit() 134 | 135 | # Prepare the readout qubit. 136 | circuit.append(cirq.X(readout)) 137 | circuit.append(cirq.H(readout)) 138 | 139 | builder = QuantumLayer( 140 | data_qubits=data_qubits, 141 | readout=readout) 142 | 143 | # Apply a series of XX layers followed 144 | # by a series of ZZ layers 145 | builder.add_layer(circuit, cirq.XX, "XX") 146 | builder.add_layer(circuit, cirq.ZZ, "ZZ") 147 | 148 | # Hadamard Gate on the readout qubit 149 | circuit.append(cirq.H(readout)) 150 | 151 | return circuit, cirq.Z(readout) 152 | 153 | 154 | def hinge_accuracy(y_true, y_pred): 155 | y_true = tf.squeeze(y_true) > 0.0 156 | y_pred = tf.squeeze(y_pred) > 0.0 157 | cost = tf.cast(y_true == y_pred, tf.float32) 158 | 159 | return tf.reduce_mean(cost) 160 | 161 | 162 | def build_model(resize_dim=4): 163 | model_circuit, model_readout = create_QNN(resize_dim=resize_dim) 164 | # Build the model. 165 | model = tf.keras.Sequential([ 166 | # The input is the data-circuit encoded as Tensors 167 | tf.keras.layers.Input(shape=(), dtype=tf.string), 168 | # The PQC layer returns the expected value of the readout gate 169 | # in the range range [-1,1] 170 | tfq.layers.PQC(model_circuit, model_readout), 171 | ]) 172 | return model, model_circuit, model_readout 173 | 174 | 175 | def main(labels_to_extract, 176 | resize_dim, 177 | binary_threshold, 178 | subsample, 179 | epochs=3, 180 | batch_size=32, 181 | eval=True): 182 | # Perform data preprocessing 183 | x_train_bin, x_test_bin, x_train_resize, x_test_resize, \ 184 | y_train_resize, y_test_resize = \ 185 | data_preprocessing(labels_to_extract=labels_to_extract, 186 | resize_dim=resize_dim, 187 | binary_threshold=binary_threshold) 188 | 189 | x_train_tfc, x_test_tfc = \ 190 | classical_data_to_tfq_tensors(x_test_bin, x_test_bin) 191 | 192 | # Convert labels to -1 or 1 to align with hinge loss 193 | y_train_hinge = 2.0 * y_train_resize - 1.0 194 | y_test_hinge = 2.0 * y_test_resize - 1.0 195 | 196 | # build model 197 | model, model_circuit, model_readout = \ 198 | build_model(resize_dim=resize_dim) 199 | 200 | # Compile Model 201 | 202 | model.compile( 203 | loss=tf.keras.losses.Hinge(), 204 | optimizer=tf.keras.optimizers.Adam(), 205 | metrics=[hinge_accuracy]) 206 | print(model.summary()) 207 | 208 | if subsample > 0: 209 | x_train_tfc_sub = x_train_tfc[:subsample] 210 | y_train_hinge_sub = y_train_hinge[:subsample] 211 | 212 | qnn_hist = model.fit( 213 | x_train_tfc_sub, 214 | y_train_hinge_sub, 215 | batch_size=batch_size, 216 | epochs=epochs, 217 | verbose=1, 218 | validation_data=(x_test_tfc, 219 | y_test_hinge)) 220 | 221 | if eval: 222 | results = model.evaluate(x_test_tfc, y_test_hinge) 223 | print(results) 224 | 225 | 226 | if __name__ == '__main__': 227 | labels_to_extract = [3, 6] 228 | resize_dim = 4 229 | binary_threshold = 0.5 230 | subsample = 500 231 | epochs = 3 232 | batch_size = 32 233 | 234 | main(labels_to_extract=labels_to_extract, 235 | resize_dim=resize_dim, 236 | binary_threshold=binary_threshold, 237 | subsample=subsample, 238 | epochs=epochs, 239 | batch_size=batch_size) -------------------------------------------------------------------------------- /Chapter_7/listing7_1/listing_7.1_output.txt: -------------------------------------------------------------------------------- 1 | /home/santanu/anaconda3/bin/python /home/santanu/PycharmProjects/QuantumML/vqe_cirq.py 2 | cirq version 0.8.2 3 | numpy version 1.19.0 4 | scipy version 1.4.1 5 | {'IIZZ': {0: 0.5, 1: -0.5, 2: -0.5, 3: 0.5, 4: 0.5, 5: -0.5, 6: -0.5, 7: 0.5, 8: 0.5, 9: -0.5, 10: -0.5, 11: 0.5, 12: 0.5, 13: -0.5, 14: -0.5, 15: 0.5}, 'IZIZ': {0: 0.5, 1: -0.5, 2: 0.5, 3: -0.5, 4: -0.5, 5: 0.5, 6: -0.5, 7: 0.5, 8: 0.5, 9: -0.5, 10: 0.5, 11: -0.5, 12: -0.5, 13: 0.5, 14: -0.5, 15: 0.5}, 'IZZI': {0: 0.5, 1: 0.5, 2: -0.5, 3: -0.5, 4: -0.5, 5: -0.5, 6: 0.5, 7: 0.5, 8: 0.5, 9: 0.5, 10: -0.5, 11: -0.5, 12: -0.5, 13: -0.5, 14: 0.5, 15: 0.5}, 'ZIIZ': {0: 0.5, 1: -0.5, 2: 0.5, 3: -0.5, 4: 0.5, 5: -0.5, 6: 0.5, 7: -0.5, 8: -0.5, 9: 0.5, 10: -0.5, 11: 0.5, 12: -0.5, 13: 0.5, 14: -0.5, 15: 0.5}, 'ZZII': {0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5, 4: -0.5, 5: -0.5, 6: -0.5, 7: -0.5, 8: -0.5, 9: -0.5, 10: -0.5, 11: -0.5, 12: 0.5, 13: 0.5, 14: 0.5, 15: 0.5}} 6 | 0: ───Ry(0.5π)───M('m')─── 7 | │ 8 | 1: ───Ry(0.5π)───M──────── 9 | │ 10 | 2: ───Ry(0.5π)───M──────── 11 | │ 12 | 3: ───Ry(0.5π)───M──────── 13 | Stats {0: 58, 15: 65, 1: 53, 7: 72, 14: 72, 3: 59, 12: 61, 4: 60, 13: 59, 10: 62, 5: 65, 8: 65, 11: 59, 2: 71, 6: 63, 9: 56} 14 | Theta: [0.5 0.5 0.5 0.5] Expectation: 0.009 15 | 0: ───Ry(1.5π)───M('m')─── 16 | │ 17 | 1: ───Ry(0.5π)───M──────── 18 | │ 19 | 2: ───Ry(0.5π)───M──────── 20 | │ 21 | 3: ───Ry(0.5π)───M──────── 22 | Stats {3: 71, 13: 69, 6: 65, 15: 55, 12: 72, 1: 58, 5: 60, 9: 59, 11: 65, 10: 58, 0: 69, 7: 60, 8: 60, 2: 53, 14: 59, 4: 67} 23 | Theta: [1.5 0.5 0.5 0.5] Expectation: -0.004 24 | 0: ───Ry(1.5π)───M('m')─── 25 | │ 26 | 1: ───Ry(1.5π)───M──────── 27 | │ 28 | 2: ───Ry(0.5π)───M──────── 29 | │ 30 | 3: ───Ry(0.5π)───M──────── 31 | Stats {1: 61, 11: 68, 3: 66, 8: 63, 5: 60, 13: 53, 7: 54, 14: 74, 12: 60, 9: 61, 4: 66, 15: 65, 6: 72, 2: 64, 10: 50, 0: 63} 32 | Theta: [1.5 1.5 0.5 0.5] Expectation: 0.008 33 | 0: ───Ry(1.5π)───M('m')─── 34 | │ 35 | 1: ───Ry(0.5π)───M──────── 36 | │ 37 | 2: ───Ry(1.5π)───M──────── 38 | │ 39 | 3: ───Ry(0.5π)───M──────── 40 | Stats {1: 65, 8: 68, 12: 61, 15: 62, 11: 57, 13: 51, 9: 75, 3: 75, 4: 53, 5: 53, 10: 81, 2: 71, 0: 63, 6: 72, 7: 45, 14: 48} 41 | Theta: [1.5 0.5 1.5 0.5] Expectation: -0.024 42 | 0: ───Ry(1.5π)───M('m')─── 43 | │ 44 | 1: ───Ry(0.5π)───M──────── 45 | │ 46 | 2: ───Ry(1.5π)───M──────── 47 | │ 48 | 3: ───Ry(1.5π)───M──────── 49 | Stats {6: 62, 3: 62, 15: 50, 9: 53, 11: 55, 14: 63, 12: 64, 13: 66, 10: 68, 1: 84, 0: 62, 5: 53, 2: 59, 7: 64, 8: 68, 4: 67} 50 | Theta: [1.5 0.5 1.5 1.5] Expectation: -0.028 51 | 0: ───Ry(1.98π)────M('m')─── 52 | │ 53 | 1: ───Ry(0.056π)───M──────── 54 | │ 55 | 2: ───Ry(-1.76π)───M──────── 56 | │ 57 | 3: ───Ry(1.65π)────M──────── 58 | Stats {0: 638, 3: 32, 1: 220, 2: 106, 5: 2, 4: 2} 59 | Theta: [1.98148148 0.05555556 2.24074074 1.64814815] Expectation: 1.518 60 | 0: ───Ry(π)────────M('m')─── 61 | │ 62 | 1: ───Ry(0.498π)───M──────── 63 | │ 64 | 2: ───Ry(1.5π)─────M──────── 65 | │ 66 | 3: ───Ry(1.5π)─────M──────── 67 | Stats {11: 128, 8: 129, 14: 118, 12: 121, 10: 121, 9: 140, 13: 133, 15: 110} 68 | Theta: [1.00001322 0.49815616 1.50307306 1.50061461] Expectation: -0.029 69 | 0: ───Ry(π)────────M('m')─── 70 | │ 71 | 1: ───Ry(0.713π)───M──────── 72 | │ 73 | 2: ───Ry(1.63π)────M──────── 74 | │ 75 | 3: ───Ry(1.5π)─────M──────── 76 | Stats {12: 292, 14: 138, 8: 68, 13: 288, 15: 112, 9: 58, 11: 18, 10: 26} 77 | Theta: [1.00001322 0.7125294 1.631697 1.50061461] Expectation: 0.166 78 | 0: ───Ry(0.996π)───M('m')─── 79 | │ 80 | 1: ───Ry(0.562π)───M──────── 81 | │ 82 | 2: ───Ry(1.01π)────M──────── 83 | │ 84 | 3: ───Ry(1.5π)─────M──────── 85 | Stats {15: 330, 10: 179, 14: 306, 11: 185} 86 | Theta: [0.99621737 0.56190953 1.0071698 1.50164267] Expectation: 0.311 87 | 0: ───Ry(π)────────M('m')─── 88 | │ 89 | 1: ───Ry(0.498π)───M──────── 90 | │ 91 | 2: ───Ry(1.5π)─────M──────── 92 | │ 93 | 3: ───Ry(1.75π)────M──────── 94 | Stats {14: 225, 8: 216, 9: 31, 10: 207, 12: 213, 13: 42, 11: 42, 15: 24} 95 | Theta: [1.00032454 0.4978688 1.50355201 1.75061379] Expectation: -0.377 96 | 0: ───Ry(1.0π)─────M('m')─── 97 | │ 98 | 1: ───Ry(0.18π)────M──────── 99 | │ 100 | 2: ───Ry(1.64π)────M──────── 101 | │ 102 | 3: ───Ry(-1.89π)───M──────── 103 | Stats {10: 268, 12: 52, 8: 623, 11: 13, 14: 16, 9: 24, 13: 4} 104 | Theta: [1.0022681 0.17954795 1.64108962 2.1108241 ] Expectation: -0.141 105 | 0: ───Ry(0.999π)───M('m')─── 106 | │ 107 | 1: ───Ry(0.566π)───M──────── 108 | │ 109 | 2: ───Ry(1.28π)────M──────── 110 | │ 111 | 3: ───Ry(1.85π)────M──────── 112 | Stats {14: 477, 10: 303, 12: 109, 8: 64, 11: 17, 15: 19, 13: 10, 9: 1} 113 | Theta: [0.99870393 0.56590197 1.28389332 1.84868989] Expectation: -0.672 114 | 0: ───Ry(0.998π)───M('m')─── 115 | │ 116 | 1: ───Ry(0.506π)───M──────── 117 | │ 118 | 2: ───Ry(1.16π)────M──────── 119 | │ 120 | 3: ───Ry(-1.94π)───M──────── 121 | Stats {14: 475, 10: 456, 12: 30, 15: 9, 8: 28, 11: 2} 122 | Theta: [0.99810809 0.50598432 1.15796581 2.05617912] Expectation: -0.901 123 | 0: ───Ry(0.997π)───M('m')─── 124 | │ 125 | 1: ───Ry(0.689π)───M──────── 126 | │ 127 | 2: ───Ry(1.13π)────M──────── 128 | │ 129 | 3: ───Ry(-1.78π)───M──────── 130 | Stats {10: 174, 15: 88, 14: 663, 8: 8, 11: 37, 12: 28, 13: 2} 131 | Theta: [0.9972151 0.68927351 1.12824065 2.22357294] Expectation: -0.4 132 | 0: ───Ry(0.873π)───M('m')─── 133 | │ 134 | 1: ───Ry(0.506π)───M──────── 135 | │ 136 | 2: ───Ry(1.16π)────M──────── 137 | │ 138 | 3: ───Ry(-1.94π)───M──────── 139 | Stats {10: 433, 14: 471, 6: 13, 12: 25, 8: 31, 11: 2, 2: 21, 15: 3, 4: 1} 140 | Theta: [0.8731113 0.50552357 1.15873373 2.05615318] Expectation: -0.872 141 | 0: ───Ry(1.01π)────M('m')─── 142 | │ 143 | 1: ───Ry(0.349π)───M──────── 144 | │ 145 | 2: ───Ry(0.979π)───M──────── 146 | │ 147 | 3: ───Ry(1.98π)────M──────── 148 | Stats {10: 715, 14: 284, 6: 1} 149 | Theta: [1.01428519 0.34861174 0.97929521 1.98168759] Expectation: -1.215 150 | 0: ───Ry(1.03π)────M('m')─── 151 | │ 152 | 1: ───Ry(0.112π)───M──────── 153 | │ 154 | 2: ───Ry(1.04π)────M──────── 155 | │ 156 | 3: ───Ry(-1.97π)───M──────── 157 | Stats {10: 957, 14: 31, 8: 5, 2: 3, 11: 4} 158 | Theta: [1.03262021 0.11175156 1.0393947 2.03117635] Expectation: -1.449 159 | 0: ───Ry(1.07π)─────M('m')─── 160 | │ 161 | 1: ───Ry(-0.082π)───M──────── 162 | │ 163 | 2: ───Ry(0.894π)────M──────── 164 | │ 165 | 3: ───Ry(-1.92π)────M──────── 166 | Stats {10: 931, 2: 17, 11: 20, 14: 9, 8: 21, 6: 1, 9: 1} 167 | Theta: [ 1.07223887 -0.08229085 0.89360086 2.07614368] Expectation: -1.393 168 | 0: ───Ry(1.05π)────M('m')─── 169 | │ 170 | 1: ───Ry(0.027π)───M──────── 171 | │ 172 | 2: ───Ry(1.11π)────M──────── 173 | │ 174 | 3: ───Ry(1.81π)────M──────── 175 | Stats {10: 872, 2: 5, 11: 91, 8: 27, 14: 1, 9: 4} 176 | Theta: [1.04663722 0.02713294 1.10851673 1.80675408] Expectation: -1.34 177 | 0: ───Ry(1.15π)────M('m')─── 178 | │ 179 | 1: ───Ry(0.118π)───M──────── 180 | │ 181 | 2: ───Ry(1.08π)────M──────── 182 | │ 183 | 3: ───Ry(-1.94π)───M──────── 184 | Stats {10: 894, 14: 38, 2: 55, 6: 1, 8: 8, 11: 4} 185 | Theta: [1.14827344 0.1175077 1.07848349 2.05741114] Expectation: -1.331 186 | 0: ───Ry(0.945π)───M('m')─── 187 | │ 188 | 1: ───Ry(0.076π)───M──────── 189 | │ 190 | 2: ───Ry(1.1π)─────M──────── 191 | │ 192 | 3: ───Ry(-1.91π)───M──────── 193 | Stats {10: 940, 8: 26, 11: 12, 14: 14, 2: 7, 12: 1} 194 | Theta: [0.94453087 0.07645965 1.10046999 2.08493096] Expectation: -1.407 195 | 0: ───Ry(1.03π)────M('m')─── 196 | │ 197 | 1: ───Ry(0.089π)───M──────── 198 | │ 199 | 2: ───Ry(1.06π)────M──────── 200 | │ 201 | 3: ───Ry(1.98π)────M──────── 202 | Stats {10: 973, 14: 18, 8: 7, 11: 1, 15: 1} 203 | Theta: [1.02595075 0.08938821 1.05578681 1.97556207] Expectation: -1.463 204 | 0: ───Ry(1.02π)────M('m')─── 205 | │ 206 | 1: ───Ry(0.116π)───M──────── 207 | │ 208 | 2: ───Ry(1.07π)────M──────── 209 | │ 210 | 3: ───Ry(1.97π)────M──────── 211 | Stats {10: 942, 14: 41, 8: 11, 12: 3, 11: 2, 2: 1} 212 | Theta: [1.02124205 0.11621597 1.06984778 1.96948333] Expectation: -1.43 213 | 0: ───Ry(1.01π)────M('m')─── 214 | │ 215 | 1: ───Ry(0.064π)───M──────── 216 | │ 217 | 2: ───Ry(1.0π)─────M──────── 218 | │ 219 | 3: ───Ry(1.96π)────M──────── 220 | Stats {10: 987, 11: 2, 14: 10, 2: 1} 221 | Theta: [1.00923065 0.06438729 1.00261814 1.96234334] Expectation: -1.486 222 | 0: ───Ry(1.05π)────M('m')─── 223 | │ 224 | 1: ───Ry(0.015π)───M──────── 225 | │ 226 | 2: ───Ry(0.993π)───M──────── 227 | │ 228 | 3: ───Ry(1.96π)────M──────── 229 | Stats {10: 992, 2: 4, 11: 4} 230 | Theta: [1.0460436 0.01484253 0.99280163 1.96243892] Expectation: -1.488 231 | 0: ───Ry(1.03π)─────M('m')─── 232 | │ 233 | 1: ───Ry(-0.002π)───M──────── 234 | │ 235 | 2: ───Ry(1.01π)─────M──────── 236 | │ 237 | 3: ───Ry(1.97π)─────M──────── 238 | Stats {10: 1000} 239 | Theta: [ 1.02725271 -0.00215486 1.00821691 1.97228388] Expectation: -1.5 240 | 0: ───Ry(0.984π)───M('m')─── 241 | │ 242 | 1: ───Ry(-0.03π)───M──────── 243 | │ 244 | 2: ───Ry(0.975π)───M──────── 245 | │ 246 | 3: ───Ry(1.98π)────M──────── 247 | Stats {10: 996, 14: 1, 2: 3} 248 | Theta: [ 0.98435081 -0.030354 0.97469508 1.98439883] Expectation: -1.493 249 | 0: ───Ry(1.02π)─────M('m')─── 250 | │ 251 | 1: ───Ry(-0.008π)───M──────── 252 | │ 253 | 2: ───Ry(1.01π)─────M──────── 254 | │ 255 | 3: ───Ry(1.94π)─────M──────── 256 | Stats {10: 992, 11: 8} 257 | Theta: [ 1.02011704 -0.0082132 1.0117461 1.94267838] Expectation: -1.492 258 | 0: ───Ry(1.03π)─────M('m')─── 259 | │ 260 | 1: ───Ry(-0.016π)───M──────── 261 | │ 262 | 2: ───Ry(1.06π)─────M──────── 263 | │ 264 | 3: ───Ry(-1.99π)────M──────── 265 | Stats {10: 994, 8: 6} 266 | Theta: [ 1.02776569 -0.01559819 1.05580355 2.01050397] Expectation: -1.488 267 | 0: ───Ry(1.05π)─────M('m')─── 268 | │ 269 | 1: ───Ry(-0.006π)───M──────── 270 | │ 271 | 2: ───Ry(0.991π)────M──────── 272 | │ 273 | 3: ───Ry(1.98π)─────M──────── 274 | Stats {10: 993, 2: 6, 11: 1} 275 | Theta: [ 1.05240904 -0.00587039 0.99083891 1.97756798] Expectation: -1.487 276 | 0: ───Ry(1.01π)────M('m')─── 277 | │ 278 | 1: ───Ry(0.026π)───M──────── 279 | │ 280 | 2: ───Ry(1.01π)────M──────── 281 | │ 282 | 3: ───Ry(1.98π)────M──────── 283 | Stats {10: 997, 14: 1, 2: 2} 284 | Theta: [1.01543899 0.02643152 1.00637566 1.97633694] Expectation: -1.495 285 | 0: ───Ry(1.02π)─────M('m')─── 286 | │ 287 | 1: ───Ry(-0.006π)───M──────── 288 | │ 289 | 2: ───Ry(1.02π)─────M──────── 290 | │ 291 | 3: ───Ry(1.98π)─────M──────── 292 | Stats {10: 996, 8: 2, 2: 1, 11: 1} 293 | Theta: [ 1.02497445 -0.00636088 1.02101014 1.97987287] Expectation: -1.493 294 | 0: ───Ry(1.02π)─────M('m')─── 295 | │ 296 | 1: ───Ry(-0.008π)───M──────── 297 | │ 298 | 2: ───Ry(0.999π)────M──────── 299 | │ 300 | 3: ───Ry(1.98π)─────M──────── 301 | Stats {10: 999, 11: 1} 302 | Theta: [ 1.01683303 -0.00844474 0.99928454 1.9763114 ] Expectation: -1.499 303 | 0: ───Ry(1.02π)────M('m')─── 304 | │ 305 | 1: ───Ry(0.005π)───M──────── 306 | │ 307 | 2: ───Ry(1.01π)────M──────── 308 | │ 309 | 3: ───Ry(1.97π)────M──────── 310 | Stats {10: 997, 11: 3} 311 | Theta: [1.02462884 0.00508435 1.00696999 1.97271917] Expectation: -1.497 312 | 0: ───Ry(1.03π)─────M('m')─── 313 | │ 314 | 1: ───Ry(-0.002π)───M──────── 315 | │ 316 | 2: ───Ry(1.01π)─────M──────── 317 | │ 318 | 3: ───Ry(1.98π)─────M──────── 319 | Stats {10: 994, 11: 4, 2: 2} 320 | Theta: [ 1.02933064e+00 -1.80830956e-03 1.00691012e+00 1.97530269e+00] Expectation: -1.492 321 | 0: ───Ry(1.02π)─────M('m')─── 322 | │ 323 | 1: ───Ry(-0.004π)───M──────── 324 | │ 325 | 2: ───Ry(1.01π)─────M──────── 326 | │ 327 | 3: ───Ry(1.97π)─────M──────── 328 | Stats {10: 997, 11: 2, 2: 1} 329 | Theta: [ 1.02482034 -0.00388304 1.00946727 1.96517272] Expectation: -1.496 330 | 0: ───Ry(1.02π)─────M('m')─── 331 | │ 332 | 1: ───Ry(-0.003π)───M──────── 333 | │ 334 | 2: ───Ry(1.01π)─────M──────── 335 | │ 336 | 3: ───Ry(1.97π)─────M──────── 337 | Stats {10: 990, 11: 4, 2: 6} 338 | Theta: [ 1.0254481 -0.00254193 1.01131725 1.97378062] Expectation: -1.484 339 | 0: ───Ry(1.03π)─────M('m')─── 340 | │ 341 | 1: ───Ry(-0.001π)───M──────── 342 | │ 343 | 2: ───Ry(1.01π)─────M──────── 344 | │ 345 | 3: ───Ry(1.97π)─────M──────── 346 | Stats {10: 998, 11: 1, 2: 1} 347 | Theta: [ 1.02842141e+00 -1.08926768e-03 1.00925970e+00 1.97180852e+00] Expectation: -1.497 348 | 0: ───Ry(1.02π)────M('m')─── 349 | │ 350 | 1: ───Ry(0.001π)───M──────── 351 | │ 352 | 2: ───Ry(1.01π)────M──────── 353 | │ 354 | 3: ───Ry(1.97π)────M──────── 355 | Stats {10: 997, 2: 2, 11: 1} 356 | Theta: [1.02535536e+00 8.43345073e-04 1.00660283e+00 1.97203014e+00] Expectation: -1.495 357 | 0: ───Ry(1.03π)─────M('m')─── 358 | │ 359 | 1: ───Ry(-0.004π)───M──────── 360 | │ 361 | 2: ───Ry(1.01π)─────M──────── 362 | │ 363 | 3: ───Ry(1.97π)─────M──────── 364 | Stats {10: 991, 2: 7, 11: 2} 365 | Theta: [ 1.02789704 -0.00407648 1.00633407 1.969526 ] Expectation: -1.484 366 | 0: ───Ry(1.03π)─────M('m')─── 367 | │ 368 | 1: ───Ry(-0.003π)───M──────── 369 | │ 370 | 2: ───Ry(1.01π)─────M──────── 371 | │ 372 | 3: ───Ry(1.97π)─────M──────── 373 | Stats {10: 998, 2: 1, 11: 1} 374 | Theta: [ 1.02757488 -0.00311567 1.00727549 1.97090494] Expectation: -1.497 375 | 0: ───Ry(1.03π)─────M('m')─── 376 | │ 377 | 1: ───Ry(-0.001π)───M──────── 378 | │ 379 | 2: ───Ry(1.01π)─────M──────── 380 | │ 381 | 3: ───Ry(1.97π)─────M──────── 382 | Stats {10: 993, 2: 3, 11: 3, 8: 1} 383 | Theta: [ 1.02678777e+00 -1.44505369e-03 1.00775439e+00 1.97214332e+00] Expectation: -1.489 384 | 0: ───Ry(1.03π)─────M('m')─── 385 | │ 386 | 1: ───Ry(-0.002π)───M──────── 387 | │ 388 | 2: ───Ry(1.01π)─────M──────── 389 | │ 390 | 3: ───Ry(1.97π)─────M──────── 391 | Stats {10: 995, 2: 2, 11: 3} 392 | Theta: [ 1.02755956 -0.00209925 1.00792276 1.97251765] Expectation: -1.493 393 | 0: ───Ry(1.03π)─────M('m')─── 394 | │ 395 | 1: ───Ry(-0.003π)───M──────── 396 | │ 397 | 2: ───Ry(1.01π)─────M──────── 398 | │ 399 | 3: ───Ry(1.97π)─────M──────── 400 | Stats {10: 998, 11: 2} 401 | Theta: [ 1.02693303 -0.0027061 1.0089526 1.97220409] Expectation: -1.498 402 | 0: ───Ry(1.03π)─────M('m')─── 403 | │ 404 | 1: ───Ry(-0.002π)───M──────── 405 | │ 406 | 2: ───Ry(1.01π)─────M──────── 407 | │ 408 | 3: ───Ry(1.97π)─────M──────── 409 | Stats {10: 991, 11: 6, 2: 2, 8: 1} 410 | Theta: [ 1.02755524 -0.00236078 1.00815378 1.97260091] Expectation: -1.488 411 | 0: ───Ry(1.03π)─────M('m')─── 412 | │ 413 | 1: ───Ry(-0.002π)───M──────── 414 | │ 415 | 2: ───Ry(1.01π)─────M──────── 416 | │ 417 | 3: ───Ry(1.97π)─────M──────── 418 | Stats {10: 995, 2: 2, 11: 2, 8: 1} 419 | Theta: [ 1.02718593 -0.00231472 1.00806037 1.9722126 ] Expectation: -1.492 420 | 0: ───Ry(1.03π)─────M('m')─── 421 | │ 422 | 1: ───Ry(-0.002π)───M──────── 423 | │ 424 | 2: ───Ry(1.01π)─────M──────── 425 | │ 426 | 3: ───Ry(1.97π)─────M──────── 427 | Stats {10: 996, 11: 2, 2: 2} 428 | Theta: [ 1.0275253 -0.00201538 1.00838839 1.97194439] Expectation: -1.494 429 | 0: ───Ry(1.03π)─────M('m')─── 430 | │ 431 | 1: ───Ry(-0.002π)───M──────── 432 | │ 433 | 2: ───Ry(1.01π)─────M──────── 434 | │ 435 | 3: ───Ry(1.97π)─────M──────── 436 | Stats {10: 997, 2: 2, 11: 1} 437 | Theta: [ 1.02711779 -0.00215422 1.00841462 1.97233193] Expectation: -1.495 438 | 0: ───Ry(1.03π)─────M('m')─── 439 | │ 440 | 1: ───Ry(-0.002π)───M──────── 441 | │ 442 | 2: ───Ry(1.01π)─────M──────── 443 | │ 444 | 3: ───Ry(1.97π)─────M──────── 445 | Stats {10: 996, 8: 1, 11: 1, 2: 2} 446 | Theta: [ 1.02721967e+00 -1.94163277e-03 1.00811674e+00 1.97233879e+00] Expectation: -1.493 447 | 0: ───Ry(1.03π)─────M('m')─── 448 | │ 449 | 1: ───Ry(-0.002π)───M──────── 450 | │ 451 | 2: ───Ry(1.01π)─────M──────── 452 | │ 453 | 3: ───Ry(1.97π)─────M──────── 454 | Stats {10: 996, 8: 1, 2: 2, 11: 1} 455 | Theta: [ 1.02732263 -0.00218261 1.00822805 1.97234883] Expectation: -1.493 456 | 0: ───Ry(1.03π)─────M('m')─── 457 | │ 458 | 1: ───Ry(-0.002π)───M──────── 459 | │ 460 | 2: ───Ry(1.01π)─────M──────── 461 | │ 462 | 3: ───Ry(1.97π)─────M──────── 463 | Stats {10: 998, 11: 1, 2: 1} 464 | Theta: [ 1.02728819 -0.00214558 1.00820712 1.97225134] Expectation: -1.497 465 | 0: ───Ry(1.03π)─────M('m')─── 466 | │ 467 | 1: ───Ry(-0.002π)───M──────── 468 | │ 469 | 2: ───Ry(1.01π)─────M──────── 470 | │ 471 | 3: ───Ry(1.97π)─────M──────── 472 | Stats {10: 999, 11: 1} 473 | Theta: [ 1.0271872 -0.00215041 1.0082891 1.97226204] Expectation: -1.499 474 | 0: ───Ry(1.03π)─────M('m')─── 475 | │ 476 | 1: ───Ry(-0.002π)───M──────── 477 | │ 478 | 2: ───Ry(1.01π)─────M──────── 479 | │ 480 | 3: ───Ry(1.97π)─────M──────── 481 | Stats {10: 995, 2: 5} 482 | Theta: [ 1.02724933 -0.00220197 1.008212 1.97226823] Expectation: -1.49 483 | 0: ───Ry(1.03π)─────M('m')─── 484 | │ 485 | 1: ───Ry(-0.002π)───M──────── 486 | │ 487 | 2: ───Ry(1.01π)─────M──────── 488 | │ 489 | 3: ───Ry(1.97π)─────M──────── 490 | Stats {10: 994, 2: 5, 11: 1} 491 | Theta: [ 1.02721832 -0.00207302 1.00818504 1.97231713] Expectation: -1.489 492 | fun: -1.489 493 | maxcv: 0.0 494 | message: 'Optimization terminated successfully.' 495 | nfev: 54 496 | status: 1 497 | success: True 498 | x: array([ 1.02721832, -0.00207302, 1.00818504, 1.97231713]) 499 | 0: ───Ry(1.03π)─────M('m')─── 500 | │ 501 | 1: ───Ry(-0.002π)───M──────── 502 | │ 503 | 2: ───Ry(1.01π)─────M──────── 504 | │ 505 | 3: ───Ry(1.97π)─────M──────── 506 | VQE Results: Minimum Hamiltonian Energy:-1.489 at theta: [ 1.02721832 -0.00207302 1.00818504 1.97231713] 507 | Histogram for optimized State: {10: 996, 2: 1, 11: 2, 8: 1} 508 | 509 | Process finished with exit code 0v -------------------------------------------------------------------------------- /Chapter_7/listing7_1/vqe_cirq.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | print('cirq version',cirq.__version__) 3 | import numpy as np 4 | print('numpy version',np.__version__) 5 | import scipy 6 | from scipy.optimize import minimize 7 | print('scipy version',scipy.__version__) 8 | 9 | 10 | def setup_vqe(hamiltonian_bases=['ZZZ'], hamiltonian_scales=[-1.0]): 11 | 12 | num_qubits = len(hamiltonian_bases[0]) 13 | eigen_values_dict = {} 14 | 15 | for base,scale in zip(hamiltonian_bases,hamiltonian_scales): 16 | eigen_values = [] 17 | for i, char in enumerate(base): 18 | if char == 'Z': 19 | eigens = np.array([1, -1]) 20 | elif char == 'I': 21 | eigens = np.array([1, 1]) 22 | else: 23 | raise NotImplementedError(f"The Gate {char} is yet to be implemented") 24 | 25 | if len(eigen_values) == 0: 26 | eigen_values = eigens 27 | else: 28 | eigen_values = np.outer(eigen_values, eigens).flatten() 29 | 30 | eigen_values_dict_elem = {} 31 | 32 | for i, x in enumerate(list(eigen_values)): 33 | eigen_values_dict_elem[i] = scale * x 34 | 35 | eigen_values_dict[base] = eigen_values_dict_elem 36 | 37 | 38 | return eigen_values_dict, num_qubits 39 | 40 | 41 | def ansatz_parameterized(theta,num_qubits=3): 42 | """ 43 | Create an Ansatz 44 | :param theta: 45 | :param num_qubits: 46 | :return: 47 | """ 48 | qubits = [cirq.LineQubit(c) for c in range(num_qubits)] 49 | circuit = cirq.Circuit() 50 | for i in range(num_qubits): 51 | circuit.append(cirq.ry(theta[i]*np.pi)(qubits[i])) 52 | circuit.append(cirq.measure(*qubits, key='m')) 53 | print(circuit) 54 | return circuit, qubits 55 | 56 | 57 | def compute_expectation(circuit, eigen_value_dict={}, copies=10000) -> float: 58 | sim = cirq.Simulator() 59 | results = sim.run(circuit, repetitions=copies) 60 | output = dict(results.histogram(key='m')) 61 | print('Stats', output) 62 | _expectation_ = 0 63 | for base in list(eigen_value_dict.keys()): 64 | for i in list(output.keys()): 65 | _expectation_ += eigen_value_dict[base][i] * output[i] 66 | 67 | _expectation_ = _expectation_ / copies 68 | 69 | return _expectation_ 70 | 71 | 72 | def VQE_routine(hamiltonian_bases=['ZZZ'], hamiltonian_scales=[1.], copies=1000, 73 | initial_theta=[0.5, 0.5, 0.5], verbose=True): 74 | eigen_value_dict, num_qubits = setup_vqe(hamiltonian_bases=hamiltonian_bases, 75 | hamiltonian_scales=hamiltonian_scales) 76 | print(eigen_value_dict) 77 | initial_theta = np.array(initial_theta) 78 | 79 | def objective(theta): 80 | circuit, qubits = ansatz_parameterized(theta, num_qubits) 81 | expectation = compute_expectation(circuit, eigen_value_dict, copies) 82 | if verbose: 83 | print(f" Theta: {theta} Expectation: {expectation}") 84 | return expectation 85 | 86 | result = minimize(objective, x0=initial_theta, method='COBYLA') 87 | print(result) 88 | circuit, _ = ansatz_parameterized(result.x, num_qubits) 89 | sim = cirq.Simulator() 90 | results = sim.run(circuit, repetitions=copies) 91 | stats = dict(results.histogram(key='m')) 92 | return result.x, result.fun, stats 93 | 94 | 95 | if __name__ == '__main__': 96 | optim_theta, optim_func, hist_stats = VQE_routine(hamiltonian_bases=['IIZZ','IZIZ','IZZI','ZIIZ','ZZII'], hamiltonian_scales=[0.5,.5,.50,.50,.50], 97 | initial_theta=[0.5, 0.5,0.5,0.5]) 98 | print(f"VQE Results: Minimum Hamiltonian Energy:{optim_func} at theta: {optim_theta}") 99 | print(f"Histogram for optimized State:", hist_stats) 100 | 101 | 102 | -------------------------------------------------------------------------------- /Chapter_7/listing7_2/Max_cut_clustering.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | from vqe_cirq import * 3 | import numpy as np 4 | import networkx as nx 5 | import matplotlib.pyplot as plt 6 | 7 | 8 | class QuantumMaxCutClustering: 9 | 10 | def __init__(self, adjacency_matrix: np.ndarray, invert_adjacency=True): 11 | self.adjacency_matrix = adjacency_matrix 12 | self.num_vertices = self.adjacency_matrix.shape[0] 13 | self.hamiltonian_basis_template = 'I' * self.num_vertices 14 | if invert_adjacency: 15 | self.hamiltonian = 1 - self.adjacency_matrix 16 | else: 17 | self.hamiltonian = self.adjacency_matrix 18 | 19 | def create_max_cut_hamiltonian(self): 20 | 21 | hamiltonian_bases, hamiltonian_coefficients = [], [] 22 | for i in range(self.num_vertices): 23 | for j in range(i + 1, self.num_vertices): 24 | if self.hamiltonian[i, j] > 0: 25 | hamiltonian_coefficients.append(self.hamiltonian[i, j]) 26 | 27 | hamiltonian_base = '' 28 | for k, c in enumerate(self.hamiltonian_basis_template): 29 | if k in [i, j]: 30 | hamiltonian_base += 'Z' 31 | else: 32 | hamiltonian_base += self.hamiltonian_basis_template[k] 33 | hamiltonian_bases.append(hamiltonian_base) 34 | return hamiltonian_bases, hamiltonian_coefficients 35 | 36 | def vqe_simulation(self, hamiltonian_bases, 37 | hamiltonian_coefficients, 38 | initial_theta=None, 39 | copies=10000): 40 | if initial_theta is None: 41 | initial_theta = [0.5] * self.num_vertices 42 | optim_theta, optim_func, hist_stats = \ 43 | VQE_routine(hamiltonian_bases=hamiltonian_bases, 44 | hamiltonian_scales=hamiltonian_coefficients, 45 | initial_theta=initial_theta, 46 | copies=copies) 47 | solution_stat = max(hist_stats, key=hist_stats.get) 48 | solution_stat = bin(solution_stat).replace("0b", "") 49 | solution_stat = (self.num_vertices - len(solution_stat)) * "0" + solution_stat 50 | 51 | return optim_theta, optim_func, hist_stats, solution_stat 52 | 53 | def max_cut_cluster(self, distance_matrix, solution_state): 54 | print(distance_matrix) 55 | G = nx.Graph() 56 | G.add_nodes_from(np.arange(0, self.num_vertices, 1)) 57 | edge_list = [] 58 | for i in range(self.num_vertices): 59 | for j in range(i + 1, self.num_vertices): 60 | if distance_matrix[i, j] > 0: 61 | edge_list.append((i, j, 1.0)) 62 | G.add_weighted_edges_from(edge_list) 63 | colors = [] 64 | for s in solution_state: 65 | if int(s) == 1: 66 | colors.append('r') 67 | else: 68 | colors.append('b') 69 | pos = nx.spring_layout(G) 70 | default_axes = plt.axes(frameon=True) 71 | nx.draw_networkx(G, node_color=colors, node_size=600, alpha=.8, ax=default_axes, pos=pos) 72 | plt.savefig('Maxcut_clustering.png') 73 | 74 | 75 | def main(self): 76 | hamiltonian_bases, hamiltonian_coefficients = self.create_max_cut_hamiltonian() 77 | print(hamiltonian_bases) 78 | optim_theta, optim_func, \ 79 | hist_stats, solution_state = self.vqe_simulation(hamiltonian_bases, 80 | hamiltonian_coefficients) 81 | 82 | print(f"VQE Results: Minimum Hamiltonian Energy:{optim_func} at theta: {optim_theta}") 83 | print(f"Histogram for optimized State:", hist_stats) 84 | print(f"Solution state: {solution_state}") 85 | self.max_cut_cluster(distance_matrix=self.hamiltonian, solution_state=solution_state) 86 | 87 | 88 | if __name__ == '__main__': 89 | adjacency_matrix = np.array([[0, 0, 0, 0], 90 | [0, 0, 0, 1], 91 | [0, 0, 0, 0], 92 | [0, 1, 0, 0]]) 93 | mc = QuantumMaxCutClustering(adjacency_matrix=adjacency_matrix) 94 | mc.main() 95 | -------------------------------------------------------------------------------- /Chapter_7/listing7_2/Maxcut_clustering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/quantum-machine-learning-python/7d22e2cebd807003ff098cc1138356d775014163/Chapter_7/listing7_2/Maxcut_clustering.png -------------------------------------------------------------------------------- /Chapter_7/listing7_3/QAOA.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | print('cirq version',cirq.__version__) 4 | print('np version', np.__version__) 5 | 6 | 7 | 8 | 9 | class QAOA: 10 | 11 | def __init__(self, num_elems:int, 12 | hamiltonian_type:str, 13 | hamiltonian_interactions:np.ndarray, 14 | verbose=True): 15 | self.num_elems = num_elems 16 | self.hamiltonian_type = hamiltonian_type 17 | self.hamiltonian_interactions = hamiltonian_interactions 18 | self.verbose = verbose 19 | if self.hamiltonian_type not in ['isling']: 20 | raise ValueError(f"No support for the Hamiltonian type {self.hamiltonian_type}") 21 | self.qubits = [cirq.LineQubit(x) for x in range(num_elems)] 22 | 23 | 24 | @staticmethod 25 | def interaction_gate(q1, q2, gamma=1): 26 | circuit = cirq.Circuit() 27 | circuit.append(cirq.CZ(q1, q2)**gamma) 28 | circuit.append([cirq.X(q2), cirq.CZ(q1, q2)**(-gamma), cirq.X(q2)]) 29 | circuit.append([cirq.X(q1), cirq.CZ(q1, q2) **(-gamma), cirq.X(q1)]) 30 | circuit.append([cirq.X(q1), cirq.X(q2), cirq.CZ(q1, q2) ** gamma, cirq.X(q1), cirq.X(q2)]) 31 | return circuit 32 | 33 | # Build the Target Hamiltonian based circuit Evolution 34 | def target_hamiltonian_evolution_circuit(self, gamma): 35 | circuit = cirq.Circuit() 36 | # Apply the interaction gates to all the qubit pairs 37 | 38 | for i in range(self.num_elems): 39 | 40 | for j in range(i+1, self.num_elems): 41 | circuit.append(self.interaction_gate( 42 | self.qubits[i], self.qubits[j], 43 | gamma=gamma)) 44 | return circuit 45 | 46 | # Build the Starting Hamiltonian based evolution circuit 47 | def starting_hamiltonian_evolution_circuit(self, beta): 48 | for i in range(self.num_elems): 49 | yield cirq.X(self.qubits[i])**beta 50 | 51 | def build_qoaa_circuit(self, gamma_store, beta_store): 52 | self.circuit = cirq.Circuit() 53 | # Hadamard gate on each qubit to get an equal superposition state 54 | print(self.qubits) 55 | self.circuit.append(cirq.H.on_each(self.qubits)) 56 | 57 | for i in range(len(gamma_store)): 58 | self.circuit.append(self.target_hamiltonian_evolution_circuit(gamma_store[i])) 59 | self.circuit.append(self.starting_hamiltonian_evolution_circuit(beta_store[i])) 60 | 61 | def simulate(self): 62 | #print(self.circuit) 63 | sim = cirq.Simulator() 64 | waveform = sim.simulate(self.circuit) 65 | return waveform 66 | 67 | 68 | def expectation(self,waveform): 69 | 70 | expectation = 0 71 | prob_from_waveform = (np.absolute(waveform.final_state))**2 72 | #print(prob_from_waveform) 73 | for i in range(len(prob_from_waveform)): 74 | base = bin(i).replace("0b", "") 75 | base = (self.num_elems - len(base))*'0' + base 76 | base_array = [] 77 | for b in base: 78 | if int(b) == 0: 79 | base_array.append(-1) 80 | else: 81 | base_array.append(1) 82 | 83 | base_array = np.array(base_array) 84 | base_interactions = np.outer(base_array, base_array) 85 | #print(i, prob_from_waveform[i], np.sum(np.multiply(base_interactions,self.hamiltonian_interactions))) 86 | expectation =+ prob_from_waveform[i]*np.sum(np.multiply(base_interactions,self.hamiltonian_interactions)) 87 | return expectation 88 | 89 | def optimize_params(self, gammas, betas, verbose=True): 90 | expectation_dict = {} 91 | waveforms_dict = {} 92 | for i, gamma in enumerate(gammas): 93 | for j, beta in enumerate(betas): 94 | self.build_qoaa_circuit([gamma],[beta]) 95 | waveform = self.simulate() 96 | expectation = self.expectation(waveform) 97 | expectation_dict[(gamma,beta)] = expectation 98 | waveforms_dict[(gamma,beta)] = waveform.final_state 99 | if verbose: 100 | print(f"Expectation for gamma:{gamma}, beta:{beta} = {expectation}") 101 | return expectation_dict, waveforms_dict 102 | 103 | 104 | def main(self): 105 | gammas = np.linspace(0, 1,50) 106 | betas = np.linspace(0, np.pi, 50) 107 | expectation_dict, waveform_dict = self.optimize_params(gammas, betas) 108 | expectation_vals = np.array(list(expectation_dict.values())) 109 | expectation_params = list(expectation_dict.keys()) 110 | waveform_vals = np.array(list(waveform_dict.values())) 111 | optim_param = expectation_params[np.argmin(expectation_vals)] 112 | optim_expectation = expectation_vals[np.argmin(expectation_vals)] 113 | optim_waveform = waveform_vals[np.argmin(expectation_vals)] 114 | print(f"Optimized parameters") 115 | print(f"-----------------------------") 116 | print(f" gamma,beta = {optim_param[0]}, {optim_param[1]}") 117 | print(f" Expectation = {optim_expectation}") 118 | print(f"-----------------------------") 119 | optimal_waveform_prob = np.array([np.abs(x)**2 for x in optim_waveform]) 120 | states = np.array([bin(i).replace('0b', "") for i in range(2 ** self.num_elems)]) 121 | states = np.array([((self.num_elems - len(s)) * '0' + s) for s in states]) 122 | sort_indices = np.argsort(-1 * np.array(optimal_waveform_prob)) 123 | print(sort_indices) 124 | optimal_waveform_prob = optimal_waveform_prob[sort_indices] 125 | states = states[sort_indices] 126 | print(f"State | Probability") 127 | print(f"-----------------------------") 128 | for i in range(len(states)): 129 | print(f"{states[i]} | {np.round(optimal_waveform_prob[i],3)}") 130 | print(f"-----------------------------") 131 | 132 | return expectation_dict 133 | 134 | 135 | if __name__ == '__main__': 136 | hamiltonian_interaction = np.array([[0,-1,-1,-1], 137 | [0,0,-1,-1], 138 | [0,0,0,-1], 139 | [0,0,0,0]]) 140 | qaoa_obj = QAOA(num_elems=4, 141 | hamiltonian_type='isling', 142 | hamiltonian_interactions=hamiltonian_interaction) 143 | expectation_dict = qaoa_obj.main() 144 | -------------------------------------------------------------------------------- /Chapter_7/listing7_3/listing_7.3_output.txt: -------------------------------------------------------------------------------- 1 | Expectation for gamma:1.0, beta:3.141592653589793 = -0.37499991059303284 2 | Optimized parameters 3 | ----------------------------- 4 | gamma,beta = 0.12244897959183673, 1.6669675304762166 5 | Expectation = -2.237522542476654 6 | ----------------------------- 7 | [ 0 15 12 9 10 6 3 5 14 13 1 4 8 11 2 7] 8 | State | Probability 9 | ----------------------------- 10 | 0000 | 0.373 11 | ----------------------------- 12 | 1111 | 0.373 13 | ----------------------------- 14 | 1100 | 0.03 15 | ----------------------------- 16 | 1001 | 0.03 17 | ----------------------------- 18 | 1010 | 0.03 19 | ----------------------------- 20 | 0110 | 0.03 21 | ----------------------------- 22 | 0011 | 0.03 23 | ----------------------------- 24 | 0101 | 0.03 25 | ----------------------------- 26 | 1110 | 0.009 27 | ----------------------------- 28 | 1101 | 0.009 29 | ----------------------------- 30 | 0001 | 0.009 31 | ----------------------------- 32 | 0100 | 0.009 33 | ----------------------------- 34 | 1000 | 0.009 35 | ----------------------------- 36 | 1011 | 0.009 37 | ----------------------------- 38 | 0010 | 0.009 39 | ----------------------------- 40 | 0111 | 0.009 41 | ----------------------------- 42 | 43 | Process finished with exit code 0 44 | -------------------------------------------------------------------------------- /Chapter_7/listing7_4/Listing_figure_7.4.amplitude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/quantum-machine-learning-python/7d22e2cebd807003ff098cc1138356d775014163/Chapter_7/listing7_4/Listing_figure_7.4.amplitude.png -------------------------------------------------------------------------------- /Chapter_7/listing7_4/quantum_random_walk.py: -------------------------------------------------------------------------------- 1 | import cirq 2 | import numpy as np 3 | import matplotlib 4 | import matplotlib.pyplot as plt 5 | import networkx as nx 6 | print('cirq version', cirq.__version__) 7 | print('numpy version', np.__version__) 8 | print('matplotlib version', matplotlib.__version__) 9 | print('networkx version', nx.__version__) 10 | 11 | 12 | class GraphQuantumRandomWalk: 13 | 14 | def __init__(self, graph_hamiltonian, t, verbose=True): 15 | self.graph_ham = graph_hamiltonian 16 | self.num_vertices = self.graph_ham.shape[0] 17 | self.num_qubits = int(np.log2(self.num_vertices)) 18 | self.qubits = [cirq.LineQubit(i) for i in range(self.num_qubits)] 19 | self.t = t 20 | self.verbose = verbose 21 | 22 | @staticmethod 23 | def diagonal_exponential(qubits, eigen_vals, t): 24 | circuit = cirq.Circuit() 25 | q1 = qubits[0] 26 | q2 = qubits[1] 27 | circuit.append(cirq.CZ(q1, q2) ** (-eigen_vals[-1] * t / np.pi)) 28 | circuit.append([cirq.X(q2), cirq.CZ(q1, q2) ** (-eigen_vals[-2] * t / np.pi), cirq.X(q2)]) 29 | circuit.append([cirq.X(q1), cirq.CZ(q1, q2) ** (-eigen_vals[-3] * t / np.pi), cirq.X(q1)]) 30 | circuit.append( 31 | [cirq.X(q1), cirq.X(q2), cirq.CZ(q1, q2) ** (-eigen_vals[-4] * t / np.pi), cirq.X(q1), cirq.X(q2)]) 32 | return circuit 33 | 34 | def unitary(self): 35 | eigen_vals, eigen_vecs = np.linalg.eigh(self.graph_ham) 36 | idx = eigen_vals.argsort()[::-1] 37 | eigen_vals = eigen_vals[idx] 38 | eigen_vecs = eigen_vecs[:, idx] 39 | if self.verbose: 40 | print(f"The Eigen values: {eigen_vals}") 41 | 42 | self.circuit = cirq.Circuit() 43 | self.circuit.append(cirq.H.on_each(self.qubits)) 44 | self.circuit += self.diagonal_exponential(self.qubits, eigen_vals, self.t) 45 | self.circuit.append(cirq.H.on_each(self.qubits)) 46 | 47 | def simulate(self): 48 | sim = cirq.Simulator() 49 | results = sim.simulate(self.circuit).final_state 50 | prob_dist = [np.abs(a) ** 2 for a in results] 51 | return prob_dist 52 | 53 | def main(self): 54 | self.unitary() 55 | prob_dist = self.simulate() 56 | if self.verbose: 57 | print(f"The converged prob_dist: {prob_dist}") 58 | return prob_dist 59 | 60 | 61 | if __name__ == '__main__': 62 | graph_hamiltonian = np.ones((4, 4)) 63 | #graph_hamiltonian = np.array([[1, 1, 1, 0], [1, 1, 0, 1], [1, 0, 1, 1], [0, 1, 1, 1]]) 64 | time_to_simulate = 4 65 | steps = 80 66 | time_trace = [] 67 | prob_dist_trace = [] 68 | for t in np.linspace(0, time_to_simulate): 69 | gqrq = GraphQuantumRandomWalk(graph_hamiltonian=graph_hamiltonian, t=t) 70 | prob_dist = gqrq.main() 71 | time_trace.append(t) 72 | prob_dist_trace.append(prob_dist) 73 | prob_dist_trace = np.array(prob_dist_trace) 74 | plt.plot(time_trace, prob_dist_trace[:, 0]) 75 | plt.show() 76 | rows, cols = np.where(graph_hamiltonian == 1) 77 | edges = zip(rows.tolist(), cols.tolist()) 78 | gr = nx.Graph() 79 | gr.add_edges_from(edges) 80 | nx.draw(gr,node_size=4) 81 | plt.show() -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2021 Santanu Pattanayak 4 | 5 | Permission is hereby granted, free of charge, to anyone obtaining a copy 6 | of this software and associated documentation files (the "Software"), 7 | to work with the Software within the limits of freeware distribution and fair use. 8 | This includes the rights to use, copy, and modify the Software for personal use. 9 | Users are also allowed and encouraged to submit corrections and modifications 10 | to the Software for the benefit of other users. 11 | 12 | It is not allowed to reuse, modify, or redistribute the Software for 13 | commercial use in any way, or for a user’s educational materials such as books 14 | or blog articles without prior permission from the copyright holder. 15 | 16 | The above copyright notice and this permission notice need to be included 17 | in all copies or substantial portions of the software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Quantum Machine Learning with Python*](https://www.apress.com/9781484265215) by Santanu Pattanayak (Apress, 2021). 4 | 5 | [comment]: #cover 6 | ![Cover image](9781484265215.jpg) 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | # Errata for *Quantum Machine Learning with Python* 2 | 3 | On **page 17** [Technical Accuracy]: 4 | 5 | The text states that the inner product between two vectors is symmetric, but it's only conjugate symmetric. 6 | 7 | *** 8 | 9 | On **page xx** [Summary of error]: 10 | 11 | Details of error here. Highlight key pieces in **bold**. 12 | 13 | *** --------------------------------------------------------------------------------