├── .gitignore
├── README.md
├── chapter01
└── problems
│ └── chapter01.pdf
├── chapter02
└── problems
│ └── chapter02.pdf
├── chapter03
└── problems
│ └── chapter03.pdf
├── chapter04
└── problems
│ └── chapter04.pdf
├── chapter05
└── problems
│ └── chapter05.pdf
├── chapter06
├── cirq
│ ├── cirq-basic.py
│ ├── cirq-bell-state.py
│ ├── cirq-parameters.py
│ └── param-sweep-cirq.pdf
├── forest
│ └── pyquil-basic.py
├── qdk
│ ├── Driver.cs
│ ├── Operations.qs
│ ├── README
│ └── Simple.csproj
└── qiskit
│ ├── qiskit-basic-circuit.png
│ └── qiskit-basic.py
├── chapter07
├── .DS_Store
├── cirq
│ ├── bell-inequality-test.py
│ ├── superdense-coding-cirq.py
│ └── teleportation-cirq.py
└── qiskit
│ ├── superdense-coding.py
│ └── teleportation.py
├── chapter08
├── .DS_Store
├── cirq
│ ├── bernstein-vazirani.py
│ ├── deutsch-jozsa.py
│ ├── deutsch.py
│ ├── grover.py
│ ├── qft.py
│ └── shor.ipynb
└── problems
│ └── chapter08.pdf
├── chapter09
├── cirq
│ ├── hhl.py
│ ├── qaoa.py
│ ├── qchem.py
│ ├── qnn.py
│ ├── qpe.py
│ └── random-bit.py
├── problems
│ └── chapter09.pdf
└── pyquil
│ └── qaoa.py
├── chapter10
└── cirq
│ ├── example-supremacy-circuit.txt
│ └── supremacy-cirquit.png
├── img
└── qc2e.png
├── korean
├── README.md
├── chapter01
│ └── problems
│ │ └── chapter01.pdf
├── chapter02
│ └── problems
│ │ └── chapter02.pdf
├── chapter03
│ └── problems
│ │ └── chapter03.pdf
├── chapter04
│ └── problems
│ │ └── chapter04.pdf
├── chapter05
│ └── problems
│ │ └── chapter05.pdf
├── chapter06
│ ├── cirq
│ │ ├── cirq-basic.py
│ │ ├── cirq-bell-state.py
│ │ ├── cirq-parameters.py
│ │ └── param-sweep-cirq.pdf
│ ├── forest
│ │ └── pyquil-basic.py
│ ├── qdk
│ │ ├── Driver.cs
│ │ ├── Operations.qs
│ │ ├── README
│ │ └── Simple.csproj
│ └── qiskit
│ │ ├── qiskit-basic-circuit.png
│ │ └── qiskit-basic.py
├── chapter07
│ ├── .DS_Store
│ ├── cirq
│ │ ├── bell-inequality-test.py
│ │ ├── superdense-coding-cirq.py
│ │ └── teleportation-cirq.py
│ └── qiskit
│ │ ├── supderdense-coding.py
│ │ └── teleportation.py
├── chapter08
│ ├── .DS_Store
│ ├── cirq
│ │ ├── bernstein-vazirani.py
│ │ ├── deutsch-jozsa.py
│ │ ├── deutsch.py
│ │ ├── grover.py
│ │ ├── qft.py
│ │ └── shor.ipynb
│ └── problems
│ │ └── chapter08.pdf
├── chapter09
│ ├── cirq
│ │ ├── hhl.py
│ │ ├── qaoa.py
│ │ ├── qchem.py
│ │ ├── qnn.py
│ │ ├── qpe.py
│ │ └── random-bit.py
│ ├── problems
│ │ └── chapter09.pdf
│ └── pyquil
│ │ └── qaoa.py
└── chapter10
│ └── cirq
│ ├── example-supremacy-circuit.txt
│ └── supremacy-cirquit.png
├── notebooks
├── Cirq_Workshop_Bootcamp_Final.ipynb
├── IonDeviceTutorial.ipynb
├── NeutralAtom.ipynb
├── Quantum_simulation_of_electronic_structure.ipynb
├── qaoa_hands_on_pubV2.ipynb
└── textbook_algos_hands_on_pub.ipynb
├── presentations
├── Cirq Ion Trap Demo.pdf
├── Cirq Workshop Slides.pdf
├── Intro to Quantum Hardware (May 2019).pdf
└── QC Review (Bootcamp) V2.pdf
└── resources
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Online Site for Quantum Computing: An Applied Approach
4 |
5 | Welcome to the online site for *Quantum Computing: An Applied Approach published by Springer*. The Second Edition is now available in both kindle and hardcover versions!
6 |
7 | [Here is the link to the hardcover and kindle versions on Amazon.](https://www.amazon.com/Quantum-Computing-An-Applied-Approach-dp-3030832732/dp/3030832732/ref=dp_ob_title_bk)
8 |
9 | You will find a number of resources on this github site including:
10 | - Problem sets (the problem sets apply to both the first and second editions)
11 | - Code for the algorithms discussed in the book
12 | - Links to further resources
13 | - Updates to the book
14 |
15 | # Problem Sets
16 |
17 | * [Chapter 1](./chapter01/problems/chapter01.pdf)
18 |
19 | * [Chapter 2](./chapter02/problems/chapter02.pdf)
20 |
21 | * [Chapter 3](./chapter03/problems/chapter03.pdf)
22 |
23 | * [Chapter 4](./chapter04/problems/chapter04.pdf)
24 |
25 | * [Chapter 5](./chapter05/problems/chapter05.pdf)
26 |
27 | * [Chapter 8](./chapter08/problems/chapter08.pdf)
28 |
29 | * [Chapter 9](./chapter09/problems/chapter09.pdf)
30 |
31 | Additional problem sets for others chapters coming soon.
32 |
33 | The problem sets have been developed by: Jack Hidary, Ryan Larose, Stefan Leichenauer and James Myers. If you would like to contribute additional problems let us know! This is for the whole community. jack@hidary.com
34 |
35 | For faculty using the book as a course textbook please email jack@hidary.com for solutions.
36 |
37 | # Further Resources
38 |
39 | *[Recordings from Google's Cirq Bootcamp on May 10 - 11, 2019](https://drive.google.com/corp/drive/folders/18cCJ_AJ-YeCmK0XwD3QbC1ppdUe99ykc)*
40 |
41 | *Notebooks*
42 |
43 | * [Intro to writing quantum algorithms in Cirq](https://colab.research.google.com/drive/1mrDPc0HSBxgD_-wwif_gUGriM3VTNYoy#forceEdit=true&offline=true&sandboxMode=true)
44 | * [Quantum simulation of electronic structure](https://colab.research.google.com/drive/1-oQy0FTtio0P7wUCc3ge7PXlk7aWSAdM)
45 | * [Textbook algorithms in Cirq](https://colab.research.google.com/drive/1X0H39CWQzx2uO9UGiokdseWsxt6ckxOw)
46 | * [Quantum Approximate Optimization Algorithm - QAOA](https://colab.research.google.com/drive/1caKw0lZ3ovdxKVQ4QxkSKgTRlQ7DxLJZ)
47 | * [Neutral atom device class](https://colab.research.google.com/drive/1pO5JrX_ieW8KAxHIqWG_viZSE_F7LDCz)
48 | * [Ion device class](https://colab.research.google.com/drive/1p_SLX83UzudhHLeZ6UXx_GAp67ElxMXW)
49 |
50 | *Presentations*
51 |
52 | * [Quantum computing refresher](https://drive.google.com/file/d/1JPk_Isr3BzM7t1EZGW0jon2k-78Hn_W5/view?usp=sharing)
53 | * [Intro to quantum hardware](https://drive.google.com/file/d/1WSwXU_PVArN32tufvBIz2wp7kK2NPMbj/view?usp=sharing)
54 | * [Cirq ion trap demo](https://drive.google.com/file/d/1Bl2VxY9_W1SQ2yp3HasKGz3ielDTSvFO/view?usp=sharing)
55 | * [Cirq workshop](https://drive.google.com/file/d/10CD0j-RFUV5S7sO6x2fOKauYvBqurzt7/view?usp=sharing)
56 |
57 | *Zoos*
58 | * [The Quantum Protocol Zoo](https://wiki.veriqloud.fr)
59 | * [Quantum Algo Zoo](http://quantumalgorithmzoo.org/)
60 | * [Complexity Zoo](https://complexityzoo.uwaterloo.ca/Complexity_Zoo)
61 |
62 | ## Book Reviews
63 |
64 | "Quantum computer programming was until recently a completely theoretical enterprise. Now, rapid advances in quantum computing hardware have generated a new wave of interest in both academia and industry in programming these machines. Quantum Computing: An Applied Approach is for this new wave. Emphasizing the nuts and bolts of quantum computing, the textbook covers APIs for multiple platforms including Google, IBM, Microsoft and Rigetti. Author Jack Hidary guides readers through a range of examples from introductory programs all the way to Shor’s factoring algorithm; the textbook also covers applications that may prove useful in the nearer term and are the subject of active research in the field. For coursework, this book is an excellent practical complement to venerable classics such as Nielsen & Chuang that teach the field’s sometimes-daunting theoretical underpinnings. Hidary’s textbook will enable researchers and engineers to quickly ramp up in this emerging field."
65 |
66 | -- Patrick Hayden, Professor of Physics, Stanford University
67 |
68 |
69 | “This is the best book for a course in quantum computing that I have seen. It gives straightforward explanations of the foundations, history, and hardware, and it walks through executable code for many important algorithms. Additionally, the book brings the reader up to speed with all the math that is needed. I plan to use the book in my course on quantum programming.”
70 |
71 | -- Jens Palsberg, Professor of Computer Science, UCLA
72 |
73 |
74 | "Hidary's 'Quantum computing: An Applied Approach' provides a welcome bridge from traditional quantum computing texts to the NISQ era which we are now entering. The book takes a modern approach, following the treatment of each of the canonical algorithms with coded versions that can be run on actual quantum computers, along with a survey of various code libraries developed for this purpose. It continues with an overview of state-of-the-art variational and optimization methods such as VQE and QAOA, and a discussion, again with code, of random circuit sampling, the forefront application expected to provide a first realization of quantum supremacy. The book has a companion website for updates and ongoing addition of new resources and developments. By building on the substantial progress of the past five years, this book and its associated resources will facilitate the transition from how quantum computers might be used in principle to how they'll probably be used in practice over the next decade. "
75 |
76 | -- Paul Ginsparg, Professor of Physics, Cornell University
77 |
78 | "This book fills a gap in the literature on quantum computing. It is a welcome tool for training and reference with numerous practical code examples, arriving just in time for researchers and engineers in both academia and industry ready to get their hands dirty with programming quantum computers."
79 |
80 | -- Dennis Willsch, Jülich Supercomputing Centre
81 |
82 |
83 |
84 | # Contact
85 |
86 | Please email us at jack@hidary.com or jtricot1@gmail.com with comments and suggestions!
87 |
88 | Jack
89 |
90 |
--------------------------------------------------------------------------------
/chapter01/problems/chapter01.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter01/problems/chapter01.pdf
--------------------------------------------------------------------------------
/chapter02/problems/chapter02.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter02/problems/chapter02.pdf
--------------------------------------------------------------------------------
/chapter03/problems/chapter03.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter03/problems/chapter03.pdf
--------------------------------------------------------------------------------
/chapter04/problems/chapter04.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter04/problems/chapter04.pdf
--------------------------------------------------------------------------------
/chapter05/problems/chapter05.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter05/problems/chapter05.pdf
--------------------------------------------------------------------------------
/chapter06/cirq/cirq-basic.py:
--------------------------------------------------------------------------------
1 | """Simple program in Cirq."""
2 |
3 | # Import the Cirq package
4 | import cirq
5 |
6 | # Pick a qubit
7 | qubit = cirq.GridQubit(0, 0)
8 |
9 | # Create a circuit
10 | circuit = cirq.Circuit([
11 | cirq.X(qubit), # NOT.
12 | cirq.measure(qubit, key='m') # Measurement
13 | ]
14 | )
15 |
16 | # Display the circuit
17 | print("Circuit:")
18 | print(circuit)
19 |
20 | # Get a simulator to execute the circuit
21 | simulator = cirq.Simulator()
22 |
23 | # Simulate the circuit several times
24 | result = simulator.run(circuit, repetitions=10)
25 |
26 | # Print the results
27 | print("Results:")
28 | print(result)
29 |
--------------------------------------------------------------------------------
/chapter06/cirq/cirq-bell-state.py:
--------------------------------------------------------------------------------
1 | """Script for preparing the Bell state |\Phi^{+}> in Cirq."""
2 |
3 | # Import the Cirq library
4 | import cirq
5 |
6 | # Get qubits and circuit
7 | qreg = [cirq.LineQubit(x) for x in range(2)]
8 | circ = cirq.Circuit()
9 |
10 | # Add the Bell state preparation circuit
11 | circ.append([cirq.H(qreg[0]),
12 | cirq.CNOT(qreg[0], qreg[1])])
13 |
14 | # Display the circuit
15 | print("Circuit")
16 | print(circ)
17 |
18 | # Add measurements
19 | circ.append(cirq.measure(*qreg, key="z"))
20 |
21 | # Simulate the circuit
22 | sim = cirq.Simulator()
23 | res = sim.run(circ, repetitions=100)
24 |
25 | # Display the outcomes
26 | print("\nMeasurements:")
27 | print(res.histogram(key="z"))
--------------------------------------------------------------------------------
/chapter06/cirq/cirq-parameters.py:
--------------------------------------------------------------------------------
1 | """Working with parameterized gates in Cirq."""
2 |
3 | # Imports
4 | import matplotlib.pyplot as plt
5 | import sympy
6 |
7 | import cirq
8 |
9 | # Get a qubit and a circuit
10 | qbit = cirq.LineQubit(0)
11 | circ = cirq.Circuit()
12 |
13 | # Get a symbol
14 | symbol = sympy.Symbol("t")
15 |
16 | # Add a parameterized gate
17 | circ.append(cirq.XPowGate(exponent=symbol)(qbit))
18 |
19 | # Measure
20 | circ.append(cirq.measure(qbit, key="z"))
21 |
22 | # Display the circuit
23 | print("Circuit:")
24 | print(circ)
25 |
26 | # Get a sweep over parameter values
27 | sweep = cirq.Linspace(key=symbol.name, start=0.0, stop=2.0, length=100)
28 |
29 | # Execute the circuit for all values in the sweep
30 | sim = cirq.Simulator()
31 | res = sim.run_sweep(circ, sweep, repetitions=1000)
32 |
33 | # Plot the measurement outcomes at each value in the sweep
34 | angles = [x[0][1] for x in sweep.param_tuples()]
35 | zeroes = [res[i].histogram(key="z")[0] / 1000 for i in range(len(res))]
36 | plt.plot(angles, zeroes, "--", linewidth=3)
37 |
38 | # Plot options and formatting
39 | plt.ylabel("Frequency of 0 Measurements")
40 | plt.xlabel("Exponent of X gate")
41 | plt.grid()
42 |
43 | plt.savefig("param-sweep-cirq.pdf", format="pdf")
44 |
--------------------------------------------------------------------------------
/chapter06/cirq/param-sweep-cirq.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter06/cirq/param-sweep-cirq.pdf
--------------------------------------------------------------------------------
/chapter06/forest/pyquil-basic.py:
--------------------------------------------------------------------------------
1 | """Simple program in pyQuil."""
2 |
3 | # Import the pyQuil library
4 | import pyquil
5 |
6 | # Create a quantum program
7 | prog = pyquil.Program()
8 |
9 | # Declare a classical register
10 | creg = prog.declare("ro", memory_type="BIT", memory_size=1)
11 |
12 | # Add a NOT operation and measurement on a qubit
13 | prog += [
14 | pyquil.gates.X(0),
15 | pyquil.gates.MEASURE(0, creg[0])
16 | ]
17 |
18 | # Print the program
19 | print("Program:")
20 | print(prog)
21 |
22 | # Get a quantum computer to run on
23 | computer = pyquil.get_qc("1q-qvm")
24 |
25 | # Simulate the program many times
26 | prog.wrap_in_numshots_loop(10)
27 |
28 | # Execute the program on the computer
29 | result = computer.run(prog)
30 |
31 | # Print the results
32 | print("Result:")
33 | print(result)
34 |
--------------------------------------------------------------------------------
/chapter06/qdk/Driver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Microsoft.Quantum.Simulation.Core;
4 | using Microsoft.Quantum.Simulation.Simulators;
5 |
6 | namespace Quantum.Simple {
7 | class Driver {
8 | static void Main(string[] args) {
9 | // Get a quantum computer simulator
10 | using (var qsim = new QuantumSimulator()) {
11 | // Run the operation NotAndMeasure and get the result
12 | var num_ones = NotAndMeasure.Run(qsim, 10).Result;
13 |
14 | // Print the measurement outcome to the console
15 | System.Console.WriteLine(
16 | $"Number of ones measured: {num_ones, 0}.");
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/chapter06/qdk/Operations.qs:
--------------------------------------------------------------------------------
1 | namespace Quantum.Simple
2 | {
3 | // Importing the libraries
4 | open Microsoft.Quantum.Primitive;
5 | open Microsoft.Quantum.Canon;
6 |
7 | // Sets a qubit in a desired state
8 | operation Set(desired_state: Result, qubit: Qubit) : Unit {
9 | let current = M(qubit);
10 | if (current != desired_state) {
11 | X(qubit);
12 | }
13 | }
14 |
15 | // Executes the "not and measure" circuit for an input number
16 | // of repetitions and returns the number of ones measured
17 | operation NotAndMeasure(repetitions: Int) : Int {
18 | // Variable to store the number of measured ones
19 | mutable num_ones = 0;
20 |
21 | // Get a qubit to use
22 | using (qubit = Qubit()) {
23 | // Loop over the desired number of repetitions
24 | for (test in 1..repetitions) {
25 | // Get a qubit in the zero state
26 | Set(Zero, qubit);
27 |
28 | // Perform a NOT operation
29 | X(qubit);
30 |
31 | // Measure the qubit
32 | let res = M (qubit);
33 |
34 | // Keep track of the number of ones we measured
35 | if (res == One) {
36 | set num_ones = num_ones + 1;
37 | }
38 | }
39 | // "Released qubits" must be in the zero state to avoid a System.AggregateException
40 | Set(Zero, qubit);
41 | }
42 | // Return the number of ones measured
43 | return num_ones;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/chapter06/qdk/README:
--------------------------------------------------------------------------------
1 | To run the example program in the QDK:
2 |
3 | (1) Type `dotnet run` at a command line.
4 |
5 | (2) Run the file through visual studio or visual studio code.
6 |
7 | The output should be
8 |
9 | Number of ones measured: 10.
10 |
11 | When run, two directories called `bin` and `obj` are created.
12 |
13 |
--------------------------------------------------------------------------------
/chapter06/qdk/Simple.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.0
6 | x64
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter06/qiskit/qiskit-basic-circuit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter06/qiskit/qiskit-basic-circuit.png
--------------------------------------------------------------------------------
/chapter06/qiskit/qiskit-basic.py:
--------------------------------------------------------------------------------
1 | """Simple program in Qiskit."""
2 |
3 | # Import the Qiskit package
4 | import qiskit
5 |
6 | # Create a quantum register with one qubit
7 | qreg = qiskit.QuantumRegister(1, name='qreg')
8 |
9 | # Create a classical register with one qubit
10 | creg = qiskit.ClassicalRegister(1, name='creg')
11 |
12 | # Create a quantum circuit with the above registers
13 | circ = qiskit.QuantumCircuit(qreg, creg)
14 |
15 | # Add a NOT operation on the qubit
16 | circ.x(qreg[0])
17 |
18 | # Add a measurement on the qubit
19 | circ.measure(qreg, creg)
20 |
21 | # Print the circuit
22 | print(circ.draw())
23 |
24 | # Get a backend to run on
25 | backend = qiskit.BasicAer.get_backend("qasm_simulator")
26 |
27 | # Execute the circuit on the backend and get the measurement results
28 | job = qiskit.execute(circ, backend, shots=10)
29 | result = job.result()
30 |
31 | # Print the measurement results
32 | print(result.get_counts())
33 |
--------------------------------------------------------------------------------
/chapter07/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter07/.DS_Store
--------------------------------------------------------------------------------
/chapter07/cirq/bell-inequality-test.py:
--------------------------------------------------------------------------------
1 | """Creates and simulates a circuit equivalent to a Bell inequality test."""
2 |
3 | # Imports
4 | import numpy as np
5 |
6 | import cirq
7 |
8 |
9 | def main():
10 | # Create circuit
11 | circuit = make_bell_test_circuit()
12 | print('Circuit:')
13 | print(circuit)
14 |
15 | # Run simulations
16 | print()
17 | repetitions = 1000
18 | print('Simulating {} repetitions...'.format(repetitions))
19 | result = cirq.Simulator().run(program=circuit,
20 | repetitions=repetitions)
21 |
22 | # Collect results
23 | a = np.array(result.measurements['a'][:, 0])
24 | b = np.array(result.measurements['b'][:, 0])
25 | x = np.array(result.measurements['x'][:, 0])
26 | y = np.array(result.measurements['y'][:, 0])
27 |
28 | # Compute the winning percentage
29 | outcomes = a ^ b == x & y
30 | win_percent = len([e for e in outcomes if e]) * 100 / repetitions
31 |
32 | # Print data
33 | print()
34 | print('Results')
35 | print('a:', bitstring(a))
36 | print('b:', bitstring(b))
37 | print('x:', bitstring(x))
38 | print('y:', bitstring(y))
39 | print('(a XOR b) == (x AND y):\n ', bitstring(outcomes))
40 | print('Win rate: {}%'.format(win_percent))
41 |
42 |
43 | def make_bell_test_circuit():
44 | # Qubits for Alice, Bob, and referees
45 | alice = cirq.GridQubit(0, 0)
46 | bob = cirq.GridQubit(1, 0)
47 | alice_referee = cirq.GridQubit(0, 1)
48 | bob_referee = cirq.GridQubit(1, 1)
49 |
50 | circuit = cirq.Circuit()
51 |
52 | # Prepare shared entangled state between Alice and Bob
53 | circuit.append([
54 | cirq.H(alice),
55 | cirq.CNOT(alice, bob),
56 | cirq.X(alice)**-0.25,
57 | ])
58 |
59 | # Referees flip coins
60 | circuit.append([
61 | cirq.H(alice_referee),
62 | cirq.H(bob_referee),
63 | ])
64 |
65 | # Players do a sqrt(X) based on their referee's coin
66 | circuit.append([
67 | cirq.CNOT(alice_referee, alice)**0.5,
68 | cirq.CNOT(bob_referee, bob)**0.5,
69 | ])
70 |
71 | # Then results are recorded
72 | circuit.append([
73 | cirq.measure(alice, key='a'),
74 | cirq.measure(bob, key='b'),
75 | cirq.measure(alice_referee, key='x'),
76 | cirq.measure(bob_referee, key='y'),
77 | ])
78 |
79 | return circuit
80 |
81 |
82 | def bitstring(bits):
83 | return ''.join('1' if e else '_' for e in bits)
84 |
85 |
86 | if __name__ == '__main__':
87 | main()
88 |
--------------------------------------------------------------------------------
/chapter07/cirq/superdense-coding-cirq.py:
--------------------------------------------------------------------------------
1 | """Superdense coding in Cirq."""
2 |
3 | # Imports
4 | import cirq
5 |
6 | # Helper function for visualizing output
7 | def bitstring(bits):
8 | return ''.join('1' if e else '0' for e in bits)
9 |
10 | # Create two quantum and classical registers
11 | qreg = [cirq.LineQubit(x) for x in range(2)]
12 | circ = cirq.Circuit()
13 |
14 | # Dictionary of operations for each message
15 | message = {"00": [],
16 | "01": [cirq.X(qreg[0])],
17 | "10": [cirq.Z(qreg[0])],
18 | "11": [cirq.X(qreg[0]), cirq.Z(qreg[0])]}
19 |
20 | # Alice creates a Bell pair
21 | circ.append(cirq.H(qreg[0]))
22 | circ.append(cirq.CNOT(qreg[0], qreg[1]))
23 |
24 | # Alice picks a message to send
25 | m = "01"
26 | print("Alice's sent message =", m)
27 |
28 | # Alice encodes her message with the appropriate quantum operations
29 | circ.append(message[m])
30 |
31 | # Bob measures in the Bell basis
32 | circ.append(cirq.CNOT(qreg[0], qreg[1]))
33 | circ.append(cirq.H(qreg[0]))
34 | circ.append([cirq.measure(qreg[0]), cirq.measure(qreg[1])])
35 |
36 | # Print out the circuit
37 | print("\nCircuit:")
38 | print(circ)
39 |
40 | # Run the quantum circuit on a simulator backend
41 | sim = cirq.Simulator()
42 | res = sim.run(circ, repetitions=1)
43 |
44 | # Print out Bob's received message: the outcome of the circuit
45 | print("\nBob's received message =", bitstring(res.measurements.values()))
46 |
--------------------------------------------------------------------------------
/chapter07/cirq/teleportation-cirq.py:
--------------------------------------------------------------------------------
1 | """Quantum teleportation in Cirq. Modified from an example at:
2 |
3 | https://github.com/quantumlib/Cirq/blob/master/examples/quantum_teleportation.py
4 | """
5 |
6 | # Imports
7 | import random
8 |
9 | import cirq
10 |
11 |
12 | def make_quantum_teleportation_circuit(ranX, ranY):
13 | """Returns a quantum teleportation circuit."""
14 | circuit = cirq.Circuit()
15 | msg, alice, bob = cirq.LineQubit.range(3)
16 |
17 | # Creates Bell state to be shared between Alice and Bob
18 | circuit.append([cirq.H(alice), cirq.CNOT(alice, bob)])
19 |
20 | # Creates a random state for the Message
21 | circuit.append([cirq.X(msg)**ranX, cirq.Y(msg)**ranY])
22 |
23 | # Bell measurement of the Message and Alice's entangled qubit
24 | circuit.append([cirq.CNOT(msg, alice), cirq.H(msg)])
25 | circuit.append(cirq.measure(msg, alice))
26 |
27 | # Uses the two classical bits from the Bell measurement to recover the
28 | # original quantum Message on Bob's entangled qubit
29 | circuit.append([cirq.CNOT(alice, bob), cirq.CZ(msg, bob)])
30 |
31 | return msg, circuit
32 |
33 |
34 | def main():
35 | # Encode a random state to teleport
36 | ranX = random.random()
37 | ranY = random.random()
38 | msg, circuit = make_quantum_teleportation_circuit(ranX, ranY)
39 |
40 | # Simulate the circuit
41 | sim = cirq.Simulator()
42 | message = sim.simulate(cirq.Circuit(
43 | [cirq.X(msg)**ranX, cirq.Y(msg)**ranY]))
44 |
45 | # Print the Bloch Sphere of Alice's qubit
46 | print("Bloch Sphere of Alice's qubit:")
47 | b0X, b0Y, b0Z = cirq.bloch_vector_from_state_vector(
48 | message.final_state_vector, 0)
49 | print("x: ", round(b0X, 4),
50 | "y: ", round(b0Y, 4),
51 | "z: ", round(b0Z, 4))
52 |
53 | # Display the teleportation circuit
54 | print("\nCircuit:")
55 | print(circuit)
56 |
57 | # Record the final state of the simulation
58 | final_results = sim.simulate(circuit)
59 |
60 | # Print the Bloch sphere of Bob's qubit
61 | print("\nBloch Sphere of Bob's qubit:")
62 | b2X, b2Y, b2Z = cirq.bloch_vector_from_state_vector(
63 | final_results.final_state_vector, 2)
64 | print("x: ", round(b2X, 4),
65 | "y: ", round(b2Y, 4),
66 | "z: ", round(b2Z, 4))
67 |
68 |
69 | if __name__ == '__main__':
70 | main()
71 |
--------------------------------------------------------------------------------
/chapter07/qiskit/superdense-coding.py:
--------------------------------------------------------------------------------
1 | """Superdense coding."""
2 |
3 | # Imports
4 | import qiskit
5 |
6 | # Create two quantum and classical registers
7 | qreg = qiskit.QuantumRegister(2)
8 | creg = qiskit.ClassicalRegister(2)
9 | circ = qiskit.QuantumCircuit(qreg, creg)
10 |
11 | # Add a Hadamard gate on qubit 0 to create a superposition
12 | circ.h(qreg[0])
13 |
14 | # Apply the X operator to qubit 0
15 | circ.x(qreg[0])
16 |
17 | # To get the Bell state apply the CNOT operator on qubit 0 and 1
18 | circ.cx(qreg[0], qreg[1])
19 |
20 | # Apply the H operator to take qubit 0 out of superposition
21 | circ.h(qreg[0])
22 |
23 | # Add a Measure gate to obtain the message
24 | circ.measure(qreg, creg)
25 |
26 | # Print out the circuit
27 | print("Circuit:")
28 | print(circ.draw())
29 |
30 | # Run the quantum circuit on a simulator backend
31 | backend = qiskit.Aer.get_backend("statevector_simulator")
32 | job = qiskit.execute(circ, backend)
33 | res = job.result()
34 | print(res.get_counts())
35 |
--------------------------------------------------------------------------------
/chapter07/qiskit/teleportation.py:
--------------------------------------------------------------------------------
1 | """Quantum teleportation in Qiskit."""
2 |
3 | from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
4 | #from qiskit import available_backends, execute
5 |
6 | # Create quantum and classical registers
7 | q = QuantumRegister(3)
8 | c = ClassicalRegister(3)
9 | qc = QuantumCircuit(q, c)
10 |
11 | # Create an initial superposition + state
12 | qc.h(q[0])
13 |
14 | # Take the qubit out of superposition
15 | qc.h(q[0])
16 |
17 | # Perform a CNOT between the qubits
18 | qc.cx(q[0], q[1])
19 |
20 | # Put the qubits into superposition and now the states are the same
21 | qc.h(q[0])
22 | qc.h(q[1])
23 |
24 | # Prepare an initial state for qubit using a single unitary
25 | qc.u1(0.5, q[0])
26 |
27 | # Perform a CNOT between qubit 0 and qubit 1
28 | qc.cx(q[0], q[1])
29 |
30 | # Measure qubit in the + - basis
31 | qc.h(q[0])
32 | qc.measure(q[0], c[0])
33 |
34 | # If needed Perform a phase correction to qubit 1
35 | if c[0] == 1:
36 | qc.z(q[1])
37 |
38 | # Prepare an initial state for qubit 0 using a single unitary
39 | qc.u1(0.5, q[0])
40 |
41 | # Prepare an entangled pair using qubit 1 and qubit 2
42 | qc.h(q[1])
43 | qc.cx(q[1], q[2])
44 |
45 | # Barrier to prevent gate reordering for optimization
46 | qc.barrier(q)
47 |
48 | # Perform a CNOT between qubit 0 and qubit 1
49 | qc.cx(q[0], q[1])
50 |
51 | # Measure qubit 1 in the computational basis
52 | qc.measure(q[1], c[1])
53 | # If needed Perform a bit flip correction to qubit 2
54 | if c[1] == 1:
55 | qc.x(q[2])
56 |
57 | # Measure qubit 0 in the + - basis
58 | qc.h(q[0])
59 | qc.measure(q[0], c[0])
60 | # If needed Perform a phase correction to qubit 2
61 | if c[0] == 1:
62 | qc.z(q[2])
63 |
64 | print(qc.draw())
--------------------------------------------------------------------------------
/chapter08/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter08/.DS_Store
--------------------------------------------------------------------------------
/chapter08/cirq/bernstein-vazirani.py:
--------------------------------------------------------------------------------
1 | """Bernstein-Vazirani algorithm in Cirq."""
2 |
3 | # Imports
4 | import random
5 |
6 | import cirq
7 |
8 |
9 | def main():
10 | """Executes the BV algorithm."""
11 | # Number of qubits
12 | qubit_count = 8
13 |
14 | # Number of times to sample from the circuit
15 | circuit_sample_count = 3
16 |
17 | # Choose qubits to use
18 | input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
19 | output_qubit = cirq.GridQubit(qubit_count, 0)
20 |
21 | # Pick coefficients for the oracle and create a circuit to query it
22 | secret_bias_bit = random.randint(0, 1)
23 | secret_factor_bits = [random.randint(0, 1) for _ in range(qubit_count)]
24 | oracle = make_oracle(input_qubits,
25 | output_qubit,
26 | secret_factor_bits,
27 | secret_bias_bit)
28 | print('Secret function:\nf(x) = x*<{}> + {} (mod 2)'.format(
29 | ', '.join(str(e) for e in secret_factor_bits),
30 | secret_bias_bit))
31 |
32 | # Embed the oracle into a special quantum circuit querying it exactly once
33 | circuit = make_bernstein_vazirani_circuit(
34 | input_qubits, output_qubit, oracle)
35 | print('\nCircuit:')
36 | print(circuit)
37 |
38 | # Sample from the circuit a couple times
39 | simulator = cirq.Simulator()
40 | result = simulator.run(circuit, repetitions=circuit_sample_count)
41 | frequencies = result.histogram(key='result', fold_func=bitstring)
42 | print('\nSampled results:\n{}'.format(frequencies))
43 |
44 | # Check if we actually found the secret value.
45 | most_common_bitstring = frequencies.most_common(1)[0][0]
46 | print('\nMost common matches secret factors:\n{}'.format(
47 | most_common_bitstring == bitstring(secret_factor_bits)))
48 |
49 |
50 | def make_oracle(input_qubits,
51 | output_qubit,
52 | secret_factor_bits,
53 | secret_bias_bit):
54 | """Gates implementing the function f(a) = a*factors + bias (mod 2)."""
55 | if secret_bias_bit:
56 | yield cirq.X(output_qubit)
57 |
58 | for qubit, bit in zip(input_qubits, secret_factor_bits):
59 | if bit:
60 | yield cirq.CNOT(qubit, output_qubit)
61 |
62 |
63 | def make_bernstein_vazirani_circuit(input_qubits, output_qubit, oracle):
64 | """Solves for factors in f(a) = a*factors + bias (mod 2) with one query."""
65 | c = cirq.Circuit()
66 |
67 | # Initialize qubits
68 | c.append([
69 | cirq.X(output_qubit),
70 | cirq.H(output_qubit),
71 | cirq.H.on_each(*input_qubits),
72 | ])
73 |
74 | # Query oracle
75 | c.append(oracle)
76 |
77 | # Measure in X basis
78 | c.append([
79 | cirq.H.on_each(*input_qubits),
80 | cirq.measure(*input_qubits, key='result')
81 | ])
82 |
83 | return c
84 |
85 |
86 | def bitstring(bits):
87 | """Creates a bit string out of an iterable of bits."""
88 | return ''.join(str(int(b)) for b in bits)
89 |
90 | if __name__ == '__main__':
91 | main()
92 |
--------------------------------------------------------------------------------
/chapter08/cirq/deutsch-jozsa.py:
--------------------------------------------------------------------------------
1 | """Deutsch-Jozsa algorithm on three qubits in Cirq."""
2 |
3 | # Import the Cirq library
4 | import cirq
5 |
6 | # Get three qubits -- two data and one target qubit
7 | q0, q1, q2 = cirq.LineQubit.range(3)
8 |
9 | # Oracles for constant functions
10 | constant = ([], [cirq.X(q2)])
11 |
12 | # Oracles for balanced functions
13 | balanced = ([cirq.CNOT(q0, q2)],
14 | [cirq.CNOT(q1, q2)],
15 | [cirq.CNOT(q0, q2), cirq.CNOT(q1, q2)],
16 | [cirq.CNOT(q0, q2), cirq.X(q2)],
17 | [cirq.CNOT(q1, q2), cirq.X(q2)],
18 | [cirq.CNOT(q0, q2), cirq.CNOT(q1, q2), cirq.X(q2)])
19 |
20 | def your_circuit(oracle):
21 | """Yields a circuit for the Deutsch-Jozsa algorithm on three qubits."""
22 | # phase kickback trick
23 | yield cirq.X(q2), cirq.H(q2)
24 |
25 | # equal superposition over input bits
26 | yield cirq.H(q0), cirq.H(q1)
27 |
28 | # query the function
29 | yield oracle
30 |
31 | # interference to get result, put last qubit into |1>
32 | yield cirq.H(q0), cirq.H(q1), cirq.H(q2)
33 |
34 | # a final OR gate to put result in final qubit
35 | yield cirq.X(q0), cirq.X(q1), cirq.CCX(q0, q1, q2)
36 | yield cirq.measure(q2)
37 |
38 | # Get a simulator
39 | simulator = cirq.Simulator()
40 |
41 | # Execute circuit for oracles of constant value functions
42 | print('Your result on constant functions')
43 | for oracle in constant:
44 | result = simulator.run(cirq.Circuit(your_circuit(oracle)), repetitions=10)
45 | print(result)
46 |
47 | # Execute circuit for oracles of balanced functions
48 | print('Your result on balanced functions')
49 | for oracle in balanced:
50 | result = simulator.run(cirq.Circuit(your_circuit(oracle)), repetitions=10)
51 | print(result)
52 |
--------------------------------------------------------------------------------
/chapter08/cirq/deutsch.py:
--------------------------------------------------------------------------------
1 | """Deutsch-Jozsa algorithm."""
2 |
3 | # Import the Cirq Library
4 | import cirq
5 |
6 | # Get two qubits, a data qubit and target qubit, respectively
7 | q0, q1 = cirq.LineQubit.range(2)
8 |
9 | # Dictionary of oracles
10 | oracles = {'0': [], '1': [cirq.X(q1)], 'x': [cirq.CNOT(q0, q1)],
11 | 'notx': [cirq.CNOT(q0, q1), cirq.X(q1)]}
12 |
13 | def deutsch_algorithm(oracle):
14 | """Yields a circuit for Deutsch's algorithm given operations implementing
15 | the oracle."""
16 | yield cirq.X(q1)
17 | yield cirq.H(q0), cirq.H(q1)
18 | yield oracle
19 | yield cirq.H(q0)
20 | yield cirq.measure(q0)
21 |
22 | # Display each circuit for all oracles
23 | for key, oracle in oracles.items():
24 | print('Circuit for {}...'.format(key))
25 | print(cirq.Circuit(deutsch_algorithm(oracle)), end="\n\n")
26 |
27 | # Get a simulator
28 | simulator = cirq.Simulator()
29 |
30 | # Execute the circuit for each oracle to distinguish constant from balanced
31 | for key, oracle in oracles.items():
32 | result = simulator.run(
33 | cirq.Circuit(deutsch_algorithm(oracle)),
34 | repetitions=10
35 | )
36 | print('oracle: {:<4} results: {}'.format(key, result))
37 |
--------------------------------------------------------------------------------
/chapter08/cirq/grover.py:
--------------------------------------------------------------------------------
1 | """Grover's algorithm in Cirq."""
2 |
3 | # Imports
4 | import random
5 |
6 | import cirq
7 |
8 |
9 | def set_io_qubits(qubit_count):
10 | """Add the specified number of input and output qubits."""
11 | input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
12 | output_qubit = cirq.GridQubit(qubit_count, 0)
13 | return (input_qubits, output_qubit)
14 |
15 |
16 | def make_oracle(input_qubits, output_qubit, x_bits):
17 | """Implement function {f(x) = 1 if x==x', f(x) = 0 if x!= x'}."""
18 | # Make oracle.
19 | # for (1, 1) it's just a Toffoli gate
20 | # otherwise negate the zero-bits.
21 | yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)
22 | yield(cirq.TOFFOLI(input_qubits[0], input_qubits[1], output_qubit))
23 | yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)
24 |
25 |
26 | def make_grover_circuit(input_qubits, output_qubit, oracle):
27 | """Find the value recognized by the oracle in sqrt(N) attempts."""
28 | # For 2 input qubits, that means using Grover operator only once.
29 | c = cirq.Circuit()
30 |
31 | # Initialize qubits.
32 | c.append([
33 | cirq.X(output_qubit),
34 | cirq.H(output_qubit),
35 | cirq.H.on_each(*input_qubits),
36 | ])
37 |
38 | # Query oracle.
39 | c.append(oracle)
40 |
41 | # Construct Grover operator.
42 | c.append(cirq.H.on_each(*input_qubits))
43 | c.append(cirq.X.on_each(*input_qubits))
44 | c.append(cirq.H.on(input_qubits[1]))
45 | c.append(cirq.CNOT(input_qubits[0], input_qubits[1]))
46 | c.append(cirq.H.on(input_qubits[1]))
47 | c.append(cirq.X.on_each(*input_qubits))
48 | c.append(cirq.H.on_each(*input_qubits))
49 |
50 | # Measure the result.
51 | c.append(cirq.measure(*input_qubits, key='result'))
52 |
53 | return c
54 |
55 |
56 | def bitstring(bits):
57 | return ''.join(str(int(b)) for b in bits)
58 |
59 |
60 | def main():
61 | qubit_count = 2
62 | circuit_sample_count = 10
63 |
64 | #Set up input and output qubits.
65 | (input_qubits, output_qubit) = set_io_qubits(qubit_count)
66 |
67 | #Choose the x' and make an oracle which can recognize it.
68 | x_bits = [random.randint(0, 1) for _ in range(qubit_count)]
69 | print('Secret bit sequence: {}'.format(x_bits))
70 |
71 | # Make oracle (black box)
72 | oracle = make_oracle(input_qubits, output_qubit, x_bits)
73 |
74 | # Embed the oracle into a quantum circuit implementing Grover's algorithm.
75 | circuit = make_grover_circuit(input_qubits, output_qubit, oracle)
76 | print('Circuit:')
77 | print(circuit)
78 |
79 | # Sample from the circuit a couple times.
80 | simulator = cirq.Simulator()
81 | result = simulator.run(circuit, repetitions=circuit_sample_count)
82 |
83 | frequencies = result.histogram(key='result', fold_func=bitstring)
84 | print('Sampled results:\n{}'.format(frequencies))
85 |
86 | # Check if we actually found the secret value.
87 | most_common_bitstring = frequencies.most_common(1)[0][0]
88 | print('Most common bitstring: {}'.format(most_common_bitstring))
89 | print('Found a match: {}'.format(
90 | most_common_bitstring == bitstring(x_bits)))
91 |
92 |
93 | if __name__ == '__main__':
94 | main()
95 |
--------------------------------------------------------------------------------
/chapter08/cirq/qft.py:
--------------------------------------------------------------------------------
1 | """Creates and simulates a circuit for Quantum Fourier Transform (QFT)
2 | on a 4 qubit system.
3 | """
4 |
5 | # Imports
6 | import numpy as np
7 |
8 | import cirq
9 |
10 |
11 | def main():
12 | """Demonstrates the Quantum Fourier transform."""
13 | # Create circuit and display it
14 | qft_circuit = generate_2x2_grid_qft_circuit()
15 | print('Circuit:')
16 | print(qft_circuit)
17 |
18 | # Simulate and collect the final state
19 | simulator = cirq.Simulator()
20 | result = simulator.simulate(qft_circuit)
21 |
22 | # Display the final state
23 | print('\nFinalState')
24 | print(np.around(result.final_state, 3))
25 |
26 |
27 | def cz_and_swap(q0, q1, rot):
28 | """Yields a controlled-RZ gate and SWAP gate on the input qubits."""
29 | yield cirq.CZ(q0, q1)**rot
30 | yield cirq.SWAP(q0,q1)
31 |
32 |
33 | def generate_2x2_grid_qft_circuit():
34 | """Returns a QFT circuit on a 2 x 2 planar qubit architecture.
35 |
36 | Circuit adopted from https://arxiv.org/pdf/quant-ph/0402196.pdf.
37 | """
38 | # Define a 2*2 square grid of qubits
39 | a, b, c, d = [cirq.GridQubit(0, 0), cirq.GridQubit(0, 1),
40 | cirq.GridQubit(1, 1), cirq.GridQubit(1, 0)]
41 |
42 | # Create the Circuit
43 | circuit = cirq.Circuit(
44 | cirq.H(a),
45 | cz_and_swap(a, b, 0.5),
46 | cz_and_swap(b, c, 0.25),
47 | cz_and_swap(c, d, 0.125),
48 | cirq.H(a),
49 | cz_and_swap(a, b, 0.5),
50 | cz_and_swap(b, c, 0.25),
51 | cirq.H(a),
52 | cz_and_swap(a, b, 0.5),
53 | cirq.H(a),
54 | strategy=cirq.InsertStrategy.EARLIEST
55 | )
56 |
57 | return circuit
58 |
59 |
60 | if __name__ == '__main__':
61 | main()
62 |
--------------------------------------------------------------------------------
/chapter08/problems/chapter08.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter08/problems/chapter08.pdf
--------------------------------------------------------------------------------
/chapter09/cirq/hhl.py:
--------------------------------------------------------------------------------
1 | """
2 | Demonstrates the algorithm for solving linear systems by Harrow, Hassidim,
3 | Lloyd (HHL).
4 |
5 | The HHL algorithm solves a system of linear equations, specifically equations
6 | of the form Ax = b, where A is a Hermitian matrix, b is a known vector, and
7 | x is the unknown vector. To solve on a quantum system, b must be rescaled to
8 | have magnitude 1, and the equation becomes:
9 |
10 | |x> = A**-1 |b> / || A**-1 |b> ||
11 |
12 | The algorithm uses 3 sets of qubits: a single ancilla qubit, a register (to
13 | store eigenvalues of A), and memory qubits (to store |b> and |x>). The
14 | following are performed in order:
15 | 1) Quantum phase estimation to extract eigenvalues of A
16 | 2) Controlled rotations of ancilla qubit
17 | 3) Uncomputation with inverse quantum phase estimation
18 |
19 | For details about the algorithm, please refer to papers in the
20 | REFERENCE section below. The following description uses variables defined
21 | in the HHL paper.
22 |
23 | This example is an implementation of the HHL algorithm for arbitrary 2x2
24 | Hermitian matrices. The output of the algorithm are the expectation values
25 | of Pauli observables of |x>. Note that the accuracy of the result depends
26 | on the following factors:
27 | * Register size
28 | * Choice of parameters C and t
29 |
30 | The result is perfect if
31 | * Each eigenvalue of the matrix is in the form
32 |
33 | 2π/t * k/N,
34 |
35 | where 0≤k>= 1
191 |
192 | # Build controlled ancilla rotation
193 | kGate = cirq.ControlledGate(kGate)
194 |
195 | yield kGate(*qubits)
196 |
197 | def _ancilla_rotation(self, k):
198 | if k == 0:
199 | k = self.N
200 | theta = 2*math.asin(self.C * self.N * self.t / (2*math.pi * k))
201 | return cirq.ry(theta)
202 |
203 |
204 | def hhl_circuit(A, C, t, register_size, *input_prep_gates):
205 | """
206 | Constructs the HHL circuit.
207 |
208 | Args:
209 | A: The input Hermitian matrix.
210 | C: Algorithm parameter, see above.
211 | t: Algorithm parameter, see above.
212 | register_size: The size of the eigenvalue register.
213 | memory_basis: The basis to measure the memory in, one of 'x', 'y', 'z'.
214 | input_prep_gates: A list of gates to be applied to |0> to generate the
215 | desired input state |b>.
216 |
217 | Returns:
218 | The HHL circuit. The ancilla measurement has key 'a' and the memory
219 | measurement is in key 'm'. There are two parameters in the circuit,
220 | `exponent` and `phase_exponent` corresponding to a possible rotation
221 | applied before the measurement on the memory with a
222 | `cirq.PhasedXPowGate`.
223 | """
224 |
225 | ancilla = cirq.LineQubit(0)
226 | # to store eigenvalues of the matrix
227 | register = [cirq.LineQubit(i + 1) for i in range(register_size)]
228 | # to store input and output vectors
229 | memory = cirq.LineQubit(register_size + 1)
230 |
231 | c = cirq.Circuit()
232 | hs = HamiltonianSimulation(A, t)
233 | pe = PhaseEstimation(register_size+1, hs)
234 | c.append([gate(memory) for gate in input_prep_gates])
235 | c.append([
236 | pe(*(register + [memory])),
237 | EigenRotation(register_size + 1, C, t)(*(register + [ancilla])),
238 | pe(*(register + [memory]))**-1,
239 | cirq.measure(ancilla, key='a')
240 | ])
241 |
242 | c.append([
243 | cirq.PhasedXPowGate(
244 | exponent=sympy.Symbol('exponent'),
245 | phase_exponent=sympy.Symbol('phase_exponent'))(memory),
246 | cirq.measure(memory, key='m')
247 | ])
248 |
249 | return c
250 |
251 |
252 | def simulate(circuit):
253 | simulator = cirq.Simulator()
254 |
255 | # Cases for measuring X, Y, and Z (respectively) on the memory qubit.
256 | params = [{
257 | 'exponent': 0.5,
258 | 'phase_exponent': -0.5
259 | }, {
260 | 'exponent': 0.5,
261 | 'phase_exponent': 0
262 | }, {
263 | 'exponent': 0,
264 | 'phase_exponent': 0
265 | }]
266 |
267 | results = simulator.run_sweep(circuit, params, repetitions=5000)
268 |
269 | for label, result in zip(('X', 'Y', 'Z'), list(results)):
270 | # Only select cases where the ancilla is 1.
271 | # TODO optimize using amplitude amplification algorithm
272 | expectation = 1 - 2 * np.mean(
273 | result.measurements['m'][result.measurements['a'] == 1])
274 | print('{} = {}'.format(label, expectation))
275 |
276 |
277 | def main():
278 | """
279 | Simulates HHL with matrix input, and outputs Pauli observables of the
280 | resulting qubit state |x>.
281 | Expected observables are calculated from the expected solution |x>.
282 | """
283 |
284 | # Eigendecomposition:
285 | # >>> import numpy as np
286 | # >>> x, y = np.linalg.eigh(A) # Eigendecomposition for a complex Hermitian matrix.
287 | # >>> [z for z in zip(list(x.astype(np.float32)), list(np.transpose(y)))]
288 | # [(0.34899944, array([-0.23681357+0.j, 0.23727026-0.94213702j])),
289 | # (4.5370007, array([-0.97155511+0.j, -0.05783389+0.229643j]))]
290 | # |b> = (0.64510-0.47848j, 0.35490-0.47848j)
291 | # |x> = (-0.0662724-0.214548j, 0.784392-0.578192j)
292 | A = np.array([[4.30213466-6.01593490e-08j,
293 | 0.23531802+9.34386156e-01j],
294 | [0.23531882-9.34388383e-01j,
295 | 0.58386534+6.01593489e-08j]])
296 | t = 0.358166*math.pi
297 | register_size = 4
298 | input_prep_gates = [cirq.rx(1.276359), cirq.rz(1.276359)]
299 | expected = (0.144130, 0.413217, -0.899154)
300 |
301 | # Set C to be the smallest eigenvalue that can be represented by the
302 | # circuit.
303 | C = 2*math.pi / (2**register_size * t)
304 |
305 | # Simulate circuit
306 | print("Expected observable outputs:")
307 | print("X =", expected[0])
308 | print("Y =", expected[1])
309 | print("Z =", expected[2])
310 | print("Actual: ")
311 | simulate(hhl_circuit(A, C, t, register_size, *input_prep_gates))
312 |
313 |
314 | if __name__ == '__main__':
315 | main()
316 |
--------------------------------------------------------------------------------
/chapter09/cirq/qaoa.py:
--------------------------------------------------------------------------------
1 | """Example using QAOA to solve MaxCut from Chapter 9.3.
2 |
3 | Requirements:
4 | cirq==0.7.0
5 | """
6 |
7 | # Imports
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | import cirq
12 |
13 |
14 | # Function to implement a ZZ gate on qubits a, b with angle gamma
15 | def ZZ(a, b, gamma):
16 | """Returns a circuit implementing exp(-i \pi \gamma Z_i Z_j)."""
17 | # Get a circuit
18 | circuit = cirq.Circuit()
19 |
20 | # Gives the fourth diagonal component
21 | circuit.append(cirq.CZ(a, b) ** gamma)
22 |
23 | # Gives the third diagonal component
24 | circuit.append([cirq.X(b), cirq.CZ(a, b) ** (-1 * gamma), cirq.X(b)])
25 |
26 | # Gives the second diagonal component
27 | circuit.append([cirq.X(a), cirq.CZ(a, b) ** -gamma, cirq.X(a)])
28 |
29 | # Gives the first diagonal component
30 | circuit.append([cirq.X(a), cirq.X(b), cirq.CZ(a, b) ** gamma,
31 | cirq.X(a), cirq.X(b)])
32 |
33 | return circuit
34 |
35 |
36 | # 26.s.one
37 | # Make sure the circuit gives the correct matrix
38 | qreg = cirq.LineQubit.range(2)
39 | zzcirc = ZZ(qreg[0], qreg[1], 0.5)
40 | print("Circuit for ZZ gate:", zzcirc, sep="\n")
41 | print("\nUnitary of circuit:", zzcirc.unitary().round(2), sep="\n")
42 |
43 | ncols = 2
44 | nrows = 2
45 | qreg = [[cirq.GridQubit(i,j) for j in range(ncols)] for i in range(nrows)]
46 |
47 | # Function to implement the cost Hamiltonian
48 | def cost_circuit(gamma):
49 | """Returns a circuit for the cost Hamiltonian."""
50 | circ = cirq.Circuit()
51 | for i in range(nrows):
52 | for j in range(ncols):
53 | if i < nrows - 1:
54 | circ += ZZ(qreg[i][j], qreg[i + 1][j], gamma)
55 | if j < ncols - 1:
56 | circ += ZZ(qreg[i][j], qreg[i][j + 1], gamma)
57 |
58 | return circ
59 |
60 | # Function to implement the mixer Hamiltonian
61 | def mixer(beta):
62 | """Generator for U(H_B, beta) layer (mixing layer)"""
63 | for row in qreg:
64 | for qubit in row:
65 | yield cirq.X(qubit)**beta
66 |
67 |
68 | # Function to build the QAOA circuit
69 | def qaoa(gammas, betas):
70 | """Returns a QAOA circuit."""
71 | circ = cirq.Circuit()
72 | circ.append(cirq.H.on_each(*[q for row in qreg for q in row]))
73 |
74 | for i in range(len(gammas)):
75 | circ += cost_circuit(gammas[i])
76 | circ.append(mixer(betas[i]))
77 |
78 | return circ
79 |
80 | def simulate(circ):
81 | """Returns the wavefunction after applying the circuit."""
82 | sim = cirq.Simulator()
83 | return sim.simulate(circ).final_state_vector
84 |
85 |
86 | def energy_from_wavefunction(wf):
87 | """Computes the energy-per-site of the Ising Model from the wavefunction."""
88 | # Z is a (n_sites x 2**n_sites) array. Each row consists of the
89 | # 2**n_sites non-zero entries in the operator that is the Pauli-Z matrix on
90 | # one of the qubits times the identites on the other qubits. The (i*n_cols + j)th
91 | # row corresponds to qubit (i,j).
92 | nsites = nrows * ncols
93 | Z = np.array([(-1) ** (np.arange(2 ** nsites) >> i)
94 | for i in range(nsites - 1, -1, -1)])
95 |
96 | # Create the operator corresponding to the interaction energy summed over all
97 | # nearest-neighbor pairs of qubits
98 | ZZ_filter = np.zeros_like(wf, dtype=float)
99 | for i in range(nrows):
100 | for j in range(ncols):
101 | if i < nrows - 1:
102 | ZZ_filter += Z[i * ncols + j] * Z[(i + 1) * ncols + j]
103 | if j < ncols - 1:
104 | ZZ_filter += Z[i * ncols + j] * Z[i * ncols + (j + 1)]
105 |
106 | # Expectation value of the energy divided by the number of sites
107 | return -np.sum(np.abs(wf) ** 2 * ZZ_filter) / nsites
108 |
109 | def cost(gammas, betas):
110 | """Returns the cost function of the problem."""
111 | wavefunction = simulate(qaoa(gammas, betas))
112 | return energy_from_wavefunction(wavefunction)
113 |
114 |
115 | def grid_search(gammavals, betavals):
116 | """Does a grid search over all parameter values."""
117 | costmat = np.zeros((len(gammavals), len(betavals)))
118 |
119 | for (i, gamma) in enumerate(gammavals):
120 | for (j, beta) in enumerate(betavals):
121 | costmat[i, j] = cost([gamma], [beta])
122 |
123 | return costmat
124 |
125 | # Get a range of parameters
126 | gammavals = np.linspace(0, 1.0, 50)
127 | betavals = np.linspace(0, np.pi, 75)
128 |
129 | # Compute the cost at all parameter values using a grid search
130 | costmat = grid_search(gammavals, betavals)
131 |
132 | # Plot the cost landscape
133 | plt.imshow(costmat, extent=(0, 1, 0, np.pi), origin="lower", aspect="auto")
134 | plt.colorbar()
135 | plt.show()
136 |
137 | # Coordinates from the grid of cost values
138 | gamma_coord, beta_coord = np.where(costmat == np.min(costmat))
139 |
140 | # Values from the coordinates
141 | gamma_opt = gammavals[gamma_coord[0]]
142 | beta_opt = betavals[beta_coord[0]]
143 |
144 |
145 | def get_bit_strings(gammas, betas, nreps=10000):
146 | """Measures the QAOA circuit in the computational basis to get bitstrings."""
147 | circ = qaoa(gammas, betas)
148 | circ.append(
149 | cirq.measure(*[qubit for row in qreg for qubit in row], key='m'))
150 |
151 | # Simulate the circuit
152 | sim = cirq.Simulator()
153 | res = sim.run(circ, repetitions=nreps)
154 |
155 | return res
156 |
157 | # Sample to get bits and convert to a histogram
158 | bits = get_bit_strings([gamma_opt], [beta_opt])
159 | hist = bits.histogram(key="m")
160 |
161 | # Get the most common bits
162 | top = hist.most_common(2)
163 |
164 | # Print out the two most common bitstrings measured
165 | print("\nMost common bitstring:")
166 | print(format(top[0][0], "#010b"))
167 |
168 | print("\nSecond most common bitstring:")
169 | print(bin(top[1][0]))
170 |
171 |
--------------------------------------------------------------------------------
/chapter09/cirq/qchem.py:
--------------------------------------------------------------------------------
1 | """Example quantum chemistry calculation using OpenFermion and Cirq.
2 |
3 | Requirements:
4 | openfermion==1.0.1
5 | """
6 |
7 | # Imports
8 | import numpy
9 | import scipy
10 | import sympy
11 |
12 | import cirq
13 | import openfermion
14 |
15 | # Set the number of qubits, simulation time, and seed for reproducibility
16 | n_qubits = 3
17 | simulation_time = 1.0
18 | random_seed = 8317
19 |
20 | # Generate the random one-body operator
21 | T = openfermion.random_hermitian_matrix(n_qubits, seed=random_seed)
22 | print("Hamiltonian:", T, sep="\n")
23 |
24 | # Compute the OpenFermion "FermionOperator" form of the Hamiltonian
25 | H = openfermion.FermionOperator()
26 | for p in range(n_qubits):
27 | for q in range(n_qubits):
28 | term = ((p, 1), (q, 0))
29 | H += openfermion.FermionOperator(term, T[p, q])
30 | print("\nFermion operator:")
31 | print(H)
32 |
33 | # Diagonalize T and obtain basis transformation matrix (aka "u")
34 | eigenvalues, eigenvectors = numpy.linalg.eigh(T)
35 | basis_transformation_matrix = eigenvectors.transpose()
36 |
37 | # Initialize the qubit register
38 | qubits = cirq.LineQubit.range(n_qubits)
39 |
40 | # Rotate to the eigenbasis
41 | inverse_basis_rotation = cirq.inverse(
42 | openfermion.bogoliubov_transform(qubits, basis_transformation_matrix)
43 | )
44 | circuit = cirq.Circuit(inverse_basis_rotation)
45 |
46 | # Add diagonal phase rotations to circuit
47 | for k, eigenvalue in enumerate(eigenvalues):
48 | phase = -eigenvalue * simulation_time
49 | circuit.append(cirq.rz(rads=phase).on(qubits[k]))
50 |
51 | # Finally, change back to the computational basis
52 | basis_rotation = openfermion.bogoliubov_transform(
53 | qubits, basis_transformation_matrix
54 | )
55 | circuit.append(basis_rotation)
56 |
57 | # Initialize a random initial state
58 | initial_state = openfermion.haar_random_vector(
59 | 2 ** n_qubits, random_seed).astype(numpy.complex64)
60 |
61 | # Numerically compute the correct circuit output
62 | hamiltonian_sparse = openfermion.get_sparse_operator(H)
63 | exact_state = scipy.sparse.linalg.expm_multiply(
64 | -1j * simulation_time * hamiltonian_sparse, initial_state
65 | )
66 |
67 | # Use Cirq simulator to apply circuit
68 | simulator = cirq.Simulator()
69 | result = simulator.simulate(circuit, qubit_order=qubits,
70 | initial_state=initial_state)
71 | simulated_state = result.final_state_vector
72 |
73 | # Print final fidelity
74 | fidelity = abs(numpy.dot(simulated_state, numpy.conjugate(exact_state)))**2
75 | print("\nfidelity =", round(fidelity, 4))
76 |
--------------------------------------------------------------------------------
/chapter09/cirq/qnn.py:
--------------------------------------------------------------------------------
1 | """Quantum neural network in Cirq."""
2 |
3 | # Imports
4 | import cirq
5 | import matplotlib.pyplot as plt
6 | import numpy as np
7 | import sympy
8 |
9 | # Class for a ZX gate in Cirq
10 | class ZXGate(cirq.ops.eigen_gate.EigenGate,
11 | cirq.ops.gate_features.TwoQubitGate):
12 | """ZXGate with variable weight."""
13 |
14 | def __init__(self, weight=1):
15 | """Initializes the ZX Gate up to phase.
16 |
17 | Args:
18 | weight: rotation angle, period 2
19 | """
20 | self.weight = weight
21 | super().__init__(exponent=weight) # Automatically handles weights other than 1
22 |
23 | def _eigen_components(self):
24 | return [
25 | (1, np.array([[0.5, 0.5, 0, 0],
26 | [ 0.5, 0.5, 0, 0],
27 | [0, 0, 0.5, -0.5],
28 | [0, 0, -0.5, 0.5]])),
29 | (-1, np.array([[0.5, -0.5, 0, 0],
30 | [ -0.5, 0.5, 0, 0],
31 | [0, 0, 0.5, 0.5],
32 | [0, 0, 0.5, 0.5]]))
33 | ]
34 |
35 | # This lets the weight be a Symbol. Useful for parameterization.
36 | def _resolve_parameters_(self, param_resolver):
37 | return ZXGate(weight=param_resolver.value_of(self.weight))
38 |
39 | # How should the gate look in ASCII diagrams?
40 | def _circuit_diagram_info_(self, args):
41 | return cirq.protocols.CircuitDiagramInfo(
42 | wire_symbols=('Z', 'X'),
43 | exponent=self.weight)
44 |
45 | # Total number of data qubits
46 | INPUT_SIZE = 9
47 |
48 | data_qubits = cirq.LineQubit.range(INPUT_SIZE)
49 | readout = cirq.NamedQubit('r')
50 |
51 | # Initialize parameters of the circuit
52 | params = {'w': 0}
53 |
54 | def ZX_layer():
55 | """Adds a ZX gate between each data qubit and the readout.
56 | All gates are given the same sympy.Symbol for a weight."""
57 | for qubit in data_qubits:
58 | yield ZXGate(sympy.Symbol('w')).on(qubit, readout)
59 |
60 |
61 | qnn = cirq.Circuit()
62 | qnn.append(ZX_layer())
63 | qnn.append([cirq.S(readout)**-1, cirq.H(readout)]) # Basis transformation
64 |
65 | def readout_expectation(state):
66 | """Takes in a specification of a state as an array of 0s and 1s
67 | and returns the expectation value of Z on the readout qubit.
68 | Uses the Simulator to calculate the wavefunction exactly."""
69 |
70 | # A convenient representation of the state as an integer
71 | state_num = int(np.sum(state*2**np.arange(len(state))))
72 |
73 | resolver = cirq.ParamResolver(params)
74 | simulator = cirq.Simulator()
75 |
76 | # Specify an explicit qubit order so that we know which qubit is the readout
77 | result = simulator.simulate(qnn, resolver, qubit_order=[readout]+data_qubits,
78 | initial_state=state_num)
79 | wf = result.final_state
80 |
81 | # Becase we specified qubit order, the Z value of the readout is the most
82 | # significant bit.
83 | Z_readout = np.append(np.ones(2**INPUT_SIZE), -np.ones(2**INPUT_SIZE))
84 |
85 | # Use np.real to eliminate +0j term
86 | return np.real(np.sum(wf*wf.conjugate()*Z_readout))
87 |
88 | def loss(states, labels):
89 | loss=0
90 | for state, label in zip(states,labels):
91 | loss += 1 - label*readout_expectation(state)
92 | return loss/(2*len(states))
93 |
94 | def classification_error(states, labels):
95 | error=0
96 | for state,label in zip(states,labels):
97 | error += 1 - label*np.sign(readout_expectation(state))
98 | return error/(2*len(states))
99 |
100 | def make_batch():
101 | """Generates a set of labels, then uses those labels to generate inputs.
102 | label = -1 corresponds to majority 0 in the sate, label = +1 corresponds to
103 | majority 1.
104 | """
105 | np.random.seed(0) # For consistency in demo
106 | labels = (-1)**np.random.choice(2, size=100) # Smaller batch sizes will speed up computation
107 | states = []
108 | for label in labels:
109 | states.append(np.random.choice(2, size=INPUT_SIZE, p=[0.5-label*0.2,0.5+label*0.2]))
110 | return states, labels
111 |
112 | states, labels = make_batch()
113 |
114 | linspace = np.linspace(start=-1, stop=1, num=80)
115 | train_losses = []
116 | error_rates = []
117 | for p in linspace:
118 | params = {'w': p}
119 | train_losses.append(loss(states, labels))
120 | error_rates.append(classification_error(states, labels))
121 | plt.plot(linspace, train_losses)
122 | plt.xlabel('Weight')
123 | plt.ylabel('Loss')
124 | plt.title('Loss as a Function of Weight')
125 | plt.show()
126 |
--------------------------------------------------------------------------------
/chapter09/cirq/qpe.py:
--------------------------------------------------------------------------------
1 | """Quantum phase estimation (QPE) in Cirq."""
2 |
3 | # Imports
4 | import numpy as np
5 | from scipy.stats import unitary_group
6 |
7 | import cirq
8 |
9 | # =============================================================================
10 | # Helper functions
11 | # =============================================================================
12 |
13 | def binary_decimal(string):
14 | """Returns the numeric value of 0babc... where a, b, c, ... are bits.
15 |
16 | Examples:
17 | 0b10 --> 0.5
18 | 0b01 --> 0.25
19 | """
20 | val = 0.0
21 | for (ind, bit) in enumerate(string[2:]):
22 | if int(bit) == 1:
23 | val += 2**(-1 -ind)
24 | return val
25 |
26 | # =============================================================================
27 | # Input to QPE
28 | # =============================================================================
29 |
30 | # Set seed for reproducible results
31 | np.random.seed(123)
32 |
33 | # Get a random unitary matrix on two qubits
34 | m = 2
35 | dim = 2**m
36 | unitary = unitary_group.rvs(dim)
37 |
38 | unitary = np.identity(4)
39 |
40 | xmat = np.array([[0, 1], [1, 0]])
41 | zmat = np.array([[1, 0], [0, -1]])
42 | unitary = np.kron(xmat, zmat)
43 |
44 | # Print it to the console
45 | print("Unitary:")
46 | print(unitary)
47 |
48 | # Diagonalize it classically
49 | evals, evecs = np.linalg.eig(unitary)
50 |
51 | # =============================================================================
52 | # Building the circuit for QPE
53 | # =============================================================================
54 |
55 | # Number of qubits in the readout/answer register (# bits of precision)
56 | n = 8
57 |
58 | # Readout register
59 | regA = cirq.LineQubit.range(n)
60 |
61 | # Register for the eigenstate
62 | regB = cirq.LineQubit.range(n, n + m)
63 |
64 | # Get a circuit
65 | circ = cirq.Circuit()
66 |
67 | # Hadamard all qubits in the readout register
68 | circ.append(cirq.H.on_each(regA))
69 |
70 | # Hadamard all qubits in the second register
71 | #circ.append(cirq.H.on_each(regB))
72 |
73 | # Get a Cirq gate for the unitary matrix
74 | ugate = cirq.ops.matrix_gates.TwoQubitMatrixGate(unitary)
75 |
76 | # Controlled version of the gate
77 | cugate = cirq.ops.ControlledGate(ugate)
78 |
79 | # Do the controlled U^{2^k} operations
80 | for k in range(n):
81 | circ.append(cugate(regA[k], *regB)**(2**k))
82 |
83 | # Do the inverse QFT
84 | for k in range(n - 1):
85 | circ.append(cirq.H.on(regA[k]))
86 | targ = k + 1
87 | for j in range(targ):
88 | exp = -2**(j - targ)
89 | rot = cirq.Rz(exp)
90 | crot = cirq.ControlledGate(rot)
91 | circ.append(crot(regA[j], regA[targ]))
92 | circ.append(cirq.H.on(regA[n - 1]))
93 |
94 | """
95 | # This is the QFT!
96 | for k in reversed(range(n)):
97 | circ.append(cirq.H.on(regA[k]))
98 | for j in reversed(range(k)):
99 | exp = 2**(j - k)
100 | rot = cirq.Rz(exp)
101 | crot = cirq.ControlledGate(rot)
102 | circ.append(crot(regA[j], regA[k]))
103 | """
104 |
105 | # Measure all qubits in the readout register
106 | circ.append(cirq.measure(*regA, key="z"))
107 |
108 | # Print out the circuit
109 | #print("Circuit:")
110 | #print(circ[5:])
111 |
112 | # =============================================================================
113 | # Executing the circuit for QPE
114 | # =============================================================================
115 |
116 | sim = cirq.Simulator()
117 |
118 | res = sim.run(circ, repetitions=1000)
119 |
120 | hist = res.histogram(key="z")
121 |
122 | top = hist.most_common(2)
123 |
124 | estimated = [np.exp(2j * np.pi * binary_decimal(bin(x[0]))) for x in top]
125 |
126 | print("\nEigenvalues from QPE:")
127 | print(sorted(estimated, key=lambda x: abs(x)**2))
128 |
129 | print("\nActual eigenvalues:")
130 | print(sorted(evals, key=lambda x: abs(x)**2))
131 |
--------------------------------------------------------------------------------
/chapter09/cirq/random-bit.py:
--------------------------------------------------------------------------------
1 | """Program for generating random bits in Cirq."""
2 |
3 | # Imports
4 | import cirq
5 |
6 | # Helper function for visualizing output
7 | def bitstring(bits):
8 | return ''.join('1' if e else '0' for e in bits)
9 |
10 | # Get a qubit and quantum circuit
11 | qbit = cirq.LineQubit(0)
12 | circ = cirq.Circuit()
13 |
14 | # Add the Hadamard and measure operations to the circuit
15 | circ.append([cirq.H(qbit), cirq.measure(qbit, key="z")])
16 |
17 | # Simulate the circuit
18 | sim = cirq.Simulator()
19 | res = sim.run(circ, repetitions=10)
20 |
21 | # Print the outcome
22 | print("Bitstring =", bitstring(res.measurements["z"]))
23 |
--------------------------------------------------------------------------------
/chapter09/problems/chapter09.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter09/problems/chapter09.pdf
--------------------------------------------------------------------------------
/chapter09/pyquil/qaoa.py:
--------------------------------------------------------------------------------
1 | """QAOA Example in pyQuil."""
2 |
3 |
4 | ##########################################################
5 | # Copyright 2016-2018 Rigetti Computing
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ##########################################################
19 |
20 | """
21 | Example program run during Rigetti's live programming session at QIP 2018. For a more complete
22 | implementation of QAOA, refer to the grove example and docs:
23 | http://grove-docs.readthedocs.io/en/latest/qaoa.html
24 | """
25 |
26 | from pyquil import get_qc
27 | from pyquil.quil import Program
28 | from pyquil.gates import H
29 | from pyquil.paulis import sI, sX, sZ, exponentiate_commuting_pauli_sum
30 |
31 | # Create a 4-node array graph: 0-1-2-3.
32 | graph = [(0, 1), (1, 2), (2, 3)]
33 | # Nodes [0, 1, 2, 3].
34 | nodes = range(4)
35 |
36 | # Create the initial state program, a sum over all bitstrings, via Hadamards on all qubits.
37 | init_state_prog = Program([H(i) for i in nodes])
38 |
39 | # The cost Hamiltonian is sum of the application of 0.5 * (1 - \sigma_z^i * \sigma_z^j) for all
40 | # qubit pairs (i, j).
41 | h_cost = -0.5 * sum(sI(nodes[0]) - sZ(i) * sZ(j) for i, j in graph)
42 |
43 | # The driver Hamiltonian is the sum of the application of \sigma_x^i for all qubits i.
44 | h_driver = -1. * sum(sX(i) for i in nodes)
45 |
46 |
47 | def qaoa_ansatz(gammas, betas):
48 | """
49 | Function that returns a QAOA ansatz program for a list of angles betas and gammas. len(betas) ==
50 | len(gammas) == P for a QAOA program of order P.
51 | :param list(float) gammas: Angles over which to parameterize the cost Hamiltonian.
52 | :param list(float) betas: Angles over which to parameterize the driver Hamiltonian.
53 | :return: The QAOA ansatz program.
54 | :rtype: Program.
55 | """
56 | return Program([exponentiate_commuting_pauli_sum(h_cost)(g)
57 | + exponentiate_commuting_pauli_sum(h_driver)(b)
58 | for g, b in zip(gammas, betas)])
59 |
60 |
61 | # Create a program, the state initialization plus a QAOA ansatz program, for P = 2.
62 | program = init_state_prog + qaoa_ansatz([0., 0.5], [0.75, 1.])
63 |
64 | # Initialize the QVM and run the program.
65 | qc = get_qc('9q-generic-qvm')
66 |
67 | results = qc.run_and_measure(program, trials=2)
68 |
69 |
--------------------------------------------------------------------------------
/chapter10/cirq/example-supremacy-circuit.txt:
--------------------------------------------------------------------------------
1 | (0, 0): ───H───@───X^0.5─────────────T───────@────────────X^0.5───H───
2 | │ │
3 | (0, 1): ───H───@───X^0.5─────────────@───────┼────X^0.5───T───────H───
4 | │ │
5 | (0, 2): ───H───T─────────────────────@───────┼────@───────@───────H───
6 | │ │ │
7 | (0, 3): ───H───T─────────────────────────────┼────┼───────@───────H───
8 | │ │
9 | (1, 0): ───H───T────────@────────────Y^0.5───@────┼───────@───────H───
10 | │ │ │
11 | (1, 1): ───H───T────────┼─────────────────────────┼───────@───────H───
12 | │ │
13 | (1, 2): ───H───@───@────┼────────────X^0.5────────@───────X^0.5───H───
14 | │ │ │
15 | (1, 3): ───H───@───┼────┼────X^0.5───T────────────────────────────H───
16 | │ │
17 | (2, 0): ───H───@───┼────@────────────Y^0.5───T────────────────────H───
18 | │ │
19 | (2, 1): ───H───@───┼────X^0.5────────@────────────@───────X^0.5───H───
20 | │ │ │
21 | (2, 2): ───H───T───@─────────────────@───────X^0.5┼───────@───────H───
22 | │ │
23 | (2, 3): ───H───T─────────────────────────────@────┼───────@───────H───
24 | │ │
25 | (3, 0): ───H───T─────────────────────────────┼────┼───────@───────H───
26 | │ │ │
27 | (3, 1): ───H───T─────────────────────────────┼────@───────@───────H───
28 | │
29 | (3, 2): ───H───@───Y^0.5─────────────T───────┼────────────────────H───
30 | │ │
31 | (3, 3): ───H───@───X^0.5─────────────T───────@────────────X^0.5───H───
32 |
--------------------------------------------------------------------------------
/chapter10/cirq/supremacy-cirquit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/chapter10/cirq/supremacy-cirquit.png
--------------------------------------------------------------------------------
/img/qc2e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/img/qc2e.png
--------------------------------------------------------------------------------
/korean/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # 양자 컴퓨팅: 응용적 접근 - 한글번역 사이트
4 |
5 | *Springer출판사의 Quantum Computing: An Applied Approach* 책의 한글번역 사이트에 오신 것을 환영합니다.
6 |
7 | [여기 아마존에서 양장본과 킨들버전을 찾으실 수 있습니다.](https://www.amazon.com/Quantum-Computing-Approach-Jack-Hidary-ebook/dp/B07X7NDFLZ/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=)
8 |
9 | 이 깃허브 사이트에서는 다음의 자료들을 제공하고 있습니다:
10 | - 연습문제
11 | - 책에 수록된 알고리즘들을 위한 코드
12 | - 하단의 더 읽을거리
13 | - 책에 대한 새로운 수정사항
14 |
15 | # 연습문제 (번역 중)
16 |
17 | * [제1 장 (번역완료)](./chapter01/problems/chapter01.pdf)
18 |
19 | * [제2 장 (번역완료)](./chapter02/problems/chapter02.pdf)
20 |
21 | * [제3 장 (번역완료)](./chapter03/problems/chapter03.pdf)
22 |
23 | * [제4 장](./chapter04/problems/chapter04.pdf)
24 |
25 | * [제5 장](./chapter05/problems/chapter05.pdf)
26 |
27 | * [제8 장](./chapter08/problems/chapter08.pdf)
28 |
29 | * [제9 장](./chapter09/problems/chapter09.pdf)
30 |
31 | 다른 장들의 추가 연습문제들은 곧 업로드 될 것입니다.
32 |
33 | 연습문제들은 다음 분들께서 제공해주셨습니다:
34 |
35 | Jack Hidary님, Ryan Larose님, Stefan Leichenauer님, James Myers님.
36 |
37 | 만일 연습문제 출제에 추가로 기여하고 싶으시다면 연락주시기 바랍니다! 이는 우리 커뮤니티의 모두를 위한 일입니다. jack@hidary.com
38 |
39 | 또한 본 도서를 강의교재로 사용하고 싶으신 교수님들께서는 jack@hidary.com로 연락주시면 연습문제 해답을 공유해드리겠습니다.
40 |
41 | # 더 읽을거리
42 |
43 | *[2019년 5월 10-11일 구글 써큐(cirq) 부트캠프 녹화본](https://drive.google.com/corp/drive/folders/18cCJ_AJ-YeCmK0XwD3QbC1ppdUe99ykc)*
44 |
45 | *구글 Colab 노트북*
46 |
47 | * [써큐에서 양자 알고리즘 작성하기 입문](https://colab.research.google.com/drive/1mrDPc0HSBxgD_-wwif_gUGriM3VTNYoy#forceEdit=true&offline=true&sandboxMode=true)
48 | * [전자들로 구성된 물리계의 양자 시뮬레이션](https://colab.research.google.com/drive/1-oQy0FTtio0P7wUCc3ge7PXlk7aWSAdM)
49 | * [써큐 교재 알고리즘들](https://colab.research.google.com/drive/1X0H39CWQzx2uO9UGiokdseWsxt6ckxOw)
50 | * [양자 근사 최적화 알고리즘(QAOA)](https://colab.research.google.com/drive/1caKw0lZ3ovdxKVQ4QxkSKgTRlQ7DxLJZ)
51 | * [중성원자 장치 써큐 클래스](https://colab.research.google.com/drive/1pO5JrX_ieW8KAxHIqWG_viZSE_F7LDCz)
52 | * [이온장치 써큐 클래스](https://colab.research.google.com/drive/1p_SLX83UzudhHLeZ6UXx_GAp67ElxMXW)
53 |
54 | *발표자료들*
55 |
56 | * [양자 컴퓨팅 복습](https://drive.google.com/file/d/1JPk_Isr3BzM7t1EZGW0jon2k-78Hn_W5/view?usp=sharing)
57 | * [양자 하드웨어 입문](https://drive.google.com/file/d/1WSwXU_PVArN32tufvBIz2wp7kK2NPMbj/view?usp=sharing)
58 | * [써큐 이온 포획 데모](https://drive.google.com/file/d/1Bl2VxY9_W1SQ2yp3HasKGz3ielDTSvFO/view?usp=sharing)
59 | * [써큐 워크숍](https://drive.google.com/file/d/10CD0j-RFUV5S7sO6x2fOKauYvBqurzt7/view?usp=sharing)
60 |
61 | *동물원*
62 | * [양자 프로토콜 동물원](https://wiki.veriqloud.fr)
63 | * [양자 알고리즘 동물원](http://quantumalgorithmzoo.org/)
64 | * [복잡도 동물원](https://complexityzoo.uwaterloo.ca/Complexity_Zoo)
65 |
66 | ## 서평
67 |
68 | "양자 컴퓨터 프로그래밍은 최근까지 완전히 이론적인 사업이었습니다.
69 | 현재, 양자 컴퓨팅 하드웨어의 빠른 발전으로 인해 학계와 산업계 모두에서
70 | 이러한 컴퓨터 위에서 어떻게 프로그래밍할지 새로운 관심들이 물결치고 있습니다.
71 | '양자 컴퓨팅: 응용적 접근'은 이 새로운 물결을 위한 책입니다.
72 | 이 교재는 양자 컴퓨팅의 기본을 강조하면서 구글, IBM, 마이크로소프트, 리게티 등 다양한 플랫폼을
73 | 위한 API들을 다루고 있습니다. 저자이신 Jack Hidary님은 다양한 예제를 통해 기초적인 프로그램에서
74 | 부터 쇼어의 소인수 알고리즘에 이르기까지 독자들을 안내합니다.
75 | 이 책은 또한 근미래에 유용하다고 증명되거나 이 분야의 활발한 연구주제인 응용들을 다루고 있습니다.
76 | 강의자료로써 이 책은 Nielsen & Chuang 같이 이 분야의 어려운 이론적 토대들을 가르치는
77 | 오래된 고전들의 훌륭하고 실용적인 보완 교재로 쓰일 수 있습니다.
78 | Hidary님의 교재는 연구원들과 엔지니어들이 새로 생겨난 이 분야에서 빠르게 습득할 수 있도록
79 | 할 것입니다."
80 |
81 | -- Patrick Hayden님, 스탠포드대학교 물리학 교수
82 |
83 |
84 | “이 책은 제가 본 양자 컴퓨팅 교재 중 최고입니다. 기본과 역사, 하드웨어에 대한
85 | 직관적인 설명 뿐만 아니라 많은 중요 알고리즘들을 실행해 볼 수 있는 코드들도 살펴봅니다.
86 | 추가로 이 책은 독자들에게 필요한 모든 수학들을 빠르게 전달해줍니다.
87 | 저 또한 제 양자 프로그래밍 수업에 이 책을 사용할 예정입니다.”
88 |
89 | -- Jens Palsberg님, UCLA대학교 컴퓨터 과학 교수
90 |
91 |
92 | "Hidary님의 '양자 컴퓨팅: 응용적 접근' 책은 전통적인 양자 컴퓨팅 교재에서 부터
93 | 현재 우리가 진입하고 있는 NISQ(오류있는 중규모 양자)시대까지 이어주는 훌륭한
94 | 교량역할을 해줍니다. 이 책은 현대적인 접근법을 취해 양자 컴퓨팅을 위해 개발된
95 | 다양한 라이브러리들을 살펴보며 실제 양자 컴퓨터에서 동작하는
96 | 정수 알고리즘들의 코드들을 살펴봅니다.
97 | 계속해서 VQE와 QAOA 같은 현존하는 최첨단(state-of-the-art)의 변분 최적화 알고리즘들
98 | 개략적으로 살펴보며 나아가 양자 우위를 처음 실현한 중심이 된 응용 분야인
99 | 무작위 회로 샘플링도 코드와 함께 살펴봅니다.
100 | 이 책의 웹사이트는 추가 수정사항과 진행중인 새로운 개발 자료들을 제공합니다.
101 | 지난 5년간의 실질적인 진보를 토대로, 이 책과 관련 자료들은
102 | 양자 컴퓨터가 이론적으로 어떻게 쓰일지에 대한 것에서
103 | 양자 컴퓨터가 앞으로 몇십년동안 실용적으로 어떻게 쓰일지로 옮겨가도록 촉진할 것입니다."
104 |
105 | -- Paul Ginsparg님, 코넬대학교 물리학 교수
106 |
107 | "이 책은 양자 컴퓨팅이라는 문헌들에 있는 간극을 채워 줍니다.
108 | 양자 컴퓨터 프로그래밍으로 손을 지저분하게 할 준비가 된 학계와 산업계의 연구원 및 엔지니어들에게
109 | 딱 맞게 도착하면서, 학습을 위한 도구로 혹은 다양한 실용 코드 예제들의 참조서로 환영받고 있습니다."
110 |
111 | -- Dennis Willsch님, 율리히(Jülich) 슈퍼컴퓨팅 연구소
112 |
113 |
114 |
115 | # 연락처
116 |
117 | 제안사항이나 의견 있으시면 jack@hidary.com 또는 jtricot1@gmail.com로 연락주시기 바랍니다.
118 |
119 | 잭(Jack)
120 |
121 | # 역자주
122 |
123 | 번역에 대한 문의나 의견 있으시면 Issue에 글을 남겨주시거나 Pull Request를 열고 저희를 검토자로 넣어주시기 바랍니다.
124 |
125 | 재(Jae) & 준호(Joonho)
126 |
127 | - [Jae Hyeon Yoo](https://research.google/people/106817/), 머신러닝 소프트웨어 엔지니어, 구글 리서치 코리아
128 | - [Joonho Kim](https://www.ias.edu/scholars/joonho-kim), 내츄럴 사이언스 멤버, 프린스턴 고등과학원
129 |
130 |
131 |
--------------------------------------------------------------------------------
/korean/chapter01/problems/chapter01.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter01/problems/chapter01.pdf
--------------------------------------------------------------------------------
/korean/chapter02/problems/chapter02.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter02/problems/chapter02.pdf
--------------------------------------------------------------------------------
/korean/chapter03/problems/chapter03.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter03/problems/chapter03.pdf
--------------------------------------------------------------------------------
/korean/chapter04/problems/chapter04.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter04/problems/chapter04.pdf
--------------------------------------------------------------------------------
/korean/chapter05/problems/chapter05.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter05/problems/chapter05.pdf
--------------------------------------------------------------------------------
/korean/chapter06/cirq/cirq-basic.py:
--------------------------------------------------------------------------------
1 | """써큐 라이브러리 간단한 예제 프로그램."""
2 |
3 | # 써큐 패키지 가져오세요.
4 | import cirq
5 |
6 | # 큐비트 하나를 고르세요.
7 | qubit = cirq.GridQubit(0, 0)
8 |
9 | # 회로를 만드세요.
10 | circuit = cirq.Circuit([
11 | cirq.X(qubit), # 양자 논리에서의 NOT.
12 | cirq.measure(qubit, key='m') # 큐비트 측정.
13 | ]
14 | )
15 |
16 | # 회로를 화면에 텍스트로 출력합니다.
17 | print("Circuit:")
18 | print(circuit)
19 |
20 | # 회로를 실행하기 위한 시뮬레이터를 가져옵니다.
21 | simulator = cirq.Simulator()
22 |
23 | # 회로를 여러번 시뮬레이션 하세요.
24 | result = simulator.run(circuit, repetitions=10)
25 |
26 | # 결과를 출력합니다.
27 | print("Results:")
28 | print(result)
29 |
--------------------------------------------------------------------------------
/korean/chapter06/cirq/cirq-bell-state.py:
--------------------------------------------------------------------------------
1 | """써큐에서 벨 상태 |\Phi^{+}>를 준비하기 위한 파이썬 스크립트."""
2 |
3 | # 써큐 라이브러리를 가져오세요.
4 | import cirq
5 |
6 | # 큐비트들과 회로를 준비합니다.
7 | # (역자주: qreg는 quantum register에서 가져온 변수명입니다.)
8 | qreg = [cirq.LineQubit(x) for x in range(2)]
9 | circ = cirq.Circuit()
10 |
11 | # 벨 상태를 준비하는 회로를 추가합니다.
12 | circ.append([cirq.H(qreg[0]),
13 | cirq.CNOT(qreg[0], qreg[1])])
14 |
15 | # 회로를 화면에 표시합니다.
16 | print("Circuit")
17 | print(circ)
18 |
19 | # 측정을 모든 큐비트에 추가합니다.
20 | circ.append(cirq.measure(*qreg, key="z"))
21 |
22 | # 회로를 시뮬레이션합니다.
23 | sim = cirq.Simulator()
24 | res = sim.run(circ, repetitions=100)
25 |
26 | # 측정결과를 출력합니다.
27 | print("\nMeasurements:")
28 | print(res.histogram(key="z"))
--------------------------------------------------------------------------------
/korean/chapter06/cirq/cirq-parameters.py:
--------------------------------------------------------------------------------
1 | """써큐에서 매개변수화된 양자 게이트 다루기."""
2 |
3 | # 라이브러리들을 가져옵니다.
4 | # (역자주: matplotlib는 매트랩같은 그래프 도식기능이 탁월한 파이썬 라이브러리이며
5 | # sympy는 심볼릭 파이썬으로 메이플같은 심볼릭 연산을 수행해주는 라이브러리 입니다.)
6 | import matplotlib.pyplot as plt
7 | import sympy
8 |
9 | import cirq
10 |
11 | # 양자 회로와 큐비트를 가져옵니다.
12 | qbit = cirq.LineQubit(0)
13 | circ = cirq.Circuit()
14 |
15 | # 매개변수 이름 `t`인 심볼을 생성합니다.
16 | symbol = sympy.Symbol("t")
17 |
18 | # 매개변수화된 양자 게이트를 추가합니다.
19 | circ.append(cirq.XPowGate(exponent=symbol)(qbit))
20 |
21 | # 측정하기.
22 | circ.append(cirq.measure(qbit, key="z"))
23 |
24 | # 회로를 화면에 출력합니다.
25 | print("Circuit:")
26 | print(circ)
27 |
28 | # 매개변수 값을 훑어보기 위해 범위를 정의합니다.
29 | sweep = cirq.Linspace(key=symbol.name, start=0.0, stop=2.0, length=100)
30 |
31 | # 정의된 매개변수 범위에서 훑어보면서 회로를 실행해봅니다.
32 | sim = cirq.Simulator()
33 | res = sim.run_sweep(circ, sweep, repetitions=1000)
34 |
35 | # 훑어본 범위에서 각 측정 결과값들을 그래프로 도식합니다.
36 | angles = [x[0][1] for x in sweep.param_tuples()]
37 | zeroes = [res[i].histogram(key="z")[0] / 1000 for i in range(len(res))]
38 | plt.plot(angles, zeroes, "--", linewidth=3)
39 |
40 | # 그래프를 꾸며봅니다.
41 | plt.ylabel("Frequency of 0 Measurements")
42 | plt.xlabel("Exponent of X gate")
43 | plt.grid()
44 |
45 | plt.savefig("param-sweep-cirq.pdf", format="pdf")
46 |
--------------------------------------------------------------------------------
/korean/chapter06/cirq/param-sweep-cirq.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter06/cirq/param-sweep-cirq.pdf
--------------------------------------------------------------------------------
/korean/chapter06/forest/pyquil-basic.py:
--------------------------------------------------------------------------------
1 | """파이퀼에서 간단한 예제 프로그램."""
2 |
3 | # 파이퀼 라이브러리를 가져옵니다.
4 | import pyquil
5 |
6 | # 양자 프로그램을 생성합니다.
7 | prog = pyquil.Program()
8 |
9 | # 고전 레지스터를 정의합니다.
10 | creg = prog.declare("ro", memory_type="BIT", memory_size=1)
11 |
12 | # ANOT연산과 0번째 큐비트에 추가하고 그 측정결과를 고전 레지스터에 0번째에 저장합니다.
13 | prog += [
14 | pyquil.gates.X(0),
15 | pyquil.gates.MEASURE(0, creg[0])
16 | ]
17 |
18 | # 프로그램을 출력합니다.
19 | print("Program:")
20 | print(prog)
21 |
22 | # 회로를 실행할 양자 컴퓨터를 가져옵니다.
23 | computer = pyquil.get_qc("1q-qvm")
24 |
25 | # 프로그램을 여러번 실행하도록 설정합니다.
26 | prog.wrap_in_numshots_loop(10)
27 |
28 | # 프로그램을 양자 컴퓨터 위에서 실행합니다.
29 | result = computer.run(prog)
30 |
31 | # 결과를 출력합니다.
32 | print("Result:")
33 | print(result)
34 |
--------------------------------------------------------------------------------
/korean/chapter06/qdk/Driver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Microsoft.Quantum.Simulation.Core;
4 | using Microsoft.Quantum.Simulation.Simulators;
5 |
6 | namespace Quantum.Simple {
7 | class Driver {
8 | static void Main(string[] args) {
9 | // 양자 컴퓨터 시뮬레이터를 가져옵니다.
10 | using (var qsim = new QuantumSimulator()) {
11 | // NotAndMeasure 연산을 수행하고 그 결과를 가져옵니다.
12 | var num_ones = NotAndMeasure.Run(qsim, 10).Result;
13 |
14 | // 측정 결과를 콘솔에 출력합니다.
15 | System.Console.WriteLine(
16 | $"Number of ones measured: {num_ones, 0}.");
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/korean/chapter06/qdk/Operations.qs:
--------------------------------------------------------------------------------
1 | namespace Quantum.Simple
2 | {
3 | // 라이브러리들을 가져옵니다.
4 | open Microsoft.Quantum.Primitive;
5 | open Microsoft.Quantum.Canon;
6 |
7 | // 큐비트 하나를 원하는 상태(desired_state)에 있도록 설정합니다.
8 | operation Set(desired_state: Result, qubit: Qubit) : Unit {
9 | let current = M(qubit);
10 | if (current != desired_state) {
11 | X(qubit);
12 | }
13 | }
14 |
15 | // 입력받은 숫자만큼 반복하며 "not and measure" 회로를 실행합니다.
16 | // 그리고 측정된 1의 개수를 반환합니다.
17 | operation NotAndMeasure(repetitions: Int) : Int {
18 | // 측정된 1의 개수를 저장할 변수.
19 | mutable num_ones = 0;
20 |
21 | // 사용할 큐비트 하나를 가져옵니다.
22 | using (qubit = Qubit()) {
23 | // 입력받은 수 repetitions 만큼 반복문을 수행합니다.
24 | for (test in 1..repetitions) {
25 | // 큐비트 하나를 |0> 상태로 설정한 후 가져옵니다.
26 | Set(Zero, qubit);
27 |
28 | // NOT 연산을 수행합니다.
29 | X(qubit);
30 |
31 | // 큐비트를 측정합니다.
32 | let res = M (qubit);
33 |
34 | // 우리가 측정한 1의 개수를 세어봅니다.
35 | if (res == One) {
36 | set num_ones = num_ones + 1;
37 | }
38 | }
39 | // System.AggregateException 예외를 피하기 위해 큐비트는 항상 할당 해제할 때
40 | // |0> 큐비트에 둡니다.
41 | Set(Zero, qubit);
42 | }
43 | // 측정된 1의 개수를 출력합니다.
44 | return num_ones;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/korean/chapter06/qdk/README:
--------------------------------------------------------------------------------
1 | QDK에서 예제 프로그램을 실행하기 위해서는:
2 |
3 | (1) 명령행에서 `dotnet run`을 입력하십시오.
4 |
5 | (2) 파일을 visual studio나 visual studio code에서 실행하십시오.
6 |
7 | 출력은 다음과 같아야합니다.
8 |
9 | Number of ones measured: 10.
10 |
11 | 실행했을 때 `bin`과 `obj` 두 디렉토리가 생성됩니다.
12 |
13 |
--------------------------------------------------------------------------------
/korean/chapter06/qdk/Simple.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.0
6 | x64
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/korean/chapter06/qiskit/qiskit-basic-circuit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter06/qiskit/qiskit-basic-circuit.png
--------------------------------------------------------------------------------
/korean/chapter06/qiskit/qiskit-basic.py:
--------------------------------------------------------------------------------
1 | """키스킷 간단한 예제 프로그램."""
2 |
3 | # 키스킷 패키지를 가져오세요.
4 | import qiskit
5 |
6 | # 1개 큐비트를 갖는 양자 레지스터를 생성하세요.
7 | qreg = qiskit.QuantumRegister(1, name='qreg')
8 |
9 | # 1개 큐비트와 연결된 고전 레지스터를 생성하세요.
10 | creg = qiskit.ClassicalRegister(1, name='creg')
11 |
12 | # 위의 두 레지스터들로 구성된 양자 회로를 생성하세요.
13 | circ = qiskit.QuantumCircuit(qreg, creg)
14 |
15 | # NOT연산을 추가하세요.
16 | circ.x(qreg[0])
17 |
18 | # 측정하기를 추가하세요.
19 | circ.measure(qreg, creg)
20 |
21 | # 회로를 출력합니다.
22 | print(circ.draw())
23 |
24 | # 양자 회로를 실행할 시뮬레이터 백엔드를 가져옵니다.
25 | backend = qiskit.BasicAer.get_backend("qasm_simulator")
26 |
27 | # 회로를 가져온 백엔드 위에서 실행하고 측정결과를 얻습니다.
28 | job = qiskit.execute(circ, backend, shots=10)
29 | result = job.result()
30 |
31 | # 측정결과를 출력합니다.
32 | print(result.get_counts())
33 |
--------------------------------------------------------------------------------
/korean/chapter07/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter07/.DS_Store
--------------------------------------------------------------------------------
/korean/chapter07/cirq/bell-inequality-test.py:
--------------------------------------------------------------------------------
1 | """벨 부등식 검사를 수행하는 양자 회로를 생성하고 시뮬레이션하기."""
2 |
3 | # 라이브러리 가져오기.
4 | import numpy as np
5 |
6 | import cirq
7 |
8 |
9 | def main():
10 | # 회로 생성.
11 | circuit = make_bell_test_circuit()
12 | print('Circuit:')
13 | print(circuit)
14 |
15 | # 시뮬레이션하기.
16 | print()
17 | repetitions = 1000
18 | print('Simulating {} repetitions...'.format(repetitions))
19 | result = cirq.Simulator().run(program=circuit,
20 | repetitions=repetitions)
21 |
22 | # 결과들 모으기.
23 | a = np.array(result.measurements['a'][:, 0])
24 | b = np.array(result.measurements['b'][:, 0])
25 | x = np.array(result.measurements['x'][:, 0])
26 | y = np.array(result.measurements['y'][:, 0])
27 |
28 | # 승률 계산하기.
29 | outcomes = a ^ b == x & y
30 | win_percent = len([e for e in outcomes if e]) * 100 / repetitions
31 |
32 | # 데이터 출력하기.
33 | print()
34 | print('Results')
35 | print('a:', bitstring(a))
36 | print('b:', bitstring(b))
37 | print('x:', bitstring(x))
38 | print('y:', bitstring(y))
39 | print('(a XOR b) == (x AND y):\n ', bitstring(outcomes))
40 | print('Win rate: {}%'.format(win_percent))
41 |
42 |
43 | def make_bell_test_circuit():
44 | # 엘리스(Alice), 밥(Bob)과 심판 큐비트들 선언.
45 | alice = cirq.GridQubit(0, 0)
46 | bob = cirq.GridQubit(1, 0)
47 | alice_referee = cirq.GridQubit(0, 1)
48 | bob_referee = cirq.GridQubit(1, 1)
49 |
50 | circuit = cirq.Circuit()
51 |
52 | # 엘리스와 밥 사이에 얽힌 양자 상태를 준비하기.
53 | circuit.append([
54 | cirq.H(alice),
55 | cirq.CNOT(alice, bob),
56 | cirq.X(alice)**-0.25,
57 | ])
58 |
59 | # 심판 큐비트들은 동전 던지기를 합니다.
60 | circuit.append([
61 | cirq.H(alice_referee),
62 | cirq.H(bob_referee),
63 | ])
64 |
65 | # 선수들은 심판의 동전 상태에 따라 sqrt(X) 연산을 수행합니다.
66 | circuit.append([
67 | cirq.CNOT(alice_referee, alice)**0.5,
68 | cirq.CNOT(bob_referee, bob)**0.5,
69 | ])
70 |
71 | # 결과들을 기록합니다.
72 | circuit.append([
73 | cirq.measure(alice, key='a'),
74 | cirq.measure(bob, key='b'),
75 | cirq.measure(alice_referee, key='x'),
76 | cirq.measure(bob_referee, key='y'),
77 | ])
78 |
79 | return circuit
80 |
81 |
82 | def bitstring(bits):
83 | return ''.join('1' if e else '_' for e in bits)
84 |
85 |
86 | if __name__ == '__main__':
87 | main()
88 |
--------------------------------------------------------------------------------
/korean/chapter07/cirq/superdense-coding-cirq.py:
--------------------------------------------------------------------------------
1 | """써큐 초고밀집 부호(superdense coding) 예제 프로그램."""
2 |
3 | # 라이브러리 가져오기
4 | import cirq
5 |
6 | # 출력결과를 보여주기 위한 보조 함수.
7 | def bitstring(bits):
8 | return ''.join('1' if e else '0' for e in bits)
9 |
10 | # 큐비트 두 개와 양자 회로를 생성합니다.
11 | qreg = [cirq.LineQubit(x) for x in range(2)]
12 | circ = cirq.Circuit()
13 |
14 | # 각 메시지별 연산들의 사전을 정의합니다.
15 | message = {"00": [],
16 | "01": [cirq.X(qreg[0])],
17 | "10": [cirq.Z(qreg[0])],
18 | "11": [cirq.X(qreg[0]), cirq.Z(qreg[0])]}
19 |
20 | # 엘리스(Alice)가 벨 상태를 생성합니다.
21 | circ.append(cirq.H(qreg[0]))
22 | circ.append(cirq.CNOT(qreg[0], qreg[1]))
23 |
24 | # 엘리스가 보낼 메시지를 선택합니다.
25 | m = "01"
26 | print("Alice's sent message =", m)
27 |
28 | # 엘리스가 보낼 메시지를 적절한 양자 연산자들로 부호화합니다.
29 | circ.append(message[m])
30 |
31 | # 밥(Bob)이 벨 기저에서 측정합니다.
32 | circ.append(cirq.CNOT(qreg[0], qreg[1]))
33 | circ.append(cirq.H(qreg[0]))
34 | circ.append([cirq.measure(qreg[0]), cirq.measure(qreg[1])])
35 |
36 | # 전체 회로를 출력합니다.
37 | print("\nCircuit:")
38 | print(circ)
39 |
40 | # 시뮬레이터 백엔드에서 양자회로를 실행합니다.
41 | sim = cirq.Simulator()
42 | res = sim.run(circ, repetitions=1)
43 |
44 | # 회로의 측정 결과인 밥이 받은 메시지를 출력합니다.
45 | print("\nBob's received message =", bitstring(res.measurements.values()))
46 |
--------------------------------------------------------------------------------
/korean/chapter07/cirq/teleportation-cirq.py:
--------------------------------------------------------------------------------
1 | """써큐에서 양자 원격이동하기. 다음 예제에서 수정되었습니다.:
2 |
3 | https://github.com/quantumlib/Cirq/blob/master/examples/quantum_teleportation.py
4 | """
5 |
6 | # 가져오기.
7 | import random
8 |
9 | import cirq
10 |
11 |
12 | def make_quantum_teleportation_circuit(ranX, ranY):
13 | """양자 원격이동 회로를 반환합니다."""
14 | circuit = cirq.Circuit()
15 | msg, alice, bob = cirq.LineQubit.range(3)
16 |
17 | # 엘리스(Alice)와 밥(Bob)이 공유할 벨상태를 생성합니다.
18 | circuit.append([cirq.H(alice), cirq.CNOT(alice, bob)])
19 |
20 | # 보낼 메시지를 위한 무작위 상태를 생성합니다.
21 | circuit.append([cirq.X(msg)**ranX, cirq.Y(msg)**ranY])
22 |
23 | # 엘리스의 얽힌 큐비트와 메시지 상태를 벨 측정합니다.
24 | circuit.append([cirq.CNOT(msg, alice), cirq.H(msg)])
25 | circuit.append(cirq.measure(msg, alice))
26 |
27 | # 밥이 가진 얽힌 큐비트와 벨 측정으로부터 얻은 2개의 고전 비트들을 통해
28 | # 원래의 양자 메시지 원본을 복구합니다.
29 | circuit.append([cirq.CNOT(alice, bob), cirq.CZ(msg, bob)])
30 |
31 | return msg, circuit
32 |
33 |
34 | def main():
35 | # 원격이동할 무작위 상태를 부호화합니다.
36 | ranX = random.random()
37 | ranY = random.random()
38 | msg, circuit = make_quantum_teleportation_circuit(ranX, ranY)
39 |
40 | # 회로를 시뮬레이션합니다.
41 | sim = cirq.Simulator()
42 | message = sim.simulate(cirq.Circuit(
43 | [cirq.X(msg)**ranX, cirq.Y(msg)**ranY]))
44 |
45 | # 엘리스의 큐비트를 블로흐 구 위에 출력합니다.
46 | print("Bloch Sphere of Alice's qubit:")
47 | b0X, b0Y, b0Z = cirq.bloch_vector_from_state_vector(
48 | message.final_state, 0)
49 | print("x: ", round(b0X, 4),
50 | "y: ", round(b0Y, 4),
51 | "z: ", round(b0Z, 4))
52 |
53 | # 원격이동 회로를 출력합니다.
54 | print("\nCircuit:")
55 | print(circuit)
56 |
57 | # 시뮬레이션의 마지막 상태를 저장합니다.
58 | final_results = sim.simulate(circuit)
59 |
60 | # 밥의 큐비트를 블로흐 구 위에 출력합니다.
61 | print("\nBloch Sphere of Bob's qubit:")
62 | b2X, b2Y, b2Z = cirq.bloch_vector_from_state_vector(
63 | final_results.final_state, 2)
64 | print("x: ", round(b2X, 4),
65 | "y: ", round(b2Y, 4),
66 | "z: ", round(b2Z, 4))
67 |
68 |
69 | if __name__ == '__main__':
70 | main()
71 |
--------------------------------------------------------------------------------
/korean/chapter07/qiskit/supderdense-coding.py:
--------------------------------------------------------------------------------
1 | """키스킷 초고밀집 부호."""
2 |
3 | # 가져오기.
4 | import qiskit
5 |
6 | # 2개 큐비트의 양자 레지스터와 2개 비트의 고전레지스터로 회로 구성하기.
7 | qreg = qiskit.QuantumRegister(2)
8 | creg = qiskit.ClassicalRegister(2)
9 | circ = qiskit.QuantumCircuit(qreg, creg)
10 |
11 | # 아다마르(Hadamard) 게이트를 0번째 큐비트에 적용하여 중첩상태를 구현합니다.
12 | circ.h(qreg[0])
13 |
14 | # X 연산자를 0번째 큐비트에 적용합니다.
15 | circ.x(qreg[0])
16 |
17 | # 벨상태를 얻기 위해 0번째와 1번째 큐비트로 CNOT연산을 가합니다.
18 | # (역자주: 첫 번째 인자가 제어비트, 두 번째 인자가 피연산비트입니다.)
19 | circ.cx(qreg[0], qreg[1])
20 |
21 | # 아다마르 연산자를 0번째 큐비트에 적용하여 중첩을 해제합니다.
22 | circ.h(qreg[0])
23 |
24 | # 메시지를 얻기위해 측정 게이트를 추가합니다.
25 | circ.measure(qreg, creg)
26 |
27 | # 회로를 출력합니다.
28 | print("Circuit:")
29 | print(circ.draw())
30 |
31 | # 상태벡터 시뮬레이터 백엔드 위에서 회로를 실행하고 결과를 얻습니다.
32 | backend = qiskit.Aer.get_backend("statevector_simulator")
33 | job = qiskit.execute(circ, backend)
34 | res = job.result()
35 | print(res.get_counts())
36 |
--------------------------------------------------------------------------------
/korean/chapter07/qiskit/teleportation.py:
--------------------------------------------------------------------------------
1 | """키스킷에서 양자 원격이동하기."""
2 |
3 | from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
4 | #from qiskit import available_backends, execute
5 |
6 | # 양자 레지스터와 고전 레지스터를 생성합니다.
7 | q = QuantumRegister(3)
8 | c = ClassicalRegister(3)
9 | qc = QuantumCircuit(q, c)
10 |
11 | # 초기 중첩 양자 상태 |+>를 구현합니다.
12 | qc.h(q[0])
13 |
14 | # 큐비트를 중첩 해제합니다.
15 | qc.h(q[0])
16 |
17 | # CNOT 연산자를 적용합니다.
18 | qc.cx(q[0], q[1])
19 |
20 | # 큐비트들을 중첩상태로 놓습니다. 현재 두 상태는 같습니다.
21 | qc.h(q[0])
22 | qc.h(q[1])
23 |
24 | # 큐비트 0에 대해 단일 유니타리 연산으로 초기 상태를 준비합니다.
25 | qc.u1(0.5, q[0])
26 |
27 | # CNOT 연산을 큐비트 0과 큐비트 1에 적용합니다.
28 | qc.cx(q[0], q[1])
29 |
30 | # 큐비트 0을 |+>와 |-> 기저로 측정합니다.
31 | qc.h(q[0])
32 | qc.measure(q[0], c[0])
33 |
34 | # 필요하다면 큐비트 1에 대해 위상 보정(phase correction)을 수행합니다.
35 | if c[0] == 1:
36 | qc.z(q[1])
37 |
38 | # 큐비트 0에 대해 단일 유니타리 연산으로 초기 상태를 준비합니다.
39 | qc.u1(0.5, q[0])
40 |
41 | # 큐비트 1과 큐비트 2를 사용해 얽힌 상태를 만듭니다.
42 | qc.h(q[1])
43 | qc.cx(q[1], q[2])
44 |
45 | # 최적화를 위해 게이트를 재배열하는 것을 막고자 장막(Barrier)을 걸어둡니다.
46 | qc.barrier(q)
47 |
48 | # CNOT 연산을 큐비트 0과 큐비트 1에 적용합니다.
49 | qc.cx(q[0], q[1])
50 |
51 | # 큐비트 1을 계산기저에서 측정합니다.
52 | qc.measure(q[1], c[1])
53 | # 필요하다면 큐비트 2에 대해서 비트 반전 보정(bit flip correction)을 수행합니다.
54 | if c[1] == 1:
55 | qc.x(q[2])
56 |
57 | # 큐비트 0을 |+>와 |-> 기저로 측정합니다.
58 | qc.h(q[0])
59 | qc.measure(q[0], c[0])
60 | # 필요하다면 큐비트 2에 대해 위상 보정(phase correction)을 수행합니다.
61 | if c[0] == 1:
62 | qc.z(q[2])
63 |
64 | print(qc.draw())
--------------------------------------------------------------------------------
/korean/chapter08/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter08/.DS_Store
--------------------------------------------------------------------------------
/korean/chapter08/cirq/bernstein-vazirani.py:
--------------------------------------------------------------------------------
1 | """번스타인-바지라니(Bernstein-Vazirani) 알고리즘 써큐 예제."""
2 |
3 | # 가져오기
4 | import random
5 |
6 | import cirq
7 |
8 |
9 | def main():
10 | """BV알고리즘을 수행합니다."""
11 | # 입력 큐비트 개수 (역자주 : 총 큐비트 개수는 출력 포함 9개)
12 | qubit_count = 8
13 |
14 | # 회로를 수행하는 횟수
15 | circuit_sample_count = 3
16 |
17 | # 사용할 큐비트 가져오기.
18 | input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
19 | output_qubit = cirq.GridQubit(qubit_count, 0)
20 |
21 | # 오라클을 위한 계수들을 무작위로 선정하고 질의(query)를 요청할 양자 회로를 생성한다.
22 | secret_bias_bit = random.randint(0, 1)
23 | secret_factor_bits = [random.randint(0, 1) for _ in range(qubit_count)]
24 | oracle = make_oracle(input_qubits,
25 | output_qubit,
26 | secret_factor_bits,
27 | secret_bias_bit)
28 | print('Secret function:\nf(x) = x*<{}> + {} (mod 2)'.format(
29 | ', '.join(str(e) for e in secret_factor_bits),
30 | secret_bias_bit))
31 |
32 | # 양자 오라클을 정확히 한 번만 질의를 요청하는 특수 목적의 양자 회로에 내포한다.
33 | circuit = make_bernstein_vazirani_circuit(
34 | input_qubits, output_qubit, oracle)
35 | print('\n회로 :')
36 | print(circuit)
37 |
38 | # 회로를 몇 번 측정한다.
39 | simulator = cirq.Simulator()
40 | result = simulator.run(circuit, repetitions=circuit_sample_count)
41 | frequencies = result.histogram(key='result', fold_func=bitstring)
42 | print('\nSampled results:\n{}'.format(frequencies))
43 |
44 | # 실제로 비밀값을 찾아냈는지 확인한다.
45 | most_common_bitstring = frequencies.most_common(1)[0][0]
46 | print('\nMost common matches secret factors:\n{}'.format(
47 | most_common_bitstring == bitstring(secret_factor_bits)))
48 |
49 |
50 | def make_oracle(input_qubits,
51 | output_qubit,
52 | secret_factor_bits,
53 | secret_bias_bit):
54 | """함수 f(a) = a*factors + bias (mod 2)를 구현하는 양자 오라클."""
55 | if secret_bias_bit:
56 | yield cirq.X(output_qubit)
57 |
58 | for qubit, bit in zip(input_qubits, secret_factor_bits):
59 | if bit:
60 | yield cirq.CNOT(qubit, output_qubit)
61 |
62 |
63 | def make_bernstein_vazirani_circuit(input_qubits, output_qubit, oracle):
64 | """단 한번의 질의만으로 f(a) = a*factors + bias (mod 2) 문제를 푸는 양자 회로."""
65 | c = cirq.Circuit()
66 |
67 | # 큐비트를 초기화한다.
68 | c.append([
69 | cirq.X(output_qubit),
70 | cirq.H(output_qubit),
71 | cirq.H.on_each(*input_qubits),
72 | ])
73 |
74 | # 양자 오라클에 질의를 요청한다.
75 | c.append(oracle)
76 |
77 | # X 기저로 측정한다.
78 | c.append([
79 | cirq.H.on_each(*input_qubits),
80 | cirq.measure(*input_qubits, key='result')
81 | ])
82 |
83 | return c
84 |
85 |
86 | def bitstring(bits):
87 | """반복가능한 bits에서 대응되는 비트 문자열을 생성한다."""
88 | return ''.join(str(int(b)) for b in bits)
89 |
90 | if __name__ == '__main__':
91 | main()
92 |
--------------------------------------------------------------------------------
/korean/chapter08/cirq/deutsch-jozsa.py:
--------------------------------------------------------------------------------
1 | """3 큐비트 도이치-조사(Deutsch-Jozsa) 알고리즘의 써큐 예제."""
2 |
3 | # 써큐 라이브러리 가져오기.
4 | import cirq
5 |
6 | # 2개 데이터와 1개 목적 큐비트, 총 3개 큐비트 가져오기.
7 | q0, q1, q2 = cirq.LineQubit.range(3)
8 |
9 | # 상수함수를 위한 양자 오라클 게이트 집합 정의.
10 | constant = ([], [cirq.X(q2)])
11 |
12 | # 균형함수를 위한 양자 오라클 게이트 집합 정의.
13 | balanced = ([cirq.CNOT(q0, q2)],
14 | [cirq.CNOT(q1, q2)],
15 | [cirq.CNOT(q0, q2), cirq.CNOT(q1, q2)],
16 | [cirq.CNOT(q0, q2), cirq.X(q2)],
17 | [cirq.CNOT(q1, q2), cirq.X(q2)],
18 | [cirq.CNOT(q0, q2), cirq.CNOT(q1, q2), cirq.X(q2)])
19 |
20 | def your_circuit(oracle):
21 | """3개 큐비트 도이치-조사 알고리즘을 위한 양자 회로 생성자."""
22 | # 위상 반동(phase kickback) 공식을 사용합니다.
23 | yield cirq.X(q2), cirq.H(q2)
24 |
25 | # 입력 비트들을 동등한 양자 중첩상태로 바꿉니다.
26 | yield cirq.H(q0), cirq.H(q1)
27 |
28 | # 함수에 질의를 요청합니다.
29 | yield oracle
30 |
31 | # 결과를 얻기 위해 간섭을 수행하고 마지막 큐비트를 |1> 상태로 둡니다.
32 | yield cirq.H(q0), cirq.H(q1), cirq.H(q2)
33 |
34 | # 결과를 목적 큐비트에 담기 위해 마지막 OR 게이트를 수행합니다.
35 | yield cirq.X(q0), cirq.X(q1), cirq.CCX(q0, q1, q2)
36 | yield cirq.measure(q2)
37 |
38 | # 시뮬레이터를 가져옵니다.
39 | simulator = cirq.Simulator()
40 |
41 | # 상수 함수 오라클을 위한 양자 회로를 수행합니다.
42 | print('Your result on constant functions')
43 | for oracle in constant:
44 | result = simulator.run(cirq.Circuit(your_circuit(oracle)), repetitions=10)
45 | print(result)
46 |
47 | # 균형 함수 오라클을 위한 양자 회로를 수행합니다.
48 | print('Your result on balanced functions')
49 | for oracle in balanced:
50 | result = simulator.run(cirq.Circuit(your_circuit(oracle)), repetitions=10)
51 | print(result)
52 |
--------------------------------------------------------------------------------
/korean/chapter08/cirq/deutsch.py:
--------------------------------------------------------------------------------
1 | """도이치-조사(Deutsch-Jozsa) 알고리즘."""
2 |
3 | # 써큐 라이브러리를 가져온다.
4 | import cirq
5 |
6 | # 데이터 큐비트와 목적 큐비트 두 개의 큐비트를 가져온다.
7 | q0, q1 = cirq.LineQubit.range(2)
8 |
9 | # 양자 오라클 사전을 정의한다.
10 | oracles = {'0': [], '1': [cirq.X(q1)], 'x': [cirq.CNOT(q0, q1)],
11 | 'notx': [cirq.CNOT(q0, q1), cirq.X(q1)]}
12 |
13 | def deutsch_algorithm(oracle):
14 | """주어진 양자 오라클 oracle을 기반으로 도이치 알고리즘을 수행하는 양자회로의 생성자."""
15 | yield cirq.X(q1)
16 | yield cirq.H(q0), cirq.H(q1)
17 | yield oracle
18 | yield cirq.H(q0)
19 | yield cirq.measure(q0)
20 |
21 | # 모든 오라클에 대한 양자 회로들을 화면에 출력하기.
22 | for key, oracle in oracles.items():
23 | print('Circuit for {}...'.format(key))
24 | print(cirq.Circuit(deutsch_algorithm(oracle)), end="\n\n")
25 |
26 | # 시뮬레이터 가져오기.
27 | simulator = cirq.Simulator()
28 |
29 | # 상수함수와 균형함수를 구분하기 위해 각각의 오라클에 대한 회로를 수행한다.
30 | for key, oracle in oracles.items():
31 | result = simulator.run(
32 | cirq.Circuit(deutsch_algorithm(oracle)),
33 | repetitions=10
34 | )
35 | print('oracle: {:<4} results: {}'.format(key, result))
36 |
--------------------------------------------------------------------------------
/korean/chapter08/cirq/grover.py:
--------------------------------------------------------------------------------
1 | """써큐 그로버(Grover) 알고리즘."""
2 |
3 | # 가져오기
4 | import random
5 |
6 | import cirq
7 |
8 |
9 | def set_io_qubits(qubit_count):
10 | """qubit_count개의 입력 큐비트와 1개의 출력 큐비트를 반환합니다."""
11 | input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
12 | output_qubit = cirq.GridQubit(qubit_count, 0)
13 | return (input_qubits, output_qubit)
14 |
15 |
16 | def make_oracle(input_qubits, output_qubit, x_bits):
17 | """함수 {f(x) = 1 if x==x', f(x) = 0 if x!= x'}를 구현합니다."""
18 | # 양자 오라클을 생성합니다.
19 | # 입력 큐비트와 입력 x 비트가 (1, 1)인 경우 토폴리(Toffoli)게이트 입니다.
20 | # 그외의 모든 경우는 0 비트를 반전합니다.
21 | yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)
22 | yield(cirq.TOFFOLI(input_qubits[0], input_qubits[1], output_qubit))
23 | yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit)
24 |
25 |
26 | def make_grover_circuit(input_qubits, output_qubit, oracle):
27 | """sqrt(N)번 양자 오라클을 수행하여 얻은 상태에서 값을 추출합니다."""
28 | # 2개 입력 큐비트의 경우 그로버 연선자를 단 한번만 수행합니다.
29 | c = cirq.Circuit()
30 |
31 | # 큐비트를 초기화합니다.
32 | c.append([
33 | cirq.X(output_qubit),
34 | cirq.H(output_qubit),
35 | cirq.H.on_each(*input_qubits),
36 | ])
37 |
38 | # 양자 오라클에 질의합니다.
39 | c.append(oracle)
40 |
41 | # 그로버 연산자를 구축합니다.
42 | c.append(cirq.H.on_each(*input_qubits))
43 | c.append(cirq.X.on_each(*input_qubits))
44 | c.append(cirq.H.on(input_qubits[1]))
45 | c.append(cirq.CNOT(input_qubits[0], input_qubits[1]))
46 | c.append(cirq.H.on(input_qubits[1]))
47 | c.append(cirq.X.on_each(*input_qubits))
48 | c.append(cirq.H.on_each(*input_qubits))
49 |
50 | # 결과를 측정합니다.
51 | c.append(cirq.measure(*input_qubits, key='result'))
52 |
53 | return c
54 |
55 |
56 | def bitstring(bits):
57 | return ''.join(str(int(b)) for b in bits)
58 |
59 |
60 | def main():
61 | qubit_count = 2
62 | circuit_sample_count = 10
63 |
64 | # 입출력 큐비트를 설정합니다.
65 | (input_qubits, output_qubit) = set_io_qubits(qubit_count)
66 |
67 | # 양자 오라클에 요청하기 위한 비밀값 비트열 x를 생성합니다.
68 | x_bits = [random.randint(0, 1) for _ in range(qubit_count)]
69 | print('Secret bit sequence: {}'.format(x_bits))
70 |
71 | # 블랙박스 양자 오라클을 생성합니다.
72 | oracle = make_oracle(input_qubits, output_qubit, x_bits)
73 |
74 | # 생성된 오라클을 내포하는 그로버 알고리즘 양자 회로를 생성합니다.
75 | circuit = make_grover_circuit(input_qubits, output_qubit, oracle)
76 | print('Circuit:')
77 | print(circuit)
78 |
79 | # 양자 회로를 수행합니다.
80 | simulator = cirq.Simulator()
81 | result = simulator.run(circuit, repetitions=circuit_sample_count)
82 |
83 | frequencies = result.histogram(key='result', fold_func=bitstring)
84 | print('Sampled results:\n{}'.format(frequencies))
85 |
86 | # 실제로 목표로한 비밀값을 찾아냈는지 확인합니다.
87 | most_common_bitstring = frequencies.most_common(1)[0][0]
88 | print('Most common bitstring: {}'.format(most_common_bitstring))
89 | print('Found a match: {}'.format(
90 | most_common_bitstring == bitstring(x_bits)))
91 |
92 |
93 | if __name__ == '__main__':
94 | main()
95 |
96 |
--------------------------------------------------------------------------------
/korean/chapter08/cirq/qft.py:
--------------------------------------------------------------------------------
1 | """4-큐비트계에서 양자 퓨리에 변환을 위한 회로를 생성하기 시뮬레이션하는 예제."""
2 |
3 | # 가져오기
4 | import numpy as np
5 |
6 | import cirq
7 |
8 |
9 | def main():
10 | """양자 퓨리에 변환을 수행합니다."""
11 | # 회로를 생성하기 화면에 표시합니다.
12 | qft_circuit = generate_2x2_grid_qft_circuit()
13 | print('Circuit:')
14 | print(qft_circuit)
15 |
16 | # 시뮬레이션 한 뒤 최종 양자 상태를 얻습니다.
17 | simulator = cirq.Simulator()
18 | result = simulator.simulate(qft_circuit)
19 |
20 | # 최종 상태를 출력합니다.
21 | print('\nFinalState')
22 | print(np.around(result.final_state, 3))
23 |
24 |
25 | def cz_and_swap(q0, q1, rot):
26 | """입력 큐비트에 제어-Z회전(controlled-RZ)과 교환(SWAP)게이트를 적용하는 생성자. """
27 | yield cirq.CZ(q0, q1)**rot
28 | yield cirq.SWAP(q0,q1)
29 |
30 |
31 | def generate_2x2_grid_qft_circuit():
32 | """2 x 2 평면 큐비트 구조에 적용되는 양자 퓨리에 변환회로를 반환.
33 |
34 | 다음 논문의 회로를 참고: https://arxiv.org/pdf/quant-ph/0402196.pdf.
35 | """
36 | # 2*2 정방형 격자 큐비트를 가져온다.
37 | a, b, c, d = [cirq.GridQubit(0, 0), cirq.GridQubit(0, 1),
38 | cirq.GridQubit(1, 1), cirq.GridQubit(1, 0)]
39 |
40 | # 회로를 생성한다.
41 | circuit = cirq.Circuit(
42 | cirq.H(a),
43 | cz_and_swap(a, b, 0.5),
44 | cz_and_swap(b, c, 0.25),
45 | cz_and_swap(c, d, 0.125),
46 | cirq.H(a),
47 | cz_and_swap(a, b, 0.5),
48 | cz_and_swap(b, c, 0.25),
49 | cirq.H(a),
50 | cz_and_swap(a, b, 0.5),
51 | cirq.H(a),
52 | strategy=cirq.InsertStrategy.EARLIEST
53 | )
54 |
55 | return circuit
56 |
57 |
58 | if __name__ == '__main__':
59 | main()
60 |
--------------------------------------------------------------------------------
/korean/chapter08/cirq/shor.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# 쇼어(Shor)의 소인수 분해 알고리즘 써큐 예제"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "이 노트북은 쇼어의 알고리즘을 써큐에서 구현하는 교육 자료입니다. 이 지침서는 [이 곳의 써큐 예제](https://github.com/quantumlib/Cirq/blob/master/examples/shor.py)에서 수정/보완된 자료입니다.."
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 1,
20 | "metadata": {},
21 | "outputs": [],
22 | "source": [
23 | "\"\"\"노트북을 위한 라이브러리 가져오기.\"\"\"\n",
24 | "import fractions\n",
25 | "import math\n",
26 | "import random\n",
27 | "\n",
28 | "import numpy as np\n",
29 | "import sympy\n",
30 | "from typing import Callable, List, Optional, Sequence, Union\n",
31 | "\n",
32 | "import cirq"
33 | ]
34 | },
35 | {
36 | "cell_type": "markdown",
37 | "metadata": {},
38 | "source": [
39 | "# 위수 찾기"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {},
45 | "source": [
46 | "정수 $n$을 소인수 분해하는 문제는 모듈러 지수함수(차후에 설명)의 주기를 찾는 문제로 좁혀질 수 있습니다. 이 주기를 찾는 것은 (매우 높은 확률로) 법(modulo) $n$에 대한 곱셈 군(multiplicative group)의 무작위로 추출된 한 원소의 위수를 찾는 것으로 달성할 수 있습니다.\n",
47 | "\n",
48 | "양의 정수 $n$에 대하여, \n",
49 | "\n",
50 | "\\begin{equation}\n",
51 | "\\mathbb{Z}_n := \\{x \\in \\mathbb{Z}_+ : x < n \\text{ 이고 } \\text{gcd}(x, n) = 1\\}\n",
52 | "\\end{equation}\n",
53 | "\n",
54 | "인 법 $n$에 대한 곱셈 군을 정의합니다.\n",
55 | "주어진 $x \\in \\mathbb{Z}_n$에 대하여 $x^r \\text{ mod } n = 1$을 만족하는 가장 작은 양의 정수 $r$를 계산합니다. \n",
56 | "\n",
57 | "군이론/정수론으로부터 다음을 보일 수 있습니다.\n",
58 | "\n",
59 | "(1) 그러한 정수 $r$이 존재합니다. (Note that $g^{|G|} = 1_G$ for any group $G$ with cardinality $|G|$ and element $g \\in G$., but it's possible that $r < |G|$.)\n",
60 | "\n",
61 | "(2) 만일 소수 $p$와 $q$에 대하여 $n = pq$일 때, $|\\mathbb{Z}_n| = \\phi(n) = (p - 1) (q - 1)$입니다. (이러한 함수 $\\phi$를 [오일러의 피 함수(Euler's totient function)](https://ko.wikipedia.org/wiki/%EC%98%A4%EC%9D%BC%EB%9F%AC_%ED%94%BC_%ED%95%A8%EC%88%98)라고 합니다.)\n",
62 | "\n",
63 | "(3) 모듈러 지수함수\n",
64 | "\n",
65 | "\\begin{equation}\n",
66 | "f_x(z) := x^z \\mod n\n",
67 | "\\end{equation}\n",
68 | "\n",
69 | "는 주기 $r$ (원소 $x \\in \\mathbb{Z}_n$의 위수)을 가집니다. 즉, $f_x(z + r) = f_x(z)$입니다. \n",
70 | "\n",
71 | "(4) 모듈러 지수함수의 주기를 알 수 있다면, (매우 높은 확률로) $p$와 $q$를 알아낼 수 있습니다. -- 즉, $n$의 인수분해입니다."
72 | ]
73 | },
74 | {
75 | "cell_type": "markdown",
76 | "metadata": {},
77 | "source": [
78 | "복습차원에서, 정수 $n$의 곱셈군 $\\mathbb{Z}_n$의 원소들을 다음의 단순한 함수로 그려볼 수 있습니다.."
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": 2,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "\"\"\"곱셈군 Z_n의 원소들을 계산하는 함수.\"\"\"\n",
88 | "def multiplicative_group(n: int) -> List[int]:\n",
89 | " \"\"\"법 n의 곱셈군을 반환합니다.\n",
90 | " \n",
91 | " Args:\n",
92 | " n: 곱셈군의 법(modulus).\n",
93 | " \"\"\"\n",
94 | " assert n > 2\n",
95 | " group = [1, 2]\n",
96 | " for x in range(3, n):\n",
97 | " if math.gcd(x, n) == 1:\n",
98 | " group.append(x)\n",
99 | " return group"
100 | ]
101 | },
102 | {
103 | "cell_type": "markdown",
104 | "metadata": {},
105 | "source": [
106 | "예를 들어, 법 $n = 15$의 곱셈군은 아래와 같습니다."
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": 3,
112 | "metadata": {
113 | "scrolled": true
114 | },
115 | "outputs": [
116 | {
117 | "name": "stdout",
118 | "output_type": "stream",
119 | "text": [
120 | "The multiplicative group modulo n = 15 is:\n",
121 | "[1, 2, 4, 7, 8, 11, 13, 14]\n"
122 | ]
123 | }
124 | ],
125 | "source": [
126 | "\"\"\"곱셈군 예제.\"\"\"\n",
127 | "n = 15\n",
128 | "print(f\"The multiplicative group modulo n = {n} is:\")\n",
129 | "print(multiplicative_group(n))"
130 | ]
131 | },
132 | {
133 | "cell_type": "markdown",
134 | "metadata": {},
135 | "source": [
136 | "평범한 곱셈 연산에서 이러한 원소들의 집합이 정말로 군을 형성하는지 확인해 보세요."
137 | ]
138 | },
139 | {
140 | "cell_type": "markdown",
141 | "metadata": {},
142 | "source": [
143 | "## 고전적 위수 찾기"
144 | ]
145 | },
146 | {
147 | "cell_type": "markdown",
148 | "metadata": {},
149 | "source": [
150 | "아래에 정수 $x \\in \\mathbb{Z}_n$의 위수 $r$을 고전적으로 찾는 함수가 있습니다. 이 함수는 단순히 수열 \n",
151 | "\n",
152 | "\\begin{align}\n",
153 | " &x^2 \\text{ mod } n, \\\\\n",
154 | " &x^3 \\text{ mod } n, \\\\\n",
155 | " &x^4 \\text{ mod } n, \\\\\n",
156 | " &\\ \\ \\ \\ \\ \\ \\ \\ \\vdots\n",
157 | "\\end{align}\n",
158 | "\n",
159 | "을 $x^r = 1 \\text{ mod } n$인 정수 $r$이 될 때까지 계산합니다. $|\\mathbb{Z}_n| = \\phi(n)$이기 때문에, 이 위수 찾기 알고리즘은 시간복잡도 $O(\\phi(n))$을 갖는데 이는 비효율적입니다. (정수 $n$의 비트수를 $L$이라 할 때 대략 $O(2^{L / 2})$.)"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": 4,
165 | "metadata": {},
166 | "outputs": [],
167 | "source": [
168 | "\"\"\"Z_n의 한 원소의 위수를 고전적으로 계산하는 함수.\"\"\"\n",
169 | "def classical_order_finder(x: int, n: int) -> Optional[int]:\n",
170 | " \"\"\"x**r mod n == 1를 만족하는 최소의 양의 정수를 계산.\n",
171 | "\n",
172 | " Args:\n",
173 | " x: 위수가 계산될 1보다 크고 법 n의 곱셈군에 속하는 정수. (정수 n과 서로소인 양의 정수\n",
174 | " 들의 곱으로 이루어진 수)\n",
175 | " n: 상기 곱셈군의 법\n",
176 | "\n",
177 | " Returns:\n",
178 | " x**r == 1 mod n를 만족하는 최소의 양의 정수.\n",
179 | " 이 알고리즘은 항상 성공합니다. (즉, 절대로 None을 반환하지 않습니다.)\n",
180 | "\n",
181 | " Raises:\n",
182 | " ValueError: x가 1이거나 법 n의 곱셈군의 원소가 아닐 때.\n",
183 | " \"\"\"\n",
184 | " # x가 Z_n에 속하는 유효한 값인지 확인합니다.\n",
185 | " if x < 2 or x >= n or math.gcd(x, n) > 1:\n",
186 | " raise ValueError(f\"Invalid x={x} for modulus n={n}.\")\n",
187 | " \n",
188 | " # 위수를 결정합니다.\n",
189 | " r, y = 1, x\n",
190 | " while y != 1:\n",
191 | " y = (x * y) % n\n",
192 | " r += 1\n",
193 | " return r"
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "주어진 $x \\in \\mathbb{Z}_n$와 $n$에 대하여 위수 $r$을 계산하는 예제가 아래 코드 영역에 있습니다."
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 5,
206 | "metadata": {
207 | "scrolled": true
208 | },
209 | "outputs": [
210 | {
211 | "name": "stdout",
212 | "output_type": "stream",
213 | "text": [
214 | "x^r mod n = 8^4 mod 15 = 1\n"
215 | ]
216 | }
217 | ],
218 | "source": [
219 | "\"\"\"(고전적으로) 한 원소의 위수를 계산하는 예제.\"\"\"\n",
220 | "n = 15 # 곱셈군은 [1, 2, 4, 7, 8, 11, 13, 14]\n",
221 | "x = 8\n",
222 | "r = classical_order_finder(x, n)\n",
223 | "\n",
224 | "# 위수가 정말로 맞는지 확인합니다.\n",
225 | "print(f\"x^r mod n = {x}^{r} mod {n} = {x**r % n}\")"
226 | ]
227 | },
228 | {
229 | "cell_type": "markdown",
230 | "metadata": {},
231 | "source": [
232 | "하지만 쇼어 알고리즘의 핵심 양자 요소는 바로 위수 찾기, 양자 회로로 구현되어야 하기에 아래에서 논의하도록 하겠습니다."
233 | ]
234 | },
235 | {
236 | "cell_type": "markdown",
237 | "metadata": {},
238 | "source": [
239 | "## 양자 위수 찾기"
240 | ]
241 | },
242 | {
243 | "cell_type": "markdown",
244 | "metadata": {},
245 | "source": [
246 | "양자 위수 찾기는 본질적으로 무작위로 추출된 $x \\in \\mathbb{Z}_n$에 대한 모듈러 지수함수 $f_x(z)$를 계산하는 유니타리 $U$를 수반하는 양자 위상 추정 알고리즘 입니다. $U$가 기초 게이트들로부터 어떻게 계산되는지의 상세한 이론은 특히 처음 읽는 경우 설명하기 복잡할 수 있습니다. 이 강의 자료에서는, 기초 게이트들에 대한 상세한 이론을 들여다 보지 않고도 그러한 유니타리 $U$ 구현할 수 있는 써큐의 산술연산을 사용할 것입니다.\n",
247 | "\n",
248 | "아래는 써큐에서 단순 산술 연산(덧셈)의 예제를 처음 보여줍니다. 그후 우리가 다룰 연산(모듈러 지수)을 논의할 것입니다."
249 | ]
250 | },
251 | {
252 | "cell_type": "markdown",
253 | "metadata": {},
254 | "source": [
255 | "### 써큐에서 양자 산술 연산하기"
256 | ]
257 | },
258 | {
259 | "cell_type": "markdown",
260 | "metadata": {},
261 | "source": [
262 | "여기서 우리는 써큐에서 산술 연산, 즉 모듈러 덧셈(modular addition)을 정의하는 예제에 대해 논의할 것입니다. 이 연산은 입력 레지서터의 값을 목적 레지스터에 더한 뒤 나머지를 취해 넣습니다. 더 자세히 설명하면 이 연산은 두 큐비트 레지스터에서 다음과 같이 동작합니다.\n",
263 | "\n",
264 | "\\begin{equation}\n",
265 | "|a\\rangle_i |b\\rangle_t \\mapsto |a\\rangle_i |a + b \\text{ mod } N_t \\rangle_t .\n",
266 | "\\end{equation}\n",
267 | "\n",
268 | "여기서 첨자 $i$와 $t$는 각각 영어 input(입력)과 target(목적) 레지스터를 의미합니다. 그리고 $N_t$는 목적 레지스터의 차원을 의미합니다.\n",
269 | "\n",
270 | "이 연산을 정의하기 위해 (이름은 `Adder`라고 합시다) `cirq.ArithmeticOperation` 클래스에서 상속받아 아래의 4개 메소드 함수를 재정의 합니다. 주요 함수인 `apply`는 산술을 정의합니다. 여기서 우리는 위에 나온 더 정확한 $a + b \\text{ mod } N_t$ 대신에 단순히 수식 $a + b$을 구현해 봅시다. -- `cirq.ArithmeticOperation` 클래스는 그 연산이 반드시 가역적이어야 하기 때문에 우리가 단순히 $a + b$로 무엇을 의미하려 했는지 유추할 수 있습니다. . "
271 | ]
272 | },
273 | {
274 | "cell_type": "code",
275 | "execution_count": 6,
276 | "metadata": {},
277 | "outputs": [],
278 | "source": [
279 | "\"\"\"써큐에서 (양자) 산술 연산자 정의하는 예제.\"\"\"\n",
280 | "class Adder(cirq.ArithmeticOperation):\n",
281 | " \"\"\"양자 덧셈.\"\"\"\n",
282 | " def __init__(self, target_register, input_register):\n",
283 | " self.input_register = input_register\n",
284 | " self.target_register = target_register\n",
285 | " \n",
286 | " def registers(self):\n",
287 | " return self.target_register, self.input_register\n",
288 | " \n",
289 | " def with_registers(self, *new_registers):\n",
290 | " return Add(*new_registers)\n",
291 | " \n",
292 | " def apply(self, target_value, input_value):\n",
293 | " return target_value + input_value"
294 | ]
295 | },
296 | {
297 | "cell_type": "markdown",
298 | "metadata": {},
299 | "source": [
300 | "이제 클래스를 정의했으므로 회로에서 사용할 수 있습니다. 아래는 두 개 큐비트 레지스터를 생성하고 \n",
301 | "$X$게이트를 이용해 첫 번째 레지스터를 (이진수) $|10\\rangle$로, 두 번째 레지스터를 (이진수)\n",
302 | "$|01\\rangle$로 설정합니다. . \n",
303 | "그런 후 `Adder`연산을 사용하고, 모든 큐비트를 측정합니다.\n",
304 | "\n",
305 | "이진수로 $10 + 01 = 11$이기 때문에, 목적 레지스터에서 항상 $|11\\rangle$를 측정할 것이라 기대할 수 있습니다.\n",
306 | "게다가, 입력 레지스터를 바꾸지 않았기 때문에 입력 레지스터도 항상 $|10\\rangle$를 측정할 것입니다. \n",
307 | "요약하면, 우리가 측정할 수 있는 것은 $1011$ 뿐임을 알 수 있습니다. "
308 | ]
309 | },
310 | {
311 | "cell_type": "code",
312 | "execution_count": 7,
313 | "metadata": {
314 | "scrolled": true
315 | },
316 | "outputs": [
317 | {
318 | "name": "stdout",
319 | "output_type": "stream",
320 | "text": [
321 | "Circuit:\n",
322 | "\n",
323 | "0: ───X───#3──────────────────────────────────────────M───\n",
324 | " │\n",
325 | "1: ───────#4──────────────────────────────────────────M───\n",
326 | " │\n",
327 | "2: ───────<__main__.Adder object at 0x7ff2b8c3d9b0>───M───\n",
328 | " │\n",
329 | "3: ───X───#2──────────────────────────────────────────M───\n",
330 | "\n",
331 | "\n",
332 | "Measurement outcomes:\n",
333 | "\n",
334 | " 0 1 2 3\n",
335 | "0 1 0 1 1\n",
336 | "1 1 0 1 1\n",
337 | "2 1 0 1 1\n",
338 | "3 1 0 1 1\n",
339 | "4 1 0 1 1\n"
340 | ]
341 | }
342 | ],
343 | "source": [
344 | "\"\"\"회로에서 Adder를 사용하는 예제.\"\"\"\n",
345 | "# 두 개의 큐비트 레지스터\n",
346 | "qreg1 = cirq.LineQubit.range(2)\n",
347 | "qreg2 = cirq.LineQubit.range(2, 4)\n",
348 | "\n",
349 | "# 회로 정의하기\n",
350 | "circ = cirq.Circuit(\n",
351 | " cirq.ops.X.on(qreg1[0]),\n",
352 | " cirq.ops.X.on(qreg2[1]),\n",
353 | " Adder(input_register=qreg1, target_register=qreg2),\n",
354 | " cirq.measure_each(*qreg1),\n",
355 | " cirq.measure_each(*qreg2)\n",
356 | ")\n",
357 | "\n",
358 | "# 화면에 회로 출력하기\n",
359 | "print(\"Circuit:\\n\")\n",
360 | "print(circ)\n",
361 | "\n",
362 | "# 측정 결과 출력하기\n",
363 | "print(\"\\n\\nMeasurement outcomes:\\n\")\n",
364 | "print(cirq.sample(circ, repetitions=5).data)"
365 | ]
366 | },
367 | {
368 | "cell_type": "markdown",
369 | "metadata": {},
370 | "source": [
371 | "이 코드 영역의 출력을 살펴보면 가장 먼저 초기화용 $X$ 게이트들을 볼 수 있고, `Adder` 연산 그리고 마지막 측정들을 볼 수 있습니다. 다음으로 우리가 예측한대로 모든 측정 비트열들이 $1011$임을 알 수 있습니다."
372 | ]
373 | },
374 | {
375 | "cell_type": "markdown",
376 | "metadata": {},
377 | "source": [
378 | "덧셈 연산의 유니타리를 보는것도 아래 처럼 가능합니다. 여기서 우리는 목적 레지스터를 \n",
379 | "$|00\\rangle$를 갖는 2개 큐비트로 설정했습니다. 입력 레지스터는 $|01\\rangle$에 해당하도록\n",
380 | "1개 큐비트를 1로 설정하였습니다. "
381 | ]
382 | },
383 | {
384 | "cell_type": "code",
385 | "execution_count": 8,
386 | "metadata": {
387 | "scrolled": false
388 | },
389 | "outputs": [
390 | {
391 | "name": "stderr",
392 | "output_type": "stream",
393 | "text": [
394 | "/home/ryan/programs/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:5: ComplexWarning: Casting complex values to real discards the imaginary part\n",
395 | " \"\"\"\n"
396 | ]
397 | },
398 | {
399 | "data": {
400 | "text/plain": [
401 | "array([[0, 0, 0, 1],\n",
402 | " [1, 0, 0, 0],\n",
403 | " [0, 1, 0, 0],\n",
404 | " [0, 0, 1, 0]], dtype=int32)"
405 | ]
406 | },
407 | "execution_count": 8,
408 | "metadata": {},
409 | "output_type": "execute_result"
410 | }
411 | ],
412 | "source": [
413 | "\"\"\"Adder 연산의 유니타리 계산 예제.\"\"\"\n",
414 | "cirq.unitary(\n",
415 | " Adder(target_register=cirq.LineQubit.range(2),\n",
416 | " input_register=1)\n",
417 | ").astype(np.int32)"
418 | ]
419 | },
420 | {
421 | "cell_type": "markdown",
422 | "metadata": {},
423 | "source": [
424 | "이 유니타리를 다음과 같이 이해할 수 있습니다. 유니타리의 $i$번째 열은 상태 $|i + 1 \\text{ mod } 4\\rangle$를 의미합니다. \n",
425 | "예를들어 $0$번째 열을 보면 $|i + 1 \\text{ mod } 4\\rangle = |0 + 1 \\text{ mod } 4\\rangle = |1\\rangle$임을 알 수 있습니다. \n",
426 | "똑같이 $1$번째 열을 보면, $|i + 1 \\text{ mod } 4\\rangle = |1 + 1 \\text{ mod } 4\\rangle = |2\\rangle$ 상태입니다. \n",
427 | "마찬가지로 나머지 두 개 열도 이해할 수 있습니다."
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "metadata": {},
433 | "source": [
434 | "### 모듈러 지수 산술 연산."
435 | ]
436 | },
437 | {
438 | "cell_type": "markdown",
439 | "metadata": {},
440 | "source": [
441 | "모듈러 지수 산술 연산도 아래 나와 있는 것처럼 단순 덧셈 산술 연산과 비슷한 방법으로 정의할 수 있습니다. \n",
442 | "쇼어 알고리즘을 이해하기 위한 목적으로, 다음 코드 영역에서 가장 중요한 요소는 산술 연산을 정의하는 `apply` 메소드 입니다."
443 | ]
444 | },
445 | {
446 | "cell_type": "code",
447 | "execution_count": 9,
448 | "metadata": {},
449 | "outputs": [],
450 | "source": [
451 | "\"\"\"쇼어 알고리즘에서 사용되는 모듈러 지수 연산을 정의하기.\"\"\"\n",
452 | "class ModularExp(cirq.ArithmeticOperation):\n",
453 | " \"\"\"양자 모듈러 거듭제곱.\n",
454 | "\n",
455 | " 이 클래스는 밑을 지수 만큼 곱한 뒤 주어진 법에 따라 모듈로 연산을 하는 유니타리를 표현합니다. \n",
456 | " 더 정확하게는, 모듈러 지수 x**e mod n를 계산하는 유니타리 V를 표현합니다.\n",
457 | "\n",
458 | " V|y⟩|e⟩ = |y * x**e mod n⟩ |e⟩ 0 <= y < n\n",
459 | " V|y⟩|e⟩ = |y⟩ |e⟩ n <= y\n",
460 | "\n",
461 | " 여기서 y는 목적 레지스터이고, e는 지수 레지스터, x는 밑, n은 법입니다. 결론적으로,\n",
462 | "\n",
463 | " V|y⟩|e⟩ = (U**e|r⟩)|e⟩\n",
464 | "\n",
465 | " 인 유니타리 U는 다음과 같이 정의됩니다.\n",
466 | "\n",
467 | " U|y⟩ = |y * x mod n⟩ 0 <= y < n\n",
468 | " U|y⟩ = |y⟩ n <= y\n",
469 | " \"\"\"\n",
470 | " def __init__(\n",
471 | " self, \n",
472 | " target: Sequence[cirq.Qid],\n",
473 | " exponent: Union[int, Sequence[cirq.Qid]], \n",
474 | " base: int,\n",
475 | " modulus: int\n",
476 | " ) -> None:\n",
477 | " if len(target) < modulus.bit_length():\n",
478 | " raise ValueError(f'Register with {len(target)} qubits is too small '\n",
479 | " f'for modulus {modulus}')\n",
480 | " self.target = target\n",
481 | " self.exponent = exponent\n",
482 | " self.base = base\n",
483 | " self.modulus = modulus\n",
484 | "\n",
485 | " def registers(self) -> Sequence[Union[int, Sequence[cirq.Qid]]]:\n",
486 | " return self.target, self.exponent, self.base, self.modulus\n",
487 | "\n",
488 | " def with_registers(\n",
489 | " self,\n",
490 | " *new_registers: Union[int, Sequence['cirq.Qid']],\n",
491 | " ) -> cirq.ArithmeticOperation:\n",
492 | " if len(new_registers) != 4:\n",
493 | " raise ValueError(f'Expected 4 registers (target, exponent, base, '\n",
494 | " f'modulus), but got {len(new_registers)}')\n",
495 | " target, exponent, base, modulus = new_registers\n",
496 | " if not isinstance(target, Sequence):\n",
497 | " raise ValueError(\n",
498 | " f'Target must be a qubit register, got {type(target)}')\n",
499 | " if not isinstance(base, int):\n",
500 | " raise ValueError(\n",
501 | " f'Base must be a classical constant, got {type(base)}')\n",
502 | " if not isinstance(modulus, int):\n",
503 | " raise ValueError(\n",
504 | " f'Modulus must be a classical constant, got {type(modulus)}')\n",
505 | " return ModularExp(target, exponent, base, modulus)\n",
506 | "\n",
507 | " def apply(self, *register_values: int) -> int:\n",
508 | " assert len(register_values) == 4\n",
509 | " target, exponent, base, modulus = register_values\n",
510 | " if target >= modulus:\n",
511 | " return target\n",
512 | " return (target * base**exponent) % modulus\n",
513 | "\n",
514 | " def _circuit_diagram_info_(\n",
515 | " self,\n",
516 | " args: cirq.CircuitDiagramInfoArgs,\n",
517 | " ) -> cirq.CircuitDiagramInfo:\n",
518 | " assert args.known_qubits is not None\n",
519 | " wire_symbols: List[str] = []\n",
520 | " t, e = 0, 0\n",
521 | " for qubit in args.known_qubits:\n",
522 | " if qubit in self.target:\n",
523 | " if t == 0:\n",
524 | " if isinstance(self.exponent, Sequence):\n",
525 | " e_str = 'e'\n",
526 | " else:\n",
527 | " e_str = str(self.exponent)\n",
528 | " wire_symbols.append(\n",
529 | " f'ModularExp(t*{self.base}**{e_str} % {self.modulus})')\n",
530 | " else:\n",
531 | " wire_symbols.append('t' + str(t))\n",
532 | " t += 1\n",
533 | " if isinstance(self.exponent, Sequence) and qubit in self.exponent:\n",
534 | " wire_symbols.append('e' + str(e))\n",
535 | " e += 1\n",
536 | " return cirq.CircuitDiagramInfo(wire_symbols=tuple(wire_symbols))"
537 | ]
538 | },
539 | {
540 | "cell_type": "markdown",
541 | "metadata": {},
542 | "source": [
543 | "`apply` 메소드에서 `(target * base**exponent) % modulus`를 계산하고 있습니다. \n",
544 | "`target`과 `exponent` 변수는 각각의 큐비트 레지스터의 값들에 의존합니다.\n",
545 | " 그리고 밑 `base`와 법 `modulus`는 상수로, `modulus`는 $n$이고 `base`는 $x \\in \\mathbb{Z}_n$입니다. "
546 | ]
547 | },
548 | {
549 | "cell_type": "markdown",
550 | "metadata": {},
551 | "source": [
552 | "우리가 사용할 총 큐비트 개수는 $3 (L + 1)$인데 $L$은 인수분해할 정수 $n$을 저장하기 위한 총 비트열의 길이입니다. \n",
553 | "그러므로 모듈러 지수를 계산할 유니타리의 크기는 $4^{3(L + 1)}$입니다. \n",
554 | "적당히 크지 않은 수 $n = 15$에 대해서도 유니타리는 $2^{30}$개의 부동소수점 실수들을 메모리에 저장해야합니다.\n",
555 | "이는 대부분의 표준 노트북 컴퓨터에서는 엄두내지 못할 크기입니다."
556 | ]
557 | },
558 | {
559 | "cell_type": "code",
560 | "execution_count": 10,
561 | "metadata": {},
562 | "outputs": [
563 | {
564 | "name": "stdout",
565 | "output_type": "stream",
566 | "text": [
567 | "To factor n = 15 which has L = 4 bits, we need 3L + 3 = 15 qubits.\n"
568 | ]
569 | }
570 | ],
571 | "source": [
572 | "\"\"\"위상 추정을 위해 목적레지스터와 지수 레지스터를 생성하고\n",
573 | "쇼어 알고리즘에서 필요한 큐비트 개수를 살펴봅니다.\n",
574 | "\"\"\"\n",
575 | "n = 15\n",
576 | "L = n.bit_length()\n",
577 | "\n",
578 | "# 목적 레지스터는 L개의 큐비트를 갖습니다.\n",
579 | "target = cirq.LineQubit.range(L)\n",
580 | "\n",
581 | "# 지수 레지스터는 2L + 3개 큐비트를 갖습니다.\n",
582 | "exponent = cirq.LineQubit.range(L, 3 * L + 3)\n",
583 | "\n",
584 | "# 정수 n을 인수분해 하기 위한 총 큐비트 개수를 화면에 출력합니다.\n",
585 | "print(f\"To factor n = {n} which has L = {L} bits, we need 3L + 3 = {3 * L + 3} qubits.\")"
586 | ]
587 | },
588 | {
589 | "cell_type": "markdown",
590 | "metadata": {},
591 | "source": [
592 | "단순 덧셈 연산과 비교하면, 이 모듈러 지수 연산은 다음과 같이 (메모리가 허용하는)출력할 수 있는 유나타리를 갖습니다."
593 | ]
594 | },
595 | {
596 | "cell_type": "code",
597 | "execution_count": 11,
598 | "metadata": {},
599 | "outputs": [],
600 | "source": [
601 | "\"\"\"모듈러 지수 연산을 위한 유니타리(의 일부분) 확인하기.\"\"\"\n",
602 | "# 법 n의 곱셈군의 한 원소를 고릅니다.\n",
603 | "x = 5\n",
604 | "\n",
605 | "# 유니타리의 일부분을 확인합니다. n이 충분히 작은 경우에만 주석을 해제합시다.\n",
606 | "# cirq.unitary(ModularExp(target, exponent, x, n))"
607 | ]
608 | },
609 | {
610 | "cell_type": "markdown",
611 | "metadata": {},
612 | "source": [
613 | "## 회로에서 모듈러 지수 연산을 사용하기"
614 | ]
615 | },
616 | {
617 | "cell_type": "markdown",
618 | "metadata": {},
619 | "source": [
620 | "쇼어 알고리즘의 양자 요소는 모듈러 지수 연산에 대응하는 유니타리 $U$의 위상추정입니다.\n",
621 | "다음 코드 영역에서는 위에서 정의한 `ModularExp`를 사용하는 쇼어 알고리즘 회로를 생성합니다."
622 | ]
623 | },
624 | {
625 | "cell_type": "code",
626 | "execution_count": 12,
627 | "metadata": {},
628 | "outputs": [],
629 | "source": [
630 | "\"\"\"위수 찾기 양자 회로를 생성하는 함수.\"\"\"\n",
631 | "def make_order_finding_circuit(x: int, n: int) -> cirq.Circuit:\n",
632 | " \"\"\"x 모듈로 n의 위수를 계산하는 양자 회로를 반환합니다.\n",
633 | "\n",
634 | " 이 회로는 양자 위상 추정을 사용하여 다음 유니타리의 고유값을 계산합니다.\n",
635 | "\n",
636 | " U|y⟩ = |y * x mod n⟩ 0 <= y < n\n",
637 | " U|y⟩ = |y⟩ n <= y\n",
638 | "\n",
639 | " Args:\n",
640 | " x: 법 n에 대해 위수를 찾을 대상인 밑이 되는 양의 정수\n",
641 | " n: x의 위수와 서로소인 법\n",
642 | "\n",
643 | " Returns:\n",
644 | " x 모듈로 n의 위수를 찾는 양자 알고리즘 회로.\n",
645 | " \"\"\"\n",
646 | " L = n.bit_length()\n",
647 | " target = cirq.LineQubit.range(L)\n",
648 | " exponent = cirq.LineQubit.range(L, 3 * L + 3)\n",
649 | " return cirq.Circuit(\n",
650 | " cirq.X(target[L - 1]),\n",
651 | " cirq.H.on_each(*exponent),\n",
652 | " ModularExp(target, exponent, x, n),\n",
653 | " cirq.QFT(*exponent, inverse=True),\n",
654 | " cirq.measure(*exponent, key='exponent'),\n",
655 | " )"
656 | ]
657 | },
658 | {
659 | "cell_type": "markdown",
660 | "metadata": {},
661 | "source": [
662 | "이 함수를 사용하여, 주어진 $x$와 $n$에 대한 회로를 그려볼 수 있습니다."
663 | ]
664 | },
665 | {
666 | "cell_type": "code",
667 | "execution_count": 13,
668 | "metadata": {
669 | "scrolled": true
670 | },
671 | "outputs": [
672 | {
673 | "name": "stdout",
674 | "output_type": "stream",
675 | "text": [
676 | "0: ────────ModularExp(t*7**e % 15)────────────────────────────\n",
677 | " │\n",
678 | "1: ────────t1─────────────────────────────────────────────────\n",
679 | " │\n",
680 | "2: ────────t2─────────────────────────────────────────────────\n",
681 | " │\n",
682 | "3: ────X───t3─────────────────────────────────────────────────\n",
683 | " │\n",
684 | "4: ────H───e0────────────────────────QFT^-1───M('exponent')───\n",
685 | " │ │ │\n",
686 | "5: ────H───e1────────────────────────#2───────M───────────────\n",
687 | " │ │ │\n",
688 | "6: ────H───e2────────────────────────#3───────M───────────────\n",
689 | " │ │ │\n",
690 | "7: ────H───e3────────────────────────#4───────M───────────────\n",
691 | " │ │ │\n",
692 | "8: ────H───e4────────────────────────#5───────M───────────────\n",
693 | " │ │ │\n",
694 | "9: ────H───e5────────────────────────#6───────M───────────────\n",
695 | " │ │ │\n",
696 | "10: ───H───e6────────────────────────#7───────M───────────────\n",
697 | " │ │ │\n",
698 | "11: ───H───e7────────────────────────#8───────M───────────────\n",
699 | " │ │ │\n",
700 | "12: ───H───e8────────────────────────#9───────M───────────────\n",
701 | " │ │ │\n",
702 | "13: ───H───e9────────────────────────#10──────M───────────────\n",
703 | " │ │ │\n",
704 | "14: ───H───e10───────────────────────#11──────M───────────────\n"
705 | ]
706 | }
707 | ],
708 | "source": [
709 | "\"\"\"주기 찾기 양자 회로의 예제.\"\"\"\n",
710 | "n = 15\n",
711 | "x = 7\n",
712 | "circuit = make_order_finding_circuit(x, n)\n",
713 | "print(circuit)"
714 | ]
715 | },
716 | {
717 | "cell_type": "markdown",
718 | "metadata": {},
719 | "source": [
720 | "이전에 설명했듯이, 아다마르 게이트를 통해 지수 레지스터를 동등한 중첩상태를 만듭니다.\n",
721 | "목적레지스터의 마지막 큐비트에 가한 $X$는 위상 반동에 사용됩니다.\n",
722 | "모듈러 지수 연산은 위상추정에서 제어 유나타리들의 나열들을 수행합니다.\n",
723 | "그 후, 역 양자 푸리에 변환을 지수 레지스터에 가한 뒤 결과를 측정해 읽어내면 됩니다."
724 | ]
725 | },
726 | {
727 | "cell_type": "markdown",
728 | "metadata": {},
729 | "source": [
730 | "측정 결과를 설명하기 위해, 더 작은 회로에서 추출을 해보겠습니다. \n",
731 | "(실제로는 절대로 쇼어 알고리즘을 짝수인 $n = 6$에서 수행하지 않습니다. 이 것은 단순히 측정 결과를 설명하기 위한 예제일 뿐 입니다.)"
732 | ]
733 | },
734 | {
735 | "cell_type": "code",
736 | "execution_count": 14,
737 | "metadata": {
738 | "scrolled": true
739 | },
740 | "outputs": [
741 | {
742 | "name": "stdout",
743 | "output_type": "stream",
744 | "text": [
745 | "Raw measurements:\n",
746 | "exponent=01010001, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000\n",
747 | "\n",
748 | "Integer in exponent register:\n",
749 | " exponent\n",
750 | "0 0\n",
751 | "1 256\n",
752 | "2 0\n",
753 | "3 256\n",
754 | "4 0\n",
755 | "5 0\n",
756 | "6 0\n",
757 | "7 256\n"
758 | ]
759 | }
760 | ],
761 | "source": [
762 | "\"\"\"쇼어의 주기 찾기 회로를 측정하기.\"\"\"\n",
763 | "circuit = make_order_finding_circuit(x=5, n=6)\n",
764 | "res = cirq.sample(circuit, repetitions=8)\n",
765 | "\n",
766 | "print(\"Raw measurements:\")\n",
767 | "print(res)\n",
768 | "\n",
769 | "print(\"\\nInteger in exponent register:\")\n",
770 | "print(res.data)"
771 | ]
772 | },
773 | {
774 | "cell_type": "markdown",
775 | "metadata": {},
776 | "source": [
777 | "측정된 각각의 비트열들을 정수로 해석할 수 있습니다. 하지만 이 정수들이 우리에게 무엇을 말해줄까요?\n",
778 | "다음 소단원에서는 이들을 해석하기위해 고전적으로 어떻게 후처리를 하는지 볼 것입니다."
779 | ]
780 | },
781 | {
782 | "cell_type": "markdown",
783 | "metadata": {},
784 | "source": [
785 | "## 고전적 후처리"
786 | ]
787 | },
788 | {
789 | "cell_type": "markdown",
790 | "metadata": {},
791 | "source": [
792 | "우리가 측정한 정수는 $x \\in \\mathbb{Z}_n$의 위수 $r$에 대해 $s / r$에 가깝습니다. \n",
793 | "이때 $0 \\le s < r$인 정수 입니다. $s / r$로 부터 $r$을 구하기 위해 \n",
794 | "연분수 알고리즘(continued fractions algorithm)을 사용합니다. \n",
795 | "만일 위수 찾기 회로가 성공한다면 그 값을 출력하고, 아니면 `None`값을 출력합니다."
796 | ]
797 | },
798 | {
799 | "cell_type": "code",
800 | "execution_count": 15,
801 | "metadata": {},
802 | "outputs": [],
803 | "source": [
804 | "def process_measurement(result: cirq.TrialResult, x: int, n: int) -> Optional[int]:\n",
805 | " \"\"\"위수 찾기 회로의 출력을 해석하기.\n",
806 | "\n",
807 | " 구체적으로, exp(2πis/r)이 다음 유니타리 U의 고유값인 s/r을 결정합니다.\n",
808 | "\n",
809 | " U|y⟩ = |xy mod n⟩ 0 <= y < n\n",
810 | " U|y⟩ = |y⟩ n <= y\n",
811 | " \n",
812 | " 그 후 가능하다면 (연분수 알고리즘으로) r을 계산하고 반환합니다.\n",
813 | "\n",
814 | " Args:\n",
815 | " result: make_order_finding_circuit에 의해 생성된 회로의 출력을 추출하여 얻은\n",
816 | " 시행 결과.\n",
817 | "\n",
818 | " Returns:\n",
819 | " r(x 모듈로 n의 위수) 혹은 None.\n",
820 | " \"\"\"\n",
821 | " # 지수 레지스터의 출력 정수를 읽습니다.\n",
822 | " exponent_as_integer = result.data[\"exponent\"][0]\n",
823 | " exponent_num_bits = result.measurements[\"exponent\"].shape[1]\n",
824 | " eigenphase = float(exponent_as_integer / 2**exponent_num_bits)\n",
825 | "\n",
826 | " # f = s / r를 결정하기 위한 연분수 알고리즘.\n",
827 | " f = fractions.Fraction.from_float(eigenphase).limit_denominator(n)\n",
828 | " \n",
829 | " # 분자가 0이면 위수 찾기가 실패 했으므로 None을 반환합니다.\n",
830 | " if f.numerator == 0:\n",
831 | " return None\n",
832 | " \n",
833 | " # 찾은 분모가 실제 위수이면 그 값을 반환합니다.\n",
834 | " r = f.denominator\n",
835 | " if x**r % n != 1:\n",
836 | " return None\n",
837 | " return r"
838 | ]
839 | },
840 | {
841 | "cell_type": "markdown",
842 | "metadata": {},
843 | "source": [
844 | "다음 코드 영역은 위수 찾기 회로를 생성하기 실행한 뒤 고전적 후처리를 통해 위수를 계산하는\n",
845 | "예제를 나타냅니다. 이 알고리즘의 양자 요소는 확률적으로 성공함을 상기해봅시다.\n",
846 | " 만일 위수가 `None`이라면 몇번 더 코드영역을 재실행 해보세요."
847 | ]
848 | },
849 | {
850 | "cell_type": "code",
851 | "execution_count": 16,
852 | "metadata": {},
853 | "outputs": [
854 | {
855 | "name": "stdout",
856 | "output_type": "stream",
857 | "text": [
858 | "Finding the order of x = 5 modulo n = 6\n",
859 | "\n",
860 | "Raw measurements:\n",
861 | "exponent=1, 0, 0, 0, 0, 0, 0, 0, 0\n",
862 | "\n",
863 | "Integer in exponent register:\n",
864 | " exponent\n",
865 | "0 256\n",
866 | "\n",
867 | "Order r = 2\n",
868 | "x^r mod n = 5^2 mod 6 = 1\n"
869 | ]
870 | }
871 | ],
872 | "source": [
873 | "\"\"\"고전적 후처리 예제.\"\"\"\n",
874 | "# n과 x를 설정합니다.\n",
875 | "n = 6\n",
876 | "x = 5\n",
877 | "\n",
878 | "print(f\"Finding the order of x = {x} modulo n = {n}\\n\")\n",
879 | "measurement = cirq.sample(circuit, repetitions=1)\n",
880 | "print(\"Raw measurements:\")\n",
881 | "print(measurement)\n",
882 | "\n",
883 | "print(\"\\nInteger in exponent register:\")\n",
884 | "print(measurement.data)\n",
885 | "\n",
886 | "r = process_measurement(measurement, x, n)\n",
887 | "print(\"\\nOrder r =\", r)\n",
888 | "if r is not None:\n",
889 | " print(f\"x^r mod n = {x}^{r} mod {n} = {x**r % n}\")"
890 | ]
891 | },
892 | {
893 | "cell_type": "markdown",
894 | "metadata": {},
895 | "source": [
896 | "곱셈군 $\\mathbb{Z}_6$의 원소 $x = 5$의 위수가 $r = 2$임을 알 수 있습니다.\n",
897 | " 실제로, $5^2 \\text{ mod } 6 = 25 \\text{ mod } 6 = 1$로 확인 가능합니다."
898 | ]
899 | },
900 | {
901 | "cell_type": "markdown",
902 | "metadata": {},
903 | "source": [
904 | "## 양자 위수 측정기"
905 | ]
906 | },
907 | {
908 | "cell_type": "markdown",
909 | "metadata": {},
910 | "source": [
911 | "이제 우리가 지금까지 작성한 함수들을 사용하여 위수 찾기의 양자 버전을 이용한 효율적인 함수를 정의할 수 있습니다. \n",
912 | "아래의 양자 위수 측정기는 회로를 생성하고 실행한 뒤 측정 결과를 처리합니다."
913 | ]
914 | },
915 | {
916 | "cell_type": "code",
917 | "execution_count": 17,
918 | "metadata": {},
919 | "outputs": [],
920 | "source": [
921 | "def quantum_order_finder(x: int, n: int) -> Optional[int]:\n",
922 | " \"\"\"x**r mod n == 1인 최소의 양의 정수 r을 계산한다.\n",
923 | " \n",
924 | " Args:\n",
925 | " x: 위수가 계산될 정수. 항상 1보더 크며 법 n의 곱셈군에 속한다. 이때 x는 n과 서로소인\n",
926 | " 양의 정수들로 이루어져 있습니다.\n",
927 | " n: 위 곱셈군의 법\n",
928 | " \"\"\"\n",
929 | " # 정수 x가 법 n 곱셈군의 유효한 원소인지 확인합니다.\n",
930 | " if x < 2 or n <= x or math.gcd(x, n) > 1:\n",
931 | " raise ValueError(f'Invalid x={x} for modulus n={n}.')\n",
932 | "\n",
933 | " # 위수 찾기 회로를 생성합니다.\n",
934 | " circuit = make_order_finding_circuit(x, n)\n",
935 | " \n",
936 | " # 위수 찾기 회로에서 결과를 추출합니다.\n",
937 | " measurement = cirq.sample(circuit)\n",
938 | " \n",
939 | " # 측정결과를 처리한 후 반환합니다.\n",
940 | " return process_measurement(measurement, x, n)"
941 | ]
942 | },
943 | {
944 | "cell_type": "markdown",
945 | "metadata": {},
946 | "source": [
947 | "이제 우리가 구현한 위수 측정기의 양자 구현과 쇼어 알고리즘의 양자 요소를 완료합니다."
948 | ]
949 | },
950 | {
951 | "cell_type": "markdown",
952 | "metadata": {},
953 | "source": [
954 | "# 완성된 인수 분해 알고리즘"
955 | ]
956 | },
957 | {
958 | "cell_type": "markdown",
959 | "metadata": {},
960 | "source": [
961 | "양자 위수 측정기(또는 고전적 위수 측정기)를 사용해 쇼어의 알고리즘을 완성할 수 있습니다.\n",
962 | " 다음 코드 영역에서는 몇가지 전처리 단계를 추가합니다.\n",
963 | "\n",
964 | "(1) $n$이 짝수인지 확인하기\n",
965 | "\n",
966 | "(2) $n$이 소수인지 확인하기\n",
967 | "\n",
968 | "(3) $n$이 소수의 거듭제곱인지 확인하기\n",
969 | "\n",
970 | "위 세가지 모두 고전 컴퓨터에서 효율적으로 처리 가능합니다. 덧붙여 \n",
971 | " we add the last necessary post-processing step which uses the order \n",
972 | " 마지막으로 위수 $r$을 사용하여 $n$의 자명하지 않은 인수인 $p$를 계산하는 후처리 단계를 추가합니다. \n",
973 | " 이는 ($r$이 짝수라고 가정하면) $y = x^{r / 2} \\text{ mod } n$을 계산하여 얻어낼 수 있습니다.\n",
974 | " 그렇다면 $p = \\text{gcd}(y - 1, n)$입니다."
975 | ]
976 | },
977 | {
978 | "cell_type": "code",
979 | "execution_count": 18,
980 | "metadata": {},
981 | "outputs": [],
982 | "source": [
983 | "\"\"\" 인수분해의 시작부터 끝까지하는 함수.\"\"\"\n",
984 | "def find_factor_of_prime_power(n: int) -> Optional[int]:\n",
985 | " \"\"\"n이 소수 한개의 거듭제곱인 경우 자명하지 않은 n의 인수를 반환합니다.\n",
986 | " 그 외에는 None을 반환합니다.\"\"\"\n",
987 | " for k in range(2, math.floor(math.log2(n)) + 1):\n",
988 | " c = math.pow(n, 1 / k)\n",
989 | " c1 = math.floor(c)\n",
990 | " if c1**k == n:\n",
991 | " return c1\n",
992 | " c2 = math.ceil(c)\n",
993 | " if c2**k == n:\n",
994 | " return c2\n",
995 | " return None\n",
996 | "\n",
997 | "\n",
998 | "def find_factor(\n",
999 | " n: int,\n",
1000 | " order_finder: Callable[[int, int], Optional[int]] = quantum_order_finder,\n",
1001 | " max_attempts: int = 30\n",
1002 | ") -> Optional[int]:\n",
1003 | " \"\"\"합성수 n의 자명하지 않은 인수를 반환합니다.\n",
1004 | "\n",
1005 | " Args:\n",
1006 | " n: 인수분해할 정수.\n",
1007 | " order_finder: 법 n 곱셈군에 속하는 원소의 위수를 찾는 함수.\n",
1008 | " max_attempts: 함수 order_finder가 호출되는 횟수의 상한값이자 시도해볼 무작위수\n",
1009 | " x의 개수.\n",
1010 | "\n",
1011 | " Returns:\n",
1012 | " n의 자명하지 않은 인수 혹은 그러한 인수가 없을 때 None.\n",
1013 | " n의 인수 k는 1이거나 n일때 자명합니다.\n",
1014 | " \"\"\"\n",
1015 | " # 만일 n이 소수이면 자명하지 않은 인수는 없습니다.\n",
1016 | " if sympy.isprime(n):\n",
1017 | " print(\"n is prime!\")\n",
1018 | " return None\n",
1019 | " \n",
1020 | " # 짝수이면 자명하지 않은 인수는 2입니다.\n",
1021 | " if n % 2 == 0:\n",
1022 | " return 2\n",
1023 | " \n",
1024 | " # n이 소수의 거듭제곱이라면, 효율적으로 자명하지 않은 인수를 구할 수 있습니다.\n",
1025 | " c = find_factor_of_prime_power(n)\n",
1026 | " if c is not None:\n",
1027 | " return c\n",
1028 | " \n",
1029 | " for _ in range(max_attempts):\n",
1030 | " # 무작위로 2에서 n - 1 사이의 값을 고릅니다.\n",
1031 | " x = random.randint(2, n - 1)\n",
1032 | " \n",
1033 | " # x와 n이 서로소 인지 확인합니다.\n",
1034 | " c = math.gcd(x, n)\n",
1035 | " \n",
1036 | " # x와 n이 서로소가 아니라면, 운이 좋게도 한 번에 비자명한 인자를 구해냈습니다.\n",
1037 | " if 1 < c < n:\n",
1038 | " return c\n",
1039 | " \n",
1040 | " # 법 n으로 하는 x의 위수 r을 위수 측정기로 계산합니다.\n",
1041 | " r = order_finder(x, n)\n",
1042 | " \n",
1043 | " # 위수 측정기가 실패하면 재시도합니다.\n",
1044 | " if r is None:\n",
1045 | " continue\n",
1046 | " \n",
1047 | " # 위수가 홀수이면 재시도합니다.\n",
1048 | " if r % 2 != 0:\n",
1049 | " continue\n",
1050 | " \n",
1051 | " # 비자명한 인자를 계산합니다.\n",
1052 | " y = x**(r // 2) % n\n",
1053 | " assert 1 < y < n\n",
1054 | " c = math.gcd(y - 1, n)\n",
1055 | " if 1 < c < n:\n",
1056 | " return c\n",
1057 | "\n",
1058 | " print(f\"Failed to find a non-trivial factor in {max_attempts} attempts.\")\n",
1059 | " return None"
1060 | ]
1061 | },
1062 | {
1063 | "cell_type": "markdown",
1064 | "metadata": {},
1065 | "source": [
1066 | "함수 `find_factor`는 `quantum_order_finder`를 기본으로 사용하며 쇼어의 알고리즘을 사용하게 됩니다. \n",
1067 | "이전에 언급했듯이, 고전적으로 이 회로를 시뮬레이션하는데에는 매우 큰 메모리가 필요하기 때문에\n",
1068 | "$n \\ge 15$인 정수에 대해서는 쇼어의 알고리즘을 실행할 수 없습니다. 이때는 대체제로 고전적인 위수\n",
1069 | "찾기 알고리즘을 사용할 수 있습니다."
1070 | ]
1071 | },
1072 | {
1073 | "cell_type": "code",
1074 | "execution_count": 19,
1075 | "metadata": {},
1076 | "outputs": [
1077 | {
1078 | "name": "stdout",
1079 | "output_type": "stream",
1080 | "text": [
1081 | "Factoring n = pq = 184573\n",
1082 | "p = 487\n",
1083 | "q = 379\n"
1084 | ]
1085 | }
1086 | ],
1087 | "source": [
1088 | "\"\"\"쇼어 알고리즘(위수 측정기)을 통해 인수분해하기 예제.\"\"\"\n",
1089 | "# 인수분해할 수를 정의합니다.\n",
1090 | "n = 184573\n",
1091 | "\n",
1092 | "# 인수를 찾아봅니다.\n",
1093 | "p = find_factor(n, order_finder=classical_order_finder)\n",
1094 | "q = n // p\n",
1095 | "\n",
1096 | "print(\"Factoring n = pq =\", n)\n",
1097 | "print(\"p =\", p)\n",
1098 | "print(\"q =\", q)"
1099 | ]
1100 | }
1101 | ],
1102 | "metadata": {
1103 | "kernelspec": {
1104 | "display_name": "Python 3",
1105 | "language": "python",
1106 | "name": "python3"
1107 | },
1108 | "language_info": {
1109 | "codemirror_mode": {
1110 | "name": "ipython",
1111 | "version": 3
1112 | },
1113 | "file_extension": ".py",
1114 | "mimetype": "text/x-python",
1115 | "name": "python",
1116 | "nbconvert_exporter": "python",
1117 | "pygments_lexer": "ipython3",
1118 | "version": "3.6.8"
1119 | },
1120 | "pycharm": {
1121 | "stem_cell": {
1122 | "cell_type": "raw",
1123 | "source": [],
1124 | "metadata": {
1125 | "collapsed": false
1126 | }
1127 | }
1128 | }
1129 | },
1130 | "nbformat": 4,
1131 | "nbformat_minor": 2
1132 | }
--------------------------------------------------------------------------------
/korean/chapter08/problems/chapter08.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter08/problems/chapter08.pdf
--------------------------------------------------------------------------------
/korean/chapter09/cirq/hhl.py:
--------------------------------------------------------------------------------
1 | """
2 | 선형 연립방정식을 풀기 위한 해로우(Harrow), 하시딤(Hassidim), 로이드(Lloyd)의 HHL 알고리즘
3 |
4 | HHL 알고리즘은 선형 연립 방정식을 푸는 알고리즘으로, 특히 Ax = b인 등식에서 행렬 A가 에르미트
5 | 행렬이고 벡터 b가 주어졌을 때 벡터 x를 찾는 문제를 위한 알고리즘입니다. 양자 시스템에서 이 문제를
6 | 해결할 때, 반드시 벡터 b는 크기가 1인 단위벡터여야 합니다. 그럼 수식은 다음과 같이 됩니다:
7 |
8 | |x> = A**-1 |b> / || A**-1 |b> ||
9 |
10 | 이 알고리즘은 다음 3개의 큐비트 집합을 사용합니다. 1. 단일 보조 큐비트, 2. (행렬 A의 고유값을
11 | 저장할) 레지스터, 그리고 3. (|b>와 |x>를 저장할) 메모리 큐비트들입니다.
12 | 이제 알고리즘은 다음 순서대로 진행됩니다.:
13 | 1) 행렬 A의 고유값을 추출하기 위한 양자 위상 추정
14 | 2) 보조 큐비트의 제어 회전
15 | 3) 역 양자 위상 추정으로 가역계산 수행.
16 |
17 | 알고리즘의 자세한 설명을 위해서는 아래 참조에 있는 논문들을 참고해주십시오.
18 | 우리는 HHL 논문에서 정의된 변수들을 이용해 알고리즘을 설명할 것입니다.
19 |
20 | 이 예제는 임의의 2x2 에르미트 행렬의 HHL 알고리즘을 구현합니다. 알고리즘은 |x> 상태의 파울리
21 | 측정의 기대값을 출력합니다. 결과의 정확도는 다음 요인들에 의해 결정됨을 참고해주십시오:
22 | * 레지스터의 크기
23 | * 매개변수 C와 t의 선택.
24 |
25 | 결과가 오류없이 완벽히 구해지는 조건들은 다음과 같습니다.
26 | * 만일 행렬의 각 고유값이 다음의 형태
27 |
28 | 2π/t * k/N,
29 |
30 | 0≤k>= 1
181 |
182 | # 제어 보조 회전을 구성합니다.
183 | kGate = cirq.ControlledGate(kGate)
184 |
185 | yield kGate(*qubits)
186 |
187 | def _ancilla_rotation(self, k):
188 | if k == 0:
189 | k = self.N
190 | theta = 2*math.asin(self.C * self.N * self.t / (2*math.pi * k))
191 | return cirq.Ry(theta)
192 |
193 |
194 | def hhl_circuit(A, C, t, register_size, *input_prep_gates):
195 | """
196 | HHL 회로를 구성합니다.
197 |
198 | Args:
199 | A: 에르미트 행렬.
200 | C: 알고리즘 매개변수, 위 설명 참고.
201 | t: 알고리즘 매개변수, 위 설명 참고.
202 | register_size: 고유값 레지스터의 크기.
203 | memory_basis: 'x', 'y', 'z' 중 하나로 메모리 큐비트를 측정할 기저.
204 | input_prep_gates: |0> 상태에 가할 게이트들의 리스트로 원하는 입력 상태 |b>에 해당.
205 |
206 | Returns:
207 | HHL 회로를 반환. 보조 큐비트 측정은 키값 'a'를, 메모리 큐비트의 측정은 키값 'm'을
208 | 갖습니다. 회로에는 두 가지 매개변수가 있습니다. `exponent`와 `phase_exponent`는
209 | 메모리에 대한 측정이 이루어지기 전에 `cirq.PhasedXPowGate`로 가해질 가능한 회전에
210 | 대응됩니다.
211 | """
212 |
213 | ancilla = cirq.LineQubit(0)
214 | # 행렬의 고유값을 저장하기 위한 레지스터.
215 | register = [cirq.LineQubit(i + 1) for i in range(register_size)]
216 | # 입력과 출력 벡터를 저장하기 위한 메모리 큐비트.
217 | memory = cirq.LineQubit(register_size + 1)
218 |
219 | c = cirq.Circuit()
220 | hs = HamiltonianSimulation(A, t)
221 | pe = PhaseEstimation(register_size+1, hs)
222 | c.append([gate(memory) for gate in input_prep_gates])
223 | c.append([
224 | pe(*(register + [memory])),
225 | EigenRotation(register_size + 1, C, t)(*(register + [ancilla])),
226 | pe(*(register + [memory]))**-1,
227 | cirq.measure(ancilla, key='a')
228 | ])
229 |
230 | c.append([
231 | cirq.PhasedXPowGate(
232 | exponent=sympy.Symbol('exponent'),
233 | phase_exponent=sympy.Symbol('phase_exponent'))(memory),
234 | cirq.measure(memory, key='m')
235 | ])
236 |
237 | return c
238 |
239 |
240 | def simulate(circuit):
241 | simulator = cirq.Simulator()
242 |
243 | # 메모리 큐비트의 X, Y, Z 기저를 각각을 측정하기 위한 회전 게이트용 매개변수들.
244 | params = [{
245 | 'exponent': 0.5,
246 | 'phase_exponent': -0.5
247 | }, {
248 | 'exponent': 0.5,
249 | 'phase_exponent': 0
250 | }, {
251 | 'exponent': 0,
252 | 'phase_exponent': 0
253 | }]
254 |
255 | results = simulator.run_sweep(circuit, params, repetitions=5000)
256 |
257 | for label, result in zip(('X', 'Y', 'Z'), list(results)):
258 | # 오직 보조 큐비트가 1인 경우만 선택합니다.
259 | # TODO 진폭 증폭 알고리즘을 사용하여 최적화히기
260 | expectation = 1 - 2 * np.mean(
261 | result.measurements['m'][result.measurements['a'] == 1])
262 | print('{} = {}'.format(label, expectation))
263 |
264 |
265 | def main():
266 | """
267 | HHL을 행렬 입력과 결과 큐비트 상태인 |x>의 파울리 측정 출력을 시뮬레이션하기.
268 | 기대되는 해 |x>로 부터 기대되는 관측량을 계산합니다.
269 | """
270 |
271 | # 고유값분해 결과:
272 | # >>> import numpy as np
273 | # >>> x, y = np.linalg.eig(A)
274 | # >>> [z for z in zip(list(x.astype(np.float32)), list(y))]
275 | # [(4.537, array([ 0.9715551 +0.j , -0.05783371-0.22964251j])),
276 | # (0.349, array([0.05783391-0.22964302j, 0.97155524+0.j ]))]
277 | # |b> = (0.64510-0.47848j, 0.35490-0.47848j)
278 | # |x> = (-0.0662724-0.214548j, 0.784392-0.578192j)
279 | A = np.array([[4.30213466-6.01593490e-08j,
280 | 0.23531802+9.34386156e-01j],
281 | [0.23531882-9.34388383e-01j,
282 | 0.58386534+6.01593489e-08j]])
283 | t = 0.358166*math.pi
284 | register_size = 4
285 | input_prep_gates = [cirq.Rx(1.276359), cirq.Rz(1.276359)]
286 | expected = (0.144130, 0.413217, -0.899154)
287 |
288 | # C를 회로에서 표현가능한 최소의 고유값에 맞춥니다.
289 | C = 2*math.pi / (2**register_size * t)
290 |
291 | # 회로를 시뮬레이션합니다.
292 | print("Expected observable outputs:")
293 | print("X =", expected[0])
294 | print("Y =", expected[1])
295 | print("Z =", expected[2])
296 | print("Actual: ")
297 | simulate(hhl_circuit(A, C, t, register_size, *input_prep_gates))
298 |
299 |
300 | if __name__ == '__main__':
301 | main()
302 |
--------------------------------------------------------------------------------
/korean/chapter09/cirq/qaoa.py:
--------------------------------------------------------------------------------
1 | """Example using QAOA to solve MaxCut from Chapter 9.3.
2 |
3 | Requirements:
4 | cirq==0.7.0
5 | """
6 |
7 | # Imports
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | import cirq
12 |
13 |
14 | # Function to implement a ZZ gate on qubits a, b with angle gamma
15 | def ZZ(a, b, gamma):
16 | """Returns a circuit implementing exp(-i \pi \gamma Z_i Z_j)."""
17 | # Get a circuit
18 | circuit = cirq.Circuit()
19 |
20 | # Gives the fourth diagonal component
21 | circuit.append(cirq.CZ(a, b) ** gamma)
22 |
23 | # Gives the third diagonal component
24 | circuit.append([cirq.X(b), cirq.CZ(a, b) ** (-1 * gamma), cirq.X(b)])
25 |
26 | # Gives the second diagonal component
27 | circuit.append([cirq.X(a), cirq.CZ(a, b) ** -gamma, cirq.X(a)])
28 |
29 | # Gives the first diagonal component
30 | circuit.append([cirq.X(a), cirq.X(b), cirq.CZ(a, b) ** gamma,
31 | cirq.X(a), cirq.X(b)])
32 |
33 | return circuit
34 |
35 |
36 | # 26.s.one
37 | # Make sure the circuit gives the correct matrix
38 | qreg = cirq.LineQubit.range(2)
39 | zzcirc = ZZ(qreg[0], qreg[1], 0.5)
40 | print("Circuit for ZZ gate:", zzcirc, sep="\n")
41 | print("\nUnitary of circuit:", zzcirc.unitary().round(2), sep="\n")
42 |
43 | ncols = 2
44 | nrows = 2
45 | qreg = [[cirq.GridQubit(i,j) for j in range(ncols)] for i in range(nrows)]
46 |
47 | # Function to implement the cost Hamiltonian
48 | def cost_circuit(gamma):
49 | """Returns a circuit for the cost Hamiltonian."""
50 | circ = cirq.Circuit()
51 | for i in range(nrows):
52 | for j in range(ncols):
53 | if i < nrows - 1:
54 | circ += ZZ(qreg[i][j], qreg[i + 1][j], gamma)
55 | if j < ncols - 1:
56 | circ += ZZ(qreg[i][j], qreg[i][j + 1], gamma)
57 |
58 | return circ
59 |
60 | # Function to implement the mixer Hamiltonian
61 | def mixer(beta):
62 | """Generator for U(H_B, beta) layer (mixing layer)"""
63 | for row in qreg:
64 | for qubit in row:
65 | yield cirq.X(qubit)**beta
66 |
67 |
68 | # Function to build the QAOA circuit
69 | def qaoa(gammas, betas):
70 | """Returns a QAOA circuit."""
71 | circ = cirq.Circuit()
72 | circ.append(cirq.H.on_each(*[q for row in qreg for q in row]))
73 |
74 | for i in range(len(gammas)):
75 | circ += cost_circuit(gammas[i])
76 | circ.append(mixer(betas[i]))
77 |
78 | return circ
79 |
80 | def simulate(circ):
81 | """Returns the wavefunction after applying the circuit."""
82 | sim = cirq.Simulator()
83 | return sim.simulate(circ).final_state
84 |
85 |
86 | def energy_from_wavefunction(wf):
87 | """Computes the energy-per-site of the Ising Model from the wavefunction."""
88 | # Z is a (n_sites x 2**n_sites) array. Each row consists of the
89 | # 2**n_sites non-zero entries in the operator that is the Pauli-Z matrix on
90 | # one of the qubits times the identites on the other qubits. The (i*n_cols + j)th
91 | # row corresponds to qubit (i,j).
92 | nsites = nrows * ncols
93 | Z = np.array([(-1) ** (np.arange(2 ** nsites) >> i)
94 | for i in range(nsites - 1, -1, -1)])
95 |
96 | # Create the operator corresponding to the interaction energy summed over all
97 | # nearest-neighbor pairs of qubits
98 | ZZ_filter = np.zeros_like(wf, dtype=float)
99 | for i in range(nrows):
100 | for j in range(ncols):
101 | if i < nrows - 1:
102 | ZZ_filter += Z[i * ncols + j] * Z[(i + 1) * ncols + j]
103 | if j < ncols - 1:
104 | ZZ_filter += Z[i * ncols + j] * Z[i * ncols + (j + 1)]
105 |
106 | # Expectation value of the energy divided by the number of sites
107 | return -np.sum(np.abs(wf) ** 2 * ZZ_filter) / nsites
108 |
109 | def cost(gammas, betas):
110 | """Returns the cost function of the problem."""
111 | wavefunction = simulate(qaoa(gammas, betas))
112 | return energy_from_wavefunction(wavefunction)
113 |
114 |
115 | def grid_search(gammavals, betavals):
116 | """Does a grid search over all parameter values."""
117 | costmat = np.zeros((len(gammavals), len(betavals)))
118 |
119 | for (i, gamma) in enumerate(gammavals):
120 | for (j, beta) in enumerate(betavals):
121 | costmat[i, j] = cost([gamma], [beta])
122 |
123 | return costmat
124 |
125 | # Get a range of parameters
126 | gammavals = np.linspace(0, 1.0, 50)
127 | betavals = np.linspace(0, np.pi, 75)
128 |
129 | # Compute the cost at all parameter values using a grid search
130 | costmat = grid_search(gammavals, betavals)
131 |
132 | # Plot the cost landscape
133 | plt.imshow(costmat, extent=(0, 1, 0, np.pi), origin="lower", aspect="auto")
134 | plt.colorbar()
135 | plt.show()
136 |
137 | # Coordinates from the grid of cost values
138 | gamma_coord, beta_coord = np.where(costmat == np.min(costmat))
139 |
140 | # Values from the coordinates
141 | gamma_opt = gammavals[gamma_coord[0]]
142 | beta_opt = betavals[beta_coord[0]]
143 |
144 |
145 | def get_bit_strings(gammas, betas, nreps=10000):
146 | """Measures the QAOA circuit in the computational basis to get bitstrings."""
147 | circ = qaoa(gammas, betas)
148 | circ.append(
149 | cirq.measure(*[qubit for row in qreg for qubit in row], key='m'))
150 |
151 | # Simulate the circuit
152 | sim = cirq.Simulator()
153 | res = sim.run(circ, repetitions=nreps)
154 |
155 | return res
156 |
157 | # Sample to get bits and convert to a histogram
158 | bits = get_bit_strings([gamma_opt], [beta_opt])
159 | hist = bits.histogram(key="m")
160 |
161 | # Get the most common bits
162 | top = hist.most_common(2)
163 |
164 | # Print out the two most common bitstrings measured
165 | print("\nMost common bitstring:")
166 | print(format(top[0][0], "#010b"))
167 |
168 | print("\nSecond most common bitstring:")
169 | print(bin(top[1][0]))
170 |
171 |
--------------------------------------------------------------------------------
/korean/chapter09/cirq/qchem.py:
--------------------------------------------------------------------------------
1 | """오픈페르미온(OpenFermion)과 써큐를 사용한 양자 화학 계산 예제.
2 |
3 | Requirements:
4 | cirq==0.7.0
5 | openfermion==0.11.0
6 | openfermioncirq==0.4.0
7 | """
8 |
9 | # 가져오기
10 | import numpy
11 | import scipy
12 | import sympy
13 |
14 | import cirq
15 | import openfermion
16 | import openfermioncirq
17 |
18 | # 큐비트 개수와 시뮬레이션 시간, 그리고 실험 재현을 위한 난수 씨앗값 설정.
19 | n_qubits = 3
20 | simulation_time = 1.0
21 | random_seed = 8317
22 |
23 | # 무작위 1-체 연산자 생성.
24 | T = openfermion.random_hermitian_matrix(n_qubits, seed=random_seed)
25 | print("Hamiltonian:", T, sep="\n")
26 |
27 | # 오픈페르미온의 "FermionOperator" 형태의 해밀토니안을 계산하기.
28 | H = openfermion.FermionOperator()
29 | for p in range(n_qubits):
30 | for q in range(n_qubits):
31 | term = ((p, 1), (q, 0))
32 | H += openfermion.FermionOperator(term, T[p, q])
33 | print("\nFermion operator:")
34 | print(H)
35 |
36 | # Diagonalize T를 대각화 하고 ("u"로 알려진) 기저 변환 행렬 구하기.
37 | eigenvalues, eigenvectors = numpy.linalg.eigh(T)
38 | basis_transformation_matrix = eigenvectors.transpose()
39 |
40 | # 큐비트 레지스터 초기화하기.
41 | qubits = cirq.LineQubit.range(n_qubits)
42 |
43 | # 고유기저로 회전하기.
44 | inverse_basis_rotation = cirq.inverse(
45 | openfermioncirq.bogoliubov_transform(qubits, basis_transformation_matrix)
46 | )
47 | circuit = cirq.Circuit.from_ops(inverse_basis_rotation)
48 |
49 | # 회로에 대각 위상 회전을 추가하기.
50 | for k, eigenvalue in enumerate(eigenvalues):
51 | phase = -eigenvalue * simulation_time
52 | circuit.append(cirq.Rz(rads=phase).on(qubits[k]))
53 |
54 | # 마지막으로, 다시 계산 기저로 돌아오기.
55 | basis_rotation = openfermioncirq.bogoliubov_transform(
56 | qubits, basis_transformation_matrix
57 | )
58 | circuit.append(basis_rotation)
59 |
60 | # 무작위로 initial_state를 초기화하기.
61 | initial_state = openfermion.haar_random_vector(
62 | 2 ** n_qubits, random_seed).astype(numpy.complex64)
63 |
64 | # 회로의 정확한 출력을 수치적으로 계산하기.
65 | hamiltonian_sparse = openfermion.get_sparse_operator(H)
66 | exact_state = scipy.sparse.linalg.expm_multiply(
67 | -1j * simulation_time * hamiltonian_sparse, initial_state
68 | )
69 |
70 | # Cirq의 시뮬레이터를 사용하여 회로를 출력상태 계산하기.
71 | simulator = cirq.Simulator()
72 | result = simulator.simulate(circuit, qubit_order=qubits,
73 | initial_state=initial_state)
74 | simulated_state = result.final_state
75 |
76 | # 마지막 충실도(fidelity) 를 출력하기
77 | fidelity = abs(numpy.dot(simulated_state, numpy.conjugate(exact_state)))**2
78 | print("\nfidelity =", round(fidelity, 4))
79 |
--------------------------------------------------------------------------------
/korean/chapter09/cirq/qnn.py:
--------------------------------------------------------------------------------
1 | """양자 신경 회로망 써큐 예제."""
2 |
3 | # 가져오기
4 | import cirq
5 | import matplotlib.pyplot as plt
6 | import numpy as np
7 | import sympy
8 |
9 | # ZX 게이트를 써큐에서 구현하기 위한 클래스
10 | class ZXGate(cirq.ops.eigen_gate.EigenGate,
11 | cirq.ops.gate_features.TwoQubitGate):
12 | """weight를 변수로 갖는 ZXGate."""
13 |
14 | def __init__(self, weight=1):
15 | """ZX 게이트를 초기화하기.
16 |
17 | Args:
18 | weight: 주기가 2인 회전각.
19 | """
20 | self.weight = weight
21 | super().__init__(exponent=weight) # 1이 아닌 weight를 자동으로 처리.
22 |
23 | def _eigen_components(self):
24 | return [
25 | (1, np.array([[0.5, 0.5, 0, 0],
26 | [ 0.5, 0.5, 0, 0],
27 | [0, 0, 0.5, -0.5],
28 | [0, 0, -0.5, 0.5]])),
29 | (-1, np.array([[0.5, -0.5, 0, 0],
30 | [ -0.5, 0.5, 0, 0],
31 | [0, 0, 0.5, 0.5],
32 | [0, 0, 0.5, 0.5]]))
33 | ]
34 |
35 | # 이 함수는 weight가 Symbol이 될 수 있게 합니다. 매개변수화 할때 유용한 함수입니다.
36 | def _resolve_parameters_(self, param_resolver):
37 | return ZXGate(weight=param_resolver.value_of(self.weight))
38 |
39 | # 게이트가 ASCII 회로도에서 어떻게 보여야 할까요?
40 | def _circuit_diagram_info_(self, args):
41 | return cirq.protocols.CircuitDiagramInfo(
42 | wire_symbols=('Z', 'X'),
43 | exponent=self.weight)
44 |
45 | # 데이터 큐비트의 총 개수
46 | INPUT_SIZE = 9
47 |
48 | data_qubits = cirq.LineQubit.range(INPUT_SIZE)
49 | readout = cirq.NamedQubit('r')
50 |
51 | # 회로의 매개변수를 초기화합니다.
52 | params = {'w': 0}
53 |
54 | def ZX_layer():
55 | """각각의 데이터 큐비트와 출력(readout) 큐비트 사이에 ZX게이트를 추가합니다.
56 | 모든 게이트가 한 개의 weight에 대한 동일한 sympy.Symbol객체를 받습니다."""
57 | for qubit in data_qubits:
58 | yield ZXGate(sympy.Symbol('w')).on(qubit, readout)
59 |
60 |
61 | qnn = cirq.Circuit()
62 | qnn.append(ZX_layer())
63 | qnn.append([cirq.S(readout)**-1, cirq.H(readout)]) # Basis transformation
64 |
65 | def readout_expectation(state):
66 | """양자 상태를 의미하는 0과 1으로 이루어진 배열을 입력받고 출력 큐비트에서 측정한 Z의 기대값을
67 | 반환합니다. 써큐의 Simulator를 사용하여 파동함수(wavefunction)를 정확하게 계산합니다."""
68 |
69 | # 상태를 표현하는 편리한 방법은 정수로 나타내는 것입니다.
70 | state_num = int(np.sum(state*2**np.arange(len(state))))
71 |
72 | resolver = cirq.ParamResolver(params)
73 | simulator = cirq.Simulator()
74 |
75 | # 큐비트 순서를 명시하여 어떠한 큐비트가 출력 큐비트 readout인지 알 수 있습니다.
76 | result = simulator.simulate(qnn, resolver, qubit_order=[readout]+data_qubits,
77 | initial_state=state_num)
78 | wf = result.final_state
79 |
80 | # 큐비트의 순서를 정했기 때문에 readout 큐비트의 Z 값은 최상위비트입니다.
81 | Z_readout = np.append(np.ones(2**INPUT_SIZE), -np.ones(2**INPUT_SIZE))
82 |
83 | # np.real함수를 사용해 허수부를 날려줍니다.
84 | return np.real(np.sum(wf*wf.conjugate()*Z_readout))
85 |
86 | def loss(states, labels):
87 | loss=0
88 | for state, label in zip(states,labels):
89 | loss += 1 - label*readout_expectation(state)
90 | return loss/(2*len(states))
91 |
92 | def classification_error(states, labels):
93 | error=0
94 | for state,label in zip(states,labels):
95 | error += 1 - label*np.sign(readout_expectation(state))
96 | return error/(2*len(states))
97 |
98 | def make_batch():
99 | """레이블의 집합을 생성하고 입력을 생성하는데 이 레이블들을 사용합니다. label = -1은 상태에서
100 | 0의 개수가 더 많다는 것을 의미하고, label = +1은 1의 개수가 더 많다는 것을 의미힙니다.
101 | """
102 | np.random.seed(0) # 데모의 일관성을 위해 씨앗값을 상수로 둡니다.
103 | labels = (-1)**np.random.choice(2, size=100) # 더 작은 크기가 계산을 빠르게합니다.
104 | states = []
105 | for label in labels:
106 | states.append(np.random.choice(2, size=INPUT_SIZE, p=[0.5-label*0.2,0.5+label*0.2]))
107 | return states, labels
108 |
109 | states, labels = make_batch()
110 |
111 | linspace = np.linspace(start=-1, stop=1, num=80)
112 | train_losses = []
113 | error_rates = []
114 | for p in linspace:
115 | params = {'w': p}
116 | train_losses.append(loss(states, labels))
117 | error_rates.append(classification_error(states, labels))
118 | plt.plot(linspace, train_losses)
119 | plt.xlabel('Weight')
120 | plt.ylabel('Loss')
121 | plt.title('Loss as a Function of Weight')
122 | plt.show()
123 |
--------------------------------------------------------------------------------
/korean/chapter09/cirq/qpe.py:
--------------------------------------------------------------------------------
1 | """써큐에서 양자 위상 추정(QPE)하기."""
2 |
3 | # 가져오기
4 | import numpy as np
5 | from scipy.stats import unitary_group
6 |
7 | import cirq
8 |
9 | # =============================================================================
10 | # 보조함수
11 | # =============================================================================
12 |
13 | def binary_decimal(string):
14 | """0babc...의 수치값을 반환합니다. 이때 a, b, c, ... 는 각각 0 또는 1입니다.
15 | (역자주: 0x1F가 16진수 1F를 의미하듯, 0babc도 2진수 abc를 의미합니다.)
16 |
17 | Examples:
18 | 0b10 --> 0.5
19 | 0b01 --> 0.25
20 | """
21 | val = 0.0
22 | for (ind, bit) in enumerate(string[2:]):
23 | if int(bit) == 1:
24 | val += 2**(-1 -ind)
25 | return val
26 |
27 | # =============================================================================
28 | # QPE 입력
29 | # =============================================================================
30 |
31 | # 결과 재현을 위한 씨앗값 설정.
32 | np.random.seed(123)
33 |
34 | # 두 개 큐비트들에 대한 무작위 유니타리 행렬을 생성.
35 | m = 2
36 | dim = 2**m
37 | unitary = unitary_group.rvs(dim)
38 |
39 | unitary = np.identity(4)
40 |
41 | xmat = np.array([[0, 1], [1, 0]])
42 | zmat = np.array([[1, 0], [0, -1]])
43 | unitary = np.kron(xmat, zmat)
44 |
45 | # 콘솔 화면에 출력하기
46 | print("Unitary:")
47 | print(unitary)
48 |
49 | # 행렬을 고전적으로 대각화하기.
50 | evals, evecs = np.linalg.eig(unitary)
51 |
52 | # =============================================================================
53 | # QPE를 위한 회로 만들기.
54 | # =============================================================================
55 |
56 | # readout/answer 레지스터에 들어갈 큐비트 개수 설정하기 (정밀도는 비트 개수에 비례합니다.)
57 | n = 8
58 |
59 | # 출력 레지스터
60 | regA = cirq.LineQubit.range(n)
61 |
62 | # 고유상태를 저장하기위한 레지스터.
63 | regB = cirq.LineQubit.range(n, n + m)
64 |
65 | # 회로 얻기
66 | circ = cirq.Circuit()
67 |
68 | # 모든 출력 레지스터 큐비트에 아다마르 연산자를 가하기.
69 | circ.append(cirq.H.on_each(regA))
70 |
71 | # 두번쨰 레지스터의 모든 큐비트에 아다마르 연산자 가하기.
72 | #circ.append(cirq.H.on_each(regB))
73 |
74 | # 입력 유니타리 행렬로 써큐 게이트 만들기
75 | ugate = cirq.ops.matrix_gates.TwoQubitMatrixGate(unitary)
76 |
77 | # 위 유니타리 게이트의 제어 버전 만들기
78 | cugate = cirq.ops.ControlledGate(ugate)
79 |
80 | # 제어-U^{2^k} 연산들을 만들기.
81 | for k in range(n):
82 | circ.append(cugate(regA[k], *regB)**(2**k))
83 |
84 | # 역 QFT 수행.
85 | for k in range(n - 1):
86 | circ.append(cirq.H.on(regA[k]))
87 | targ = k + 1
88 | for j in range(targ):
89 | exp = -2**(j - targ)
90 | rot = cirq.Rz(exp)
91 | crot = cirq.ControlledGate(rot)
92 | circ.append(crot(regA[j], regA[targ]))
93 | circ.append(cirq.H.on(regA[n - 1]))
94 |
95 | """
96 | # 이것이 바로 QFT입니다!
97 | for k in reversed(range(n)):
98 | circ.append(cirq.H.on(regA[k]))
99 | for j in reversed(range(k)):
100 | exp = 2**(j - k)
101 | rot = cirq.Rz(exp)
102 | crot = cirq.ControlledGate(rot)
103 | circ.append(crot(regA[j], regA[k]))
104 | """
105 |
106 | # 출력 레지스터에서 모든 큐비트를 측정하기.
107 | circ.append(cirq.measure(*regA, key="z"))
108 |
109 | # 회로를 출력합니다.
110 | #print("Circuit:")
111 | #print(circ[5:])
112 |
113 | # =============================================================================
114 | # QPE 회로 실행하기
115 | # =============================================================================
116 |
117 | sim = cirq.Simulator()
118 |
119 | res = sim.run(circ, repetitions=1000)
120 |
121 | hist = res.histogram(key="z")
122 |
123 | top = hist.most_common(2)
124 |
125 | estimated = [np.exp(2j * np.pi * binary_decimal(bin(x[0]))) for x in top]
126 |
127 | print("\nEigenvalues from QPE:")
128 | print(sorted(estimated, key=lambda x: abs(x)**2))
129 |
130 | print("\nActual eigenvalues:")
131 | print(sorted(evals, key=lambda x: abs(x)**2))
132 |
--------------------------------------------------------------------------------
/korean/chapter09/cirq/random-bit.py:
--------------------------------------------------------------------------------
1 | """써큐에서 비트 난수 발생하기."""
2 |
3 | # 가져오기
4 | import cirq
5 |
6 | # 출력을 위한 보조함수.
7 | def bitstring(bits):
8 | return ''.join('1' if e else '0' for e in bits)
9 |
10 | # 큐비트와 양자회로 얻기
11 | qbit = cirq.LineQubit(0)
12 | circ = cirq.Circuit()
13 |
14 | # 아다마르 연산자와 출력 연산을 회로에 추가하기
15 | circ.append([cirq.H(qbit), cirq.measure(qbit, key="z")])
16 |
17 | # 회로 시뮬레이션하기
18 | sim = cirq.Simulator()
19 | res = sim.run(circ, repetitions=10)
20 |
21 | # 결과 출력하기
22 | print("Bitstring =", bitstring(res.measurements["z"]))
23 |
--------------------------------------------------------------------------------
/korean/chapter09/problems/chapter09.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter09/problems/chapter09.pdf
--------------------------------------------------------------------------------
/korean/chapter09/pyquil/qaoa.py:
--------------------------------------------------------------------------------
1 | """파이퀼(pyQuil)에서 QAOA하기 예제"""
2 |
3 |
4 | ##########################################################
5 | # Copyright 2016-2018 Rigetti Computing
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ##########################################################
19 |
20 | """
21 | 이 예제는 QIP 2018학회에서 Rigetti사의 라이브 프로그래밍 세션에서 실제 선보였던 프로그램입니다.
22 | QAOA의 더 복잡한 구현을 위해서는 그로브 예제와 문서를 찾아주십시오.
23 | http://grove-docs.readthedocs.io/en/latest/qaoa.html
24 | """
25 |
26 | from pyquil import get_qc
27 | from pyquil.quil import Program
28 | from pyquil.gates import H
29 | from pyquil.paulis import sI, sX, sZ, exponentiate_commuting_pauli_sum
30 |
31 | # 4-노드 배열 그래프를 생성합니다 : 0-1-2-3.
32 | graph = [(0, 1), (1, 2), (2, 3)]
33 | # 노드들은 [0, 1, 2, 3]입니다.
34 | nodes = range(4)
35 |
36 | # 초기 상태 프로그램입니다. 모든 큐비트에 아다마르를 가해 모든 비트열의 중첩을 구합니다.
37 | init_state_prog = Program([H(i) for i in nodes])
38 |
39 | # 비용 해밀토니안은 모든 큐비트 쌍 (i, j)에서 0.5 * (1 - \sigma_z^i * \sigma_z^j)의 합.
40 | h_cost = -0.5 * sum(sI(nodes[0]) - sZ(i) * sZ(j) for i, j in graph)
41 |
42 | # 구동 해밀토니안은 모든 큐비트 i에 대해 \sigma_x^i의 합.
43 | h_driver = -1. * sum(sX(i) for i in nodes)
44 |
45 |
46 | def qaoa_ansatz(gammas, betas):
47 | """
48 | 각도 betas와 gammas의 배열로 주어지는 QAOA 가정법(ansatz) 프로그램을 반환하는 함수.
49 | 차수(order) P인 QAOA program은 len(betas) == len(gammas) == P를 갖는다.
50 | :param list(float) gammas: 비용 해밀토니안을 매개변수화하는 각도값들의 배열.
51 | :param list(float) betas: 구동 해밀토니안을 매개변수화하는 각도값들의 배열.
52 | :return: QAOA 가정법 프로그램.
53 | :rtype: 프로그램.
54 | """
55 | return Program([exponentiate_commuting_pauli_sum(h_cost)(g)
56 | + exponentiate_commuting_pauli_sum(h_driver)(b)
57 | for g, b in zip(gammas, betas)])
58 |
59 |
60 | # 상태 초기화 프로그램과 차수 P = 2인 QAOA 가정법 프로그램을 더해 전체 프로그램 생성하기.
61 | program = init_state_prog + qaoa_ansatz([0., 0.5], [0.75, 1.])
62 |
63 | # 양자 가상 머신 (QVM)을 초기화하고 프로그램을 수행합니다.
64 | qc = get_qc('9q-generic-qvm')
65 |
66 | results = qc.run_and_measure(program, trials=2)
67 |
68 |
--------------------------------------------------------------------------------
/korean/chapter10/cirq/example-supremacy-circuit.txt:
--------------------------------------------------------------------------------
1 | (0, 0): ───H───@───X^0.5─────────────T───────@────────────X^0.5───H───
2 | │ │
3 | (0, 1): ───H───@───X^0.5─────────────@───────┼────X^0.5───T───────H───
4 | │ │
5 | (0, 2): ───H───T─────────────────────@───────┼────@───────@───────H───
6 | │ │ │
7 | (0, 3): ───H───T─────────────────────────────┼────┼───────@───────H───
8 | │ │
9 | (1, 0): ───H───T────────@────────────Y^0.5───@────┼───────@───────H───
10 | │ │ │
11 | (1, 1): ───H───T────────┼─────────────────────────┼───────@───────H───
12 | │ │
13 | (1, 2): ───H───@───@────┼────────────X^0.5────────@───────X^0.5───H───
14 | │ │ │
15 | (1, 3): ───H───@───┼────┼────X^0.5───T────────────────────────────H───
16 | │ │
17 | (2, 0): ───H───@───┼────@────────────Y^0.5───T────────────────────H───
18 | │ │
19 | (2, 1): ───H───@───┼────X^0.5────────@────────────@───────X^0.5───H───
20 | │ │ │
21 | (2, 2): ───H───T───@─────────────────@───────X^0.5┼───────@───────H───
22 | │ │
23 | (2, 3): ───H───T─────────────────────────────@────┼───────@───────H───
24 | │ │
25 | (3, 0): ───H───T─────────────────────────────┼────┼───────@───────H───
26 | │ │ │
27 | (3, 1): ───H───T─────────────────────────────┼────@───────@───────H───
28 | │
29 | (3, 2): ───H───@───Y^0.5─────────────T───────┼────────────────────H───
30 | │ │
31 | (3, 3): ───H───@───X^0.5─────────────T───────@────────────X^0.5───H───
32 |
--------------------------------------------------------------------------------
/korean/chapter10/cirq/supremacy-cirquit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/korean/chapter10/cirq/supremacy-cirquit.png
--------------------------------------------------------------------------------
/notebooks/IonDeviceTutorial.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "IonDeviceTutorial.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "include_colab_link": true
10 | },
11 | "kernelspec": {
12 | "name": "python3",
13 | "display_name": "Python 3"
14 | }
15 | },
16 | "cells": [
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {
20 | "id": "view-in-github",
21 | "colab_type": "text"
22 | },
23 | "source": [
24 | "
"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {
30 | "id": "bNlUyYQcgMF-",
31 | "colab_type": "text"
32 | },
33 | "source": [
34 | "# **Ion Device Class**\n",
35 | "This notebook provides an introductiong to making circuits that are compatable with ion qubit devices in Cirq. IonDevice classes are available starting with release 0.5.0."
36 | ]
37 | },
38 | {
39 | "cell_type": "code",
40 | "metadata": {
41 | "id": "IzkX8CaROO8s",
42 | "colab_type": "code",
43 | "colab": {}
44 | },
45 | "source": [
46 | ""
47 | ],
48 | "execution_count": 0,
49 | "outputs": []
50 | },
51 | {
52 | "cell_type": "code",
53 | "metadata": {
54 | "id": "GTjMbjyAfJCK",
55 | "colab_type": "code",
56 | "outputId": "396de61f-b7a5-41de-c1fb-aad4f8144165",
57 | "colab": {
58 | "base_uri": "https://localhost:8080/",
59 | "height": 600
60 | }
61 | },
62 | "source": [
63 | "# install release containing NeutralAtomDevice and IonDevice classes\n",
64 | "!pip install cirq~=0.5.0"
65 | ],
66 | "execution_count": 0,
67 | "outputs": [
68 | {
69 | "output_type": "stream",
70 | "text": [
71 | "Requirement already satisfied: cirq~=0.5.0 in /usr/local/lib/python3.6/dist-packages (0.5.0)\n",
72 | "Requirement already satisfied: google-api-python-client~=1.6 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (1.7.11)\n",
73 | "Requirement already satisfied: sortedcontainers~=2.0 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (2.1.0)\n",
74 | "Requirement already satisfied: scipy in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (1.3.1)\n",
75 | "Requirement already satisfied: networkx~=2.1 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (2.4)\n",
76 | "Requirement already satisfied: protobuf~=3.5 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (3.10.0)\n",
77 | "Requirement already satisfied: sympy in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (1.1.1)\n",
78 | "Requirement already satisfied: numpy~=1.12 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (1.17.3)\n",
79 | "Requirement already satisfied: requests~=2.18 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (2.21.0)\n",
80 | "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (3.6.6)\n",
81 | "Requirement already satisfied: matplotlib~=2.2 in /usr/local/lib/python3.6/dist-packages (from cirq~=0.5.0) (2.2.4)\n",
82 | "Requirement already satisfied: uritemplate<4dev,>=3.0.0 in /usr/local/lib/python3.6/dist-packages (from google-api-python-client~=1.6->cirq~=0.5.0) (3.0.0)\n",
83 | "Requirement already satisfied: google-auth-httplib2>=0.0.3 in /usr/local/lib/python3.6/dist-packages (from google-api-python-client~=1.6->cirq~=0.5.0) (0.0.3)\n",
84 | "Requirement already satisfied: httplib2<1dev,>=0.9.2 in /usr/local/lib/python3.6/dist-packages (from google-api-python-client~=1.6->cirq~=0.5.0) (0.11.3)\n",
85 | "Requirement already satisfied: six<2dev,>=1.6.1 in /usr/local/lib/python3.6/dist-packages (from google-api-python-client~=1.6->cirq~=0.5.0) (1.12.0)\n",
86 | "Requirement already satisfied: google-auth>=1.4.1 in /usr/local/lib/python3.6/dist-packages (from google-api-python-client~=1.6->cirq~=0.5.0) (1.4.2)\n",
87 | "Requirement already satisfied: decorator>=4.3.0 in /usr/local/lib/python3.6/dist-packages (from networkx~=2.1->cirq~=0.5.0) (4.4.1)\n",
88 | "Requirement already satisfied: setuptools in /usr/local/lib/python3.6/dist-packages (from protobuf~=3.5->cirq~=0.5.0) (41.4.0)\n",
89 | "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.6/dist-packages (from sympy->cirq~=0.5.0) (1.1.0)\n",
90 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests~=2.18->cirq~=0.5.0) (2019.9.11)\n",
91 | "Requirement already satisfied: urllib3<1.25,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests~=2.18->cirq~=0.5.0) (1.24.3)\n",
92 | "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests~=2.18->cirq~=0.5.0) (3.0.4)\n",
93 | "Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests~=2.18->cirq~=0.5.0) (2.8)\n",
94 | "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib~=2.2->cirq~=0.5.0) (1.1.0)\n",
95 | "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib~=2.2->cirq~=0.5.0) (0.10.0)\n",
96 | "Requirement already satisfied: pytz in /usr/local/lib/python3.6/dist-packages (from matplotlib~=2.2->cirq~=0.5.0) (2018.9)\n",
97 | "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib~=2.2->cirq~=0.5.0) (2.6.1)\n",
98 | "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib~=2.2->cirq~=0.5.0) (2.4.2)\n",
99 | "Requirement already satisfied: cachetools>=2.0.0 in /usr/local/lib/python3.6/dist-packages (from google-auth>=1.4.1->google-api-python-client~=1.6->cirq~=0.5.0) (3.1.1)\n",
100 | "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.6/dist-packages (from google-auth>=1.4.1->google-api-python-client~=1.6->cirq~=0.5.0) (0.2.7)\n",
101 | "Requirement already satisfied: rsa>=3.1.4 in /usr/local/lib/python3.6/dist-packages (from google-auth>=1.4.1->google-api-python-client~=1.6->cirq~=0.5.0) (4.0)\n",
102 | "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /usr/local/lib/python3.6/dist-packages (from pyasn1-modules>=0.2.1->google-auth>=1.4.1->google-api-python-client~=1.6->cirq~=0.5.0) (0.4.7)\n"
103 | ],
104 | "name": "stdout"
105 | }
106 | ]
107 | },
108 | {
109 | "cell_type": "markdown",
110 | "metadata": {
111 | "id": "v3YMaPw1hfV_",
112 | "colab_type": "text"
113 | },
114 | "source": [
115 | "## IonDevice\n",
116 | "*Disclaimer: As with any proposed architecture for quantum computing, several research groups around the world are working towards a device based on ion qubits and each research group has a different approach. The IonDevice class will not accurately reflect all such devices. The class assumes a fully connected chain of ions with two-qubit gates implemented by an Ising type coupling known as the Molmer-Sorensen gate. The Molmer-Sorensen gate couples ions through the shared motional modes of the ion chain. The ion motion and internal state decouples at the end of each gate. The class assumes this decoupling is perfect and does not explicitly model the ion motion. This device is modeled on the ion trap quantum computer being constructed at Duke University as part of the National Science Foundation STAQ project and the participation in Cirq is part of the National Science Foundation EPiQC project's mission to provide open-source tools for mapping algorithms to hardware.*\n",
117 | "\n",
118 | "\n",
119 | "The IonDevice is described as a lineary array of qubits (LineQubit). The user must specify the number of qubits in the line and the duration of gates and measurements. The gate times and measurement times listed here are conservative values in microseconds."
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "metadata": {
125 | "id": "On6Wrh3XhSPO",
126 | "colab_type": "code",
127 | "colab": {}
128 | },
129 | "source": [
130 | "import cirq\n",
131 | "import numpy as np\n",
132 | "import cirq.ion as ci\n",
133 | "from cirq import Simulator\n",
134 | "import itertools\n",
135 | "import random\n",
136 | "### number of qubits \n",
137 | "qubit_num = 5\n",
138 | "### define your qubits as line qubits for a linear ion trap\n",
139 | "qubit_list = cirq.LineQubit.range(qubit_num)\n",
140 | "### make your ion trap device with desired gate times and qubits\n",
141 | "us = 1000*cirq.Duration(nanos=1)\n",
142 | "ion_device = ci.IonDevice(measurement_duration=100*us,\n",
143 | " twoq_gates_duration=200*us,\n",
144 | " oneq_gates_duration=10*us,\n",
145 | " qubits=qubit_list)"
146 | ],
147 | "execution_count": 0,
148 | "outputs": []
149 | },
150 | {
151 | "cell_type": "markdown",
152 | "metadata": {
153 | "id": "ptv6T5WH8CLa",
154 | "colab_type": "text"
155 | },
156 | "source": [
157 | "---\n",
158 | "\n",
159 | "### Native Gate Set\n",
160 | "The gates supported by the IonDevice class are single qubit rotations about X, Y, and Z and two qubit Molmer-Sorensen gates that are rotations about XX. \n",
161 | "\n",
162 | "\n",
163 | "\n",
164 | "---\n",
165 | "\n",
166 | "\n",
167 | "Some examples of gates in Cirq that the device supports are given below."
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "metadata": {
173 | "id": "Hotk4cHCpXCV",
174 | "colab_type": "code",
175 | "colab": {}
176 | },
177 | "source": [
178 | "# Single Qubit Z rotation by Pi/5 radians\n",
179 | "ion_device.validate_gate(cirq.Rz(np.pi/5))\n",
180 | "# Single Qubit X rotation by Pi/7 radians \n",
181 | "ion_device.validate_gate(cirq.Rx(np.pi/7))\n",
182 | "# Molmer-Sorensen gate by Pi/4 \n",
183 | "ion_device.validate_gate(cirq.MS(np.pi/4))"
184 | ],
185 | "execution_count": 0,
186 | "outputs": []
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {
191 | "id": "nc4zLydMsrkV",
192 | "colab_type": "text"
193 | },
194 | "source": [
195 | "A Toffoli is an example of a gates in Cirq that the IonDevice does not support."
196 | ]
197 | },
198 | {
199 | "cell_type": "code",
200 | "metadata": {
201 | "id": "ChT4QK7TsabR",
202 | "colab_type": "code",
203 | "outputId": "884ba1fd-e01c-4350-c984-c871e2a62e63",
204 | "colab": {
205 | "base_uri": "https://localhost:8080/",
206 | "height": 164
207 | }
208 | },
209 | "source": [
210 | "#Controlled gate with non-integer exponent (rotation angle must be a multiple of pi)\n",
211 | "ion_device.validate_gate(cirq.TOFFOLI)"
212 | ],
213 | "execution_count": 0,
214 | "outputs": [
215 | {
216 | "output_type": "error",
217 | "ename": "AttributeError",
218 | "evalue": "ignored",
219 | "traceback": [
220 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
221 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
222 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mion_device\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_gate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcirq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mToffoli\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
223 | "\u001b[0;31mAttributeError\u001b[0m: module 'cirq' has no attribute 'Toffoli'"
224 | ]
225 | }
226 | ]
227 | },
228 | {
229 | "cell_type": "markdown",
230 | "metadata": {
231 | "id": "1byvHcWvHx-D",
232 | "colab_type": "text"
233 | },
234 | "source": [
235 | "###Bernstein-Vazirani Algorithm\n",
236 | "As an example of implementing an algorithm on the IonDevice. We examine the Bernstein-Vazirani Algorithm (BV). \n",
237 | "\n",
238 | "**Problem** Given a hidden string of $k$ bits $s$ and an oracle that outputs a single bit $y=x\\cdot s$ mod 2, find *s*. For input string $x$ and output bit $b$, $Oracle([x,b])=[x,b\\oplus y]$\n",
239 | "\n",
240 | "**Classical Solution** We can determine $s$ bit by bit by sending bit strings with a single 1 ( $x_l = x_{{0l\n",
241 | "}}x_{{1l}}x_{{2l}}..x_{{kl}}$ where $x_{{jl}}=\\delta_{{jl}}$). Then each $y$ yields one bit of $s$ and after $k$ queries we have $s$.\n",
242 | "\n",
243 | "**Quantum Solution** BV uses phase kick-back to reveal the value of the $s$ in a single oracle call. The input string starts in $|0\\rangle$ and then Hadamards are applied to yield $\\sum_x \\frac{1}{2^{{k/2}}} |x\\rangle$. The output bit starts in $|1\\rangle$ and then a Hadamard is applied yielding $|-\\rangle =\\frac{1}{\\sqrt{2}}(|0\\rangle-|1\\rangle)$. When the Oracle is applied, all strings $x$ where $x\\cdot s =0$ mod 2 do not receive a phase. All strings where $x\\cdot s =1$ mod 2 receive a phase of -1. After the oracle, our state on the input register is $\\sum_x \\frac{1}{2^{{k/2}}} (-1)^{{x.s}} |x\\rangle$. When we apply Hadamards to the input register, this yields $|s\\rangle$. BV allows us to find $s$ in a single oracle call.\n",
244 | "\n",
245 | "### Ion Trap Implementation\n",
246 | "Oracles are note a native device gate, so we need to construct it. A simple oracle can be constructed by applying CNOT gates from the input register to the output bit where there is a CNOT from bit $l$ in the input register to the output bit if $s_l=1$. CNOT gates are also not native ion trap gates. Below we show how to implement this sequence in Cirq using the decomposition tool to translate from CNOTSs and Hadamards to ion trap gates.\n",
247 | "\n",
248 | "\n",
249 | "\n",
250 | "\n",
251 | "\n"
252 | ]
253 | },
254 | {
255 | "cell_type": "markdown",
256 | "metadata": {
257 | "id": "mWCh6lMVHuHT",
258 | "colab_type": "text"
259 | },
260 | "source": [
261 | "First we define the hidden string $s$ ."
262 | ]
263 | },
264 | {
265 | "cell_type": "code",
266 | "metadata": {
267 | "id": "2-JF9nfaIDul",
268 | "colab_type": "code",
269 | "colab": {}
270 | },
271 | "source": [
272 | "### length of your hidden string\n",
273 | "string_length = qubit_num-1\n",
274 | "### generate all possible strings of length string_length, and randomly choose one as your hidden string\n",
275 | "all_strings = [\"\".join(seq) for seq in itertools.product(\"01\", repeat=string_length)]\n",
276 | "hidden_string = random.choice(all_strings)"
277 | ],
278 | "execution_count": 0,
279 | "outputs": []
280 | },
281 | {
282 | "cell_type": "markdown",
283 | "metadata": {
284 | "id": "0G36UOx5IiAt",
285 | "colab_type": "text"
286 | },
287 | "source": [
288 | "Then we construct the generic circuit."
289 | ]
290 | },
291 | {
292 | "cell_type": "code",
293 | "metadata": {
294 | "id": "Ivz41tqnImIJ",
295 | "colab_type": "code",
296 | "outputId": "bb5a6623-9dec-47a9-b73f-4d001fbde2d5",
297 | "colab": {
298 | "base_uri": "https://localhost:8080/",
299 | "height": 289
300 | }
301 | },
302 | "source": [
303 | "\n",
304 | "### make the circuit for BV with clifford gates\n",
305 | "circuit = cirq.Circuit()\n",
306 | "circuit.append([cirq.X(qubit_list[qubit_num-1])])\n",
307 | "for i in range(qubit_num):\n",
308 | " circuit.append([cirq.H(qubit_list[i])])\n",
309 | "for i in range(qubit_num-1):\n",
310 | " if hidden_string[i] == '1':\n",
311 | " circuit.append([cirq.CNOT(qubit_list[i], qubit_list[qubit_num-1])])\n",
312 | "for i in range(qubit_num - 1):\n",
313 | " circuit.append([cirq.H(qubit_list[i])])\n",
314 | " circuit.append([cirq.measure(qubit_list[i])])\n",
315 | "\n",
316 | "print(\"Doing Bernstein-Vazirani algorithm with hidden string\",\n",
317 | " hidden_string, \"\\n\")\n",
318 | "print(\"Clifford Circuit:\\n\")\n",
319 | "print(circuit, \"\\n\")"
320 | ],
321 | "execution_count": 0,
322 | "outputs": [
323 | {
324 | "output_type": "stream",
325 | "text": [
326 | "Doing Bernstein-Vazirani algorithm with hidden string 1011 \n",
327 | "\n",
328 | "Clifford Circuit:\n",
329 | "\n",
330 | " ┌──┐\n",
331 | "0: ───H────────@─────H───M───────────\n",
332 | " │\n",
333 | "1: ───H───H────┼M────────────────────\n",
334 | " │\n",
335 | "2: ───H────────┼─────@───H───M───────\n",
336 | " │ │\n",
337 | "3: ───H────────┼─────┼───@───H───M───\n",
338 | " │ │ │\n",
339 | "4: ───X───H────X─────X───X───────────\n",
340 | " └──┘ \n",
341 | "\n"
342 | ],
343 | "name": "stdout"
344 | }
345 | ]
346 | },
347 | {
348 | "cell_type": "markdown",
349 | "metadata": {
350 | "id": "43Y5dphQI3Be",
351 | "colab_type": "text"
352 | },
353 | "source": [
354 | "Convert to ion trap gates using KAK decomposition and circuit identities for CNOT and H."
355 | ]
356 | },
357 | {
358 | "cell_type": "code",
359 | "metadata": {
360 | "id": "wxe42roTJNZ1",
361 | "colab_type": "code",
362 | "outputId": "c0b475f1-0321-406e-ddb4-f0ba8b04970a",
363 | "colab": {
364 | "base_uri": "https://localhost:8080/",
365 | "height": 1249
366 | }
367 | },
368 | "source": [
369 | "### convert the clifford circuit into circuit with ion trap native gates\n",
370 | "ion_circuit = ion_device.decompose_circuit(circuit)\n",
371 | "print(repr(ion_circuit))\n",
372 | "print(\"Iontrap Circuit: \\n\", ion_circuit, \"\\n\")"
373 | ],
374 | "execution_count": 0,
375 | "outputs": [
376 | {
377 | "output_type": "stream",
378 | "text": [
379 | "cirq.Circuit(moments=[\n",
380 | " cirq.Moment(operations=[\n",
381 | " cirq.X.on(cirq.LineQubit(4)),\n",
382 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(0)),\n",
383 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(1)),\n",
384 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(2)),\n",
385 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(3)),\n",
386 | " ]),\n",
387 | " cirq.Moment(operations=[\n",
388 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(0)),\n",
389 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(1)),\n",
390 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(2)),\n",
391 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(3)),\n",
392 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(4)),\n",
393 | " ]),\n",
394 | " cirq.Moment(operations=[\n",
395 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(4)),\n",
396 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(1)),\n",
397 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(2)),\n",
398 | " cirq.Ry(np.pi*0.5).on(cirq.LineQubit(0)),\n",
399 | " cirq.Ry(np.pi*0.5).on(cirq.LineQubit(3)),\n",
400 | " ]),\n",
401 | " cirq.Moment(operations=[\n",
402 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(1)),\n",
403 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(2)),\n",
404 | " cirq.MS(0.5*np.pi/2).on(cirq.LineQubit(0), cirq.LineQubit(4)),\n",
405 | " ]),\n",
406 | " cirq.Moment(operations=[\n",
407 | " cirq.Rx(np.pi*-0.5).on(cirq.LineQubit(0)),\n",
408 | " cirq.Rx(np.pi*-0.5).on(cirq.LineQubit(4)),\n",
409 | " cirq.MeasurementGate(1, '1', ()).on(cirq.LineQubit(1)),\n",
410 | " cirq.MeasurementGate(1, '2', ()).on(cirq.LineQubit(2)),\n",
411 | " ]),\n",
412 | " cirq.Moment(operations=[\n",
413 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(0)),\n",
414 | " cirq.MS(0.5*np.pi/2).on(cirq.LineQubit(3), cirq.LineQubit(4)),\n",
415 | " ]),\n",
416 | " cirq.Moment(operations=[\n",
417 | " cirq.Rx(np.pi*-0.5).on(cirq.LineQubit(3)),\n",
418 | " cirq.Rx(np.pi*-0.5).on(cirq.LineQubit(4)),\n",
419 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(0)),\n",
420 | " ]),\n",
421 | " cirq.Moment(operations=[\n",
422 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(3)),\n",
423 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(0)),\n",
424 | " ]),\n",
425 | " cirq.Moment(operations=[\n",
426 | " cirq.MeasurementGate(1, '0', ()).on(cirq.LineQubit(0)),\n",
427 | " cirq.Rx(np.pi*1.0).on(cirq.LineQubit(3)),\n",
428 | " ]),\n",
429 | " cirq.Moment(operations=[\n",
430 | " cirq.Ry(np.pi*-0.5).on(cirq.LineQubit(3)),\n",
431 | " ]),\n",
432 | " cirq.Moment(operations=[\n",
433 | " cirq.MeasurementGate(1, '3', ()).on(cirq.LineQubit(3)),\n",
434 | " ]),\n",
435 | "])\n",
436 | "Iontrap Circuit: \n",
437 | " ┌──────────────────┐\n",
438 | "0: ───Rx(π)───Ry(-0.5π)───Ry(0.5π)──────────────MS(0.25π)────Rx(-0.5π)───Ry(-0.5π)───Rx(π)───────Ry(-0.5π)───M───────────────────────\n",
439 | " │\n",
440 | "1: ───Rx(π)───Ry(-0.5π)───Rx(π)────────Ry(-0.5π)┼────────────M───────────────────────────────────────────────────────────────────────\n",
441 | " │\n",
442 | "2: ───Rx(π)───Ry(-0.5π)───Rx(π)────────Ry(-0.5π)┼────────────M───────────────────────────────────────────────────────────────────────\n",
443 | " │\n",
444 | "3: ───Rx(π)───Ry(-0.5π)───Ry(0.5π)──────────────┼────────────────────────MS(0.25π)───Rx(-0.5π)───Ry(-0.5π)───Rx(π)───Ry(-0.5π)───M───\n",
445 | " │ │\n",
446 | "4: ───X───────Rx(π)───────Ry(-0.5π)─────────────MS(0.25π)────Rx(-0.5π)───MS(0.25π)───Rx(-0.5π)───────────────────────────────────────\n",
447 | " └──────────────────┘ \n",
448 | "\n"
449 | ],
450 | "name": "stdout"
451 | }
452 | ]
453 | },
454 | {
455 | "cell_type": "markdown",
456 | "metadata": {
457 | "id": "6Znix0ZLI_FP",
458 | "colab_type": "text"
459 | },
460 | "source": [
461 | "We can use cirq.merge_single_qubit_gates_into_phased_x_z(circuit)"
462 | ]
463 | },
464 | {
465 | "cell_type": "code",
466 | "metadata": {
467 | "id": "rt-MfhxXJAK7",
468 | "colab_type": "code",
469 | "outputId": "d8b8f67c-2938-474c-a798-d67fff1c8dbe",
470 | "colab": {
471 | "base_uri": "https://localhost:8080/",
472 | "height": 210
473 | }
474 | },
475 | "source": [
476 | "### convert the clifford circuit into circuit with ion trap native gates\n",
477 | "ion_circuit = ion_device.decompose_circuit(circuit)\n",
478 | "optimized_ion_circuit=cirq.merge_single_qubit_gates_into_phased_x_z(ion_circuit)\n",
479 | "print(\"Iontrap Circuit: \\n\", ion_circuit, \"\\n\")"
480 | ],
481 | "execution_count": 0,
482 | "outputs": [
483 | {
484 | "output_type": "stream",
485 | "text": [
486 | "Iontrap Circuit: \n",
487 | " 0: ───X────────────────MS(0.25π)───X^0.5─────────────────────────────M───────────\n",
488 | " │\n",
489 | "1: ────────────────────┼───────────M─────────────────────────────────────────────\n",
490 | " │\n",
491 | "2: ────────────────────┼───────────M─────────────────────────────────────────────\n",
492 | " │\n",
493 | "3: ───X────────────────┼────────────────────MS(0.25π)───X^0.5────────────────M───\n",
494 | " │ │\n",
495 | "4: ───Y^-0.5───────────MS(0.25π)───X^-0.5───MS(0.25π)───X^-0.5─────────────────── \n",
496 | "\n"
497 | ],
498 | "name": "stdout"
499 | }
500 | ]
501 | },
502 | {
503 | "cell_type": "markdown",
504 | "metadata": {
505 | "id": "_OI0PKG2JrfG",
506 | "colab_type": "text"
507 | },
508 | "source": [
509 | "We can compare then simulate both circuits"
510 | ]
511 | },
512 | {
513 | "cell_type": "code",
514 | "metadata": {
515 | "id": "kCsfQim5KARZ",
516 | "colab_type": "code",
517 | "outputId": "b0cc373a-0877-4034-b72d-1678915d8d7c",
518 | "colab": {
519 | "base_uri": "https://localhost:8080/",
520 | "height": 70
521 | }
522 | },
523 | "source": [
524 | "### run the ion trap circuit\n",
525 | "simulator = Simulator()\n",
526 | "clifford_result = simulator.run(circuit)\n",
527 | "result = simulator.run(ion_circuit)\n",
528 | "\n",
529 | "measurement_results = ''\n",
530 | "for i in range(qubit_num-1):\n",
531 | " if result.measurements[str(i)][0][0]:\n",
532 | " measurement_results += '1'\n",
533 | " else:\n",
534 | " measurement_results += '0'\n",
535 | "\n",
536 | "print(\"Hidden string is:\", hidden_string)\n",
537 | "print(\"Measurement results are:\", measurement_results)\n",
538 | "print(\"Found answer using Bernstein-Vazirani:\", hidden_string == measurement_results)\n"
539 | ],
540 | "execution_count": 0,
541 | "outputs": [
542 | {
543 | "output_type": "stream",
544 | "text": [
545 | "Hidden string is: 1001\n",
546 | "Measurement results are: 1001\n",
547 | "Found answer using Bernstein-Vazirani: True\n"
548 | ],
549 | "name": "stdout"
550 | }
551 | ]
552 | },
553 | {
554 | "cell_type": "code",
555 | "metadata": {
556 | "id": "Q1OStHBa0Aur",
557 | "colab_type": "code",
558 | "colab": {}
559 | },
560 | "source": [
561 | ""
562 | ],
563 | "execution_count": 0,
564 | "outputs": []
565 | }
566 | ]
567 | }
--------------------------------------------------------------------------------
/presentations/Cirq Ion Trap Demo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/presentations/Cirq Ion Trap Demo.pdf
--------------------------------------------------------------------------------
/presentations/Cirq Workshop Slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/presentations/Cirq Workshop Slides.pdf
--------------------------------------------------------------------------------
/presentations/Intro to Quantum Hardware (May 2019).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/presentations/Intro to Quantum Hardware (May 2019).pdf
--------------------------------------------------------------------------------
/presentations/QC Review (Bootcamp) V2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackHidary/quantumcomputingbook/64a5c56f24390f2efb38967a1b0adf77c395e028/presentations/QC Review (Bootcamp) V2.pdf
--------------------------------------------------------------------------------
/resources:
--------------------------------------------------------------------------------
1 | resources
2 |
3 |
4 | https://www.scientificamerican.com/article/what-makes-a-quantum-comp/
5 |
--------------------------------------------------------------------------------