Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Add python examples (#261)
Browse files Browse the repository at this point in the history
* 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
deadmau6 authored and Chris Granade committed Dec 9, 2019
1 parent 55b4618 commit ba5b111
Show file tree
Hide file tree
Showing 13 changed files with 751 additions and 0 deletions.
117 changes: 117 additions & 0 deletions samples/algorithms/database-search/host.py
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")
64 changes: 64 additions & 0 deletions samples/algorithms/integer-factorization/host.py
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.")
30 changes: 30 additions & 0 deletions samples/algorithms/oracle-synthesis/host.py
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")
125 changes: 125 additions & 0 deletions samples/algorithms/order_finding.py
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)
14 changes: 14 additions & 0 deletions samples/algorithms/reversible-logic-synthesis/host.py
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}')
18 changes: 18 additions & 0 deletions samples/chemistry/AnalyzeHamiltonian/host.py
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}")
Loading

0 comments on commit ba5b111

Please sign in to comment.