This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 922
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* started writing python examples * Most of the Algorithms samples are complete * error-correction samples complete * Completed integer factorization I also changed the default to 10 because 100 is alot. * Complete all of the python examples in algorithms. The following examples completed: * Database Search * Oracle Synthesis * Reversible Logic Synthesis * Order Finding * Completed simulations and simple algorithms * Complete the samples for the numerics folder * fix quantum oracle probability output * Clean up the code and add useful comments. * Added spacing and helpful comments. * Added helpful comments and removed unused imports. * Added helpful comments and cmd args to simulation. * Added helpful comments and moved code to a main function. * Create basic AnalyzeHamiltonian python sample * start to the chemistry samples * removed unfinished chemistry samples * Changes made: * Converted everything to pep8 with a little help from [autopep8](https://github.com/hhatto/autopep8). * Add `try/except` in `integer-factorization/host.py`. * Add `if __name__ == "__main__"` in `oracle-synthesis/host.py`. * Use `%` in `f-string` in `order_finding.py`. * Added citation in `order_finding.py`. * Add MIT license reminder to each source file. * Fixes: * corrected more style issues * renamed some variables to be more clear and concise * corrected the import order for numerics * removed unused imports
- Loading branch information
Showing
13 changed files
with
751 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import math | ||
import qsharp | ||
from Microsoft.Quantum.Samples.DatabaseSearch import ApplyQuantumSearch, ApplyGroverSearch | ||
|
||
def random_oracle(): | ||
"""Let us investigate the success probability of classical random search. | ||
This corresponds to the case where we only prepare the start state, and | ||
do not perform any Grover iterates to amplify the marked subspace. | ||
""" | ||
n_iterations = 0 | ||
|
||
# Define the size `N` = 2^n of the database to search in terms of number of qubits | ||
n_qubits = 3 | ||
db_size = 2 ** n_qubits | ||
|
||
# We now execute the classical random search and verify that the success | ||
# probability matches the classical result of 1/N. Let us repeat 100 | ||
# times to collect enough statistics. | ||
classical_success = 1 / db_size | ||
repeats = 1000 | ||
success_count = 0 | ||
|
||
print("Classical random search for marked element in database.") | ||
print(f"Database size: {db_size}.") | ||
print(f"Success probability: {classical_success}.\n") | ||
|
||
for i in range(repeats): | ||
# The simulation returns a tuple like so: (Int, List). | ||
marked_qubit, db_register = ApplyQuantumSearch.simulate(nIterations=n_iterations, nDatabaseQubits=n_qubits) | ||
success_count += 1 if marked_qubit == 1 else 0 | ||
# Print the results of the search every 100 attempts | ||
if (i + 1) % 100 == 0: | ||
print(f"Attempt: {i}. Success: {marked_qubit}, Probability: {round(success_count / (i + 1), 3)} Found database index: {', '.join([str(x) for x in db_register])}") | ||
|
||
def quantum_oracle(): | ||
"""Let us investigate the success probability of the quantum search. | ||
Now perform Grover iterates to amplify the marked subspace. | ||
""" | ||
n_iterations = 3 | ||
# Number of queries to database oracle. | ||
queries = n_iterations * 2 + 1 | ||
# Define the size `N` = 2^n of the database to search in terms of number of qubits | ||
n_qubits = 6 | ||
db_size = 2 ** n_qubits | ||
|
||
# Now execute the quantum search and verify that the success probability matches the theoretical prediction. | ||
classical_success = 1 / db_size | ||
quantum_success = math.pow(math.sin((2 * n_iterations + 1) * math.asin(1 / math.sqrt(db_size))), 2) | ||
repeats = 100 | ||
success_count = 0 | ||
|
||
print("Quantum search for marked element in database.") | ||
print(f" Database Size: {db_size}") | ||
print(f" Classical Success Probability: {classical_success}") | ||
print(f" Queries per search: {queries}") | ||
print(f" Quantum Success Probability: {quantum_success}.\n") | ||
|
||
for i in range(repeats): | ||
# The simulation returns a tuple like so: (Int, List). | ||
marked_qubit, register = ApplyQuantumSearch.simulate(nIterations=n_iterations, nDatabaseQubits=n_qubits) | ||
success_count += 1 if marked_qubit == 1 else 0 | ||
# Print the results of the search every 10 attempts. | ||
if (i + 1) % 10 == 0: | ||
empirical_success = round(success_count / (i + 1), 3) | ||
# This is how much faster the quantum algorithm performs on average over the classical search. | ||
speed_up = round( (empirical_success / classical_success) / queries, 3) | ||
print(f"Attempt: {i} Success: {marked_qubit} Probability: {empirical_success} Speed: {speed_up} Found database index at: {', '.join([str(x) for x in register])}") | ||
|
||
def multiple_quantum_elements(): | ||
"""Let us investigate the success probability of the quantum search with multiple marked elements. | ||
We perform Grover iterates to amplify the marked subspace. | ||
""" | ||
n_iterations = 3 | ||
# Number of queries to database oracle. | ||
queries = n_iterations * 2 + 1 | ||
# Define the size `N` = 2^n of the database to search in terms of number of qubits | ||
n_qubits = 8 | ||
db_size = 2 ** n_qubits | ||
# We define the marked elements. These must be smaller than `databaseSize`. | ||
marked_elements = [0, 39, 101, 234] | ||
# Now execute the quantum search and verify that the success probability matches the theoretical prediction. | ||
classical_success = len(marked_elements) / db_size | ||
quantum_success = math.pow(math.sin((2 * n_iterations + 1) * math.asin(math.sqrt(len(marked_elements)) / math.sqrt(db_size))), 2) | ||
repeats = 10 | ||
success_count = 0 | ||
|
||
print("Quantum search for marked element in database.") | ||
print(f" Database size: {db_size}.") | ||
print(f" Marked Elements: {', '.join([str(x) for x in marked_elements])}") | ||
print(f" Classical Success Probility: {classical_success}") | ||
print(f" Queries per search: {queries}") | ||
print(f" Quantum success probability: {quantum_success}.\n") | ||
|
||
for i in range(repeats): | ||
# The simulation returns a tuple like so: (Int, List). | ||
marked_qubits, register = ApplyGroverSearch.simulate(markedElements=marked_elements, nIterations=n_iterations, nDatabaseQubits=n_qubits) | ||
success_count += 1 if marked_qubits == 1 else 0 | ||
|
||
# Print the results of the search every attempt. | ||
empirical_success = round(success_count / (i + 1), 3) | ||
# This is how much faster the quantum algorithm performs on average over the classical search. | ||
speed_up = round( (empirical_success / classical_success) / queries, 3) | ||
print(f"Attempt: {i}. Success: {marked_qubits}, Probability: {empirical_success} Speed up: {speed_up} Found database index: {register}") | ||
|
||
if __name__ == "__main__": | ||
random_oracle() | ||
print("\n") | ||
quantum_oracle() | ||
print("\n") | ||
multiple_quantum_elements() | ||
print("\n\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import argparse | ||
import qsharp | ||
from qsharp import IQSharpError | ||
from Microsoft.Quantum.Samples.IntegerFactorization import FactorInteger | ||
|
||
|
||
def factor_integer(number_to_factor, n_trials, use_robust_phase_estimation): | ||
""" Use Shor's algorithm to factor an integer. | ||
Shor's algorithm is a probabilistic algorithm and can fail with certain probability in several ways. | ||
For more details see Shor.qs. | ||
""" | ||
# Repeat Shor's algorithm multiple times because the algorithm is | ||
# probabilistic. | ||
for i in range(n_trials): | ||
# Report the number to factor on each attempt. | ||
print("==========================================") | ||
print(f'Factoring {number_to_factor}') | ||
# Compute the factors | ||
try: | ||
output = FactorInteger.simulate( | ||
number=number_to_factor, | ||
useRobustPhaseEstimation=use_robust_phase_estimation, | ||
raise_on_stderr=True) | ||
factor_1, factor_2 = output | ||
print(f"Factors are {factor_1} and {factor_2}.") | ||
except IQSharpError as error: | ||
# Report the failed attempt. | ||
print("This run of Shor's algorithm failed:") | ||
print(error) | ||
|
||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description="Factor Integers using Shor's algorithm.") | ||
parser.add_argument( | ||
'-n', | ||
'--number', | ||
type=int, | ||
help='number to be factored.(default=15)', | ||
default=15 | ||
) | ||
parser.add_argument( | ||
'-t', | ||
'--trials', | ||
type=int, | ||
help='number of trial to perform.(default=10)', | ||
default=10 | ||
) | ||
parser.add_argument( | ||
'-u', | ||
'--use-robust-pe', | ||
action='store_true', | ||
help='if true uses Robust Phase Estimation, otherwise uses Quantum Phase Estimation.(default=False)', | ||
default=False) | ||
args = parser.parse_args() | ||
if args.number >= 1: | ||
factor_integer(args.number, args.trials, args.use_robust_pe) | ||
else: | ||
print("Error: Invalid number. The number '-n' must be greater than or equal to 1.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import qsharp | ||
from Microsoft.Quantum.Samples.OracleSynthesis import RunOracleSynthesisOnCleanTarget, RunOracleSynthesis | ||
|
||
if __name__ == "__main__": | ||
"""Runs the Oracle Synthesis. | ||
The input 'func' is suppose to be an integer representation of a truth table. | ||
So if 'func' = 5 then the truth table is [1, 0, 1] which is actually encoded as [-1, 1, -1] => [true, false, true]. | ||
The input 'vars' determines the size of the truth table such that the length of a the table = 2 ** 'vars'. | ||
So if 'vars' = 3 then the table will have 8 values. | ||
""" | ||
print("Running Synthesis on clean target...") | ||
for i in range(256): | ||
# Implements oracle circuit for a given function, assuming that target qubit is initialized 0. | ||
# The adjoint operation assumes that the target qubit will be released to 0. | ||
res = RunOracleSynthesisOnCleanTarget.simulate(func=i, vars=3) | ||
if not res: | ||
print(f"Result = {res}") | ||
print("Complete.\n") | ||
|
||
print("Running Synthesis...") | ||
for i in range(256): | ||
# Implements oracle circuit for function | ||
res = RunOracleSynthesis.simulate(func=i, vars=3) | ||
if not res: | ||
print(f"Result = {res}") | ||
print("Complete.\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import argparse | ||
import random | ||
import qsharp | ||
from Microsoft.Quantum.Samples.OrderFinding import FindOrder | ||
|
||
|
||
def get_order(perm, index): | ||
"""Returns the exact order (length) of the cycle that contains a given index. | ||
""" | ||
order = 1 | ||
curr = index | ||
while index != perm[curr]: | ||
order += 1 | ||
curr = perm[curr] | ||
return order | ||
|
||
|
||
def guess_quantum(perm, index): | ||
"""Estimates the order of a cycle, using a quantum algorithm defined in the Q# file. | ||
Computes the permutation πⁱ(input) where i is a superposition of all values from 0 to 7. | ||
The algorithm then uses QFT to find a period in the resulting state. | ||
The result needs to be post-processed to find the estimate. | ||
""" | ||
result = FindOrder.simulate(perm=perm, input=index) | ||
if result == 0: | ||
guess = random.random() | ||
# The probability distribution is extracted from the second column (m = 0) in Fig. 2's table | ||
# on the right-hand side, as shown in L.M.K. Vandersypen et al., PRL 85, 5452, 2000 (https://arxiv.org/abs/quant-ph/0007017). | ||
if guess <= 0.5505: | ||
return 1 | ||
elif guess <= 0.5505 + 0.1009: | ||
return 2 | ||
elif guess <= 0.5505 + 0.1009 + 0.1468: | ||
return 3 | ||
return 4 | ||
elif result % 2 == 1: | ||
return 3 | ||
elif (result == 2) or (result == 6): | ||
return 4 | ||
return 2 | ||
|
||
|
||
def guess_classical(perm, index): | ||
"""Guesses the order (classically) for cycle that contains a given index | ||
The algorithm computes π³(index). If the result is index, it | ||
returns 1 or 3 with probability 50% each, otherwise, it | ||
returns 2 or 4 with probability 50% each. | ||
""" | ||
if perm[perm[perm[index]]] == index: | ||
return random.choice([1, 3]) | ||
return random.choice([2, 4]) | ||
|
||
|
||
def guess_order(perm, index, n): | ||
|
||
# This object counts the number of times the quantum algorithm guesses a | ||
# given order.(so { order: count }) | ||
q_guesses = {k + 1: 0 for k in perm} | ||
# This object counts the number of times the classical algorithm guesses a | ||
# given order.(so { order: count }) | ||
c_guesses = {k + 1: 0 for k in perm} | ||
|
||
# Guess the order, 'n' amount of times. | ||
for i in range(n): | ||
# Count the classical guesses. | ||
c_guesses[guess_classical(perm, index)] += 1 | ||
# Count the quantum guesses. | ||
q_guesses[guess_quantum(perm, index)] += 1 | ||
|
||
print("\nClassical Guesses: ") | ||
for order, count in c_guesses.items(): | ||
# Return the percentage of each order guess, which = (num_of_guesses / | ||
# total_guesses) * 100. | ||
print(f"{order}: {count / n : 0.2%}") | ||
|
||
print("\nQuantum Guesses: ") | ||
for order, count in q_guesses.items(): | ||
# Return the percentage of each order guess, which = (num_of_guesses / | ||
# total_guesses) * 100. | ||
print(f"{order}: {count / n : 0.2%}") | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description="Guess the order of a given permutation, using both classical and Quantum computing.") | ||
parser.add_argument( | ||
'-p', | ||
'--permutation', | ||
nargs=4, | ||
type=int, | ||
help='provide only four integers to form a permutation.(default=[1,2,3,0])', | ||
metavar='INT', | ||
default=[ | ||
1, | ||
2, | ||
3, | ||
0]) | ||
parser.add_argument( | ||
'-i', | ||
'--index', | ||
type=int, | ||
help='the permutations cycle index.(default=0)', | ||
default=0 | ||
) | ||
parser.add_argument( | ||
'-s', | ||
'--shots', | ||
type=int, | ||
help='number of repetitions when guessing.(default=1024)', | ||
default=1024 | ||
) | ||
|
||
args = parser.parse_args() | ||
print(f"Permutation: {args.permutation}") | ||
print(f"Find cycle length at index: {args.index}") | ||
|
||
exact_order = get_order(args.permutation, args.index) | ||
print(f"Exact order: {exact_order}") | ||
|
||
guess_order(args.permutation, args.index, args.shots) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import qsharp | ||
from Microsoft.Quantum.Samples.ReversibleLogicSynthesis import SimulatePermutation, FindHiddenShift | ||
|
||
if __name__ == "__main__": | ||
perm = [0, 2, 3, 5, 7, 1, 4, 6] | ||
res = SimulatePermutation.simulate(perm=perm) | ||
print(f'Does circuit realize permutation: {res}') | ||
|
||
for shift in range(len(perm)): | ||
measure = FindHiddenShift.simulate(perm=perm, shift=shift) | ||
print(f'Applied shift = {shift} Measured shift: {measure}') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
import numpy as np | ||
from numpy import linalg as LA | ||
from qsharp.chemistry import load_broombridge, load_fermion_hamiltonian, IndexConvention | ||
|
||
|
||
LiH = '../IntegralData/YAML/lih_sto-3g_0.800_int.yaml' | ||
|
||
print(f"Processing the following file: {LiH}") | ||
broombridge = load_broombridge(LiH) | ||
general_hamiltonian = broombridge.problem_description[0].load_fermion_hamiltonian( | ||
index_convention=IndexConvention.UpDown) | ||
print("End of file. Computing One-norms:") | ||
for term, matrix in general_hamiltonian.terms: | ||
one_norm = LA.norm(np.asarray([v for k, v in matrix], dtype=np.float32), ord=1) | ||
print(f"One-norm for term type {term}: {one_norm}") |
Oops, something went wrong.