Compare commits
4 Commits
task1
...
a512e5a534
| Author | SHA1 | Date | |
|---|---|---|---|
| a512e5a534 | |||
| b85f09e680 | |||
| ac2f465ae2 | |||
| f614abe349 |
25
task2/main.py
Normal file
25
task2/main.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import cirq
|
||||||
|
|
||||||
|
q0, q1 = cirq.LineQubit.range(2)
|
||||||
|
|
||||||
|
oracles = {
|
||||||
|
"0": [],
|
||||||
|
"1": [cirq.X(q1)],
|
||||||
|
"x": [cirq.CNOT(q0, q1)],
|
||||||
|
"notx": [cirq.CNOT(q0, q1), cirq.X(q1)],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def deutsch_algorithm(oracle):
|
||||||
|
yield cirq.X(q1)
|
||||||
|
yield cirq.H(q0), cirq.H(q1)
|
||||||
|
yield oracle
|
||||||
|
yield cirq.H(q0)
|
||||||
|
yield cirq.measure(q0)
|
||||||
|
|
||||||
|
|
||||||
|
simulator = cirq.Simulator()
|
||||||
|
|
||||||
|
for key, oracle in oracles.items():
|
||||||
|
result = simulator.run(cirq.Circuit(deutsch_algorithm(oracle)), repetitions=10)
|
||||||
|
print("oracle: {:<4} results: {}".format(key, result))
|
||||||
61
task3/main.py
Normal file
61
task3/main.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import cirq
|
||||||
|
|
||||||
|
# Кубиты: два входных (q0, q1) и целевой вспомогательный (q2)
|
||||||
|
q0, q1, q2 = cirq.LineQubit.range(3)
|
||||||
|
|
||||||
|
# Оракулы для константных функций: f(x)=0 и f(x)=1
|
||||||
|
constant = (
|
||||||
|
[], # ничего не делаем с целевым
|
||||||
|
[cirq.X(q2)], # инвертируем целевой
|
||||||
|
)
|
||||||
|
|
||||||
|
# Оракулы для сбалансированных функций
|
||||||
|
balanced = (
|
||||||
|
[cirq.CNOT(q0, q2)], # f=x0
|
||||||
|
[cirq.CNOT(q1, q2)], # f=x1
|
||||||
|
[cirq.CNOT(q0, q2), cirq.CNOT(q1, q2)],
|
||||||
|
[cirq.CNOT(q0, q2), cirq.X(q2)],
|
||||||
|
[cirq.CNOT(q1, q2), cirq.X(q2)],
|
||||||
|
[cirq.CNOT(q0, q2), cirq.CNOT(q1, q2), cirq.X(q2)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def deutsch_jozsa_circuit(oracle):
|
||||||
|
"""Схема DJ через yield: измеряем только q0 и q1."""
|
||||||
|
# 1) Входы в равномерную суперпозицию
|
||||||
|
yield cirq.H(q0), cirq.H(q1)
|
||||||
|
|
||||||
|
# 2) Подготовка целевого в |-> для фазового трюка
|
||||||
|
yield cirq.X(q2), cirq.H(q2)
|
||||||
|
|
||||||
|
# 3) Вызов оракула U_f
|
||||||
|
yield oracle
|
||||||
|
|
||||||
|
# 4) Интерференция на входах
|
||||||
|
yield cirq.H(q0), cirq.H(q1)
|
||||||
|
|
||||||
|
# 5) Измеряем только входные кубиты
|
||||||
|
yield cirq.measure(q0, q1, key="in")
|
||||||
|
|
||||||
|
|
||||||
|
def interpret(bits):
|
||||||
|
# bits — это массив вида [q0, q1]
|
||||||
|
return "constant" if (bits[0] == 0 and bits[1] == 0) else "balanced"
|
||||||
|
|
||||||
|
|
||||||
|
# Симулятор
|
||||||
|
sim = cirq.Simulator()
|
||||||
|
|
||||||
|
print("Результаты для константных функций:")
|
||||||
|
for i, oracle in enumerate(constant):
|
||||||
|
result = sim.run(cirq.Circuit(deutsch_jozsa_circuit(oracle)), repetitions=1)
|
||||||
|
bits = result.measurements["in"][0]
|
||||||
|
print(f" Константный оракул {i}: meas(q0,q1)={bits.tolist()} -> {interpret(bits)}")
|
||||||
|
|
||||||
|
print("\nРезультаты для сбалансированных функций:")
|
||||||
|
for i, oracle in enumerate(balanced):
|
||||||
|
result = sim.run(cirq.Circuit(deutsch_jozsa_circuit(oracle)), repetitions=1)
|
||||||
|
bits = result.measurements["in"][0]
|
||||||
|
print(
|
||||||
|
f" Сбалансированный оракул {i}: meas(q0,q1)={bits.tolist()} -> {interpret(bits)}"
|
||||||
|
)
|
||||||
91
task4/main.py
Normal file
91
task4/main.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
"""Алгоритм Бернштейна–Вазирани в Cirq."""
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
import cirq
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Выполняет алгоритм BV."""
|
||||||
|
# Количество кубитов
|
||||||
|
qubit_count = 8
|
||||||
|
# Количество выборок из схемы
|
||||||
|
circuit_sample_count = 3
|
||||||
|
|
||||||
|
# Выберите кубиты для использования
|
||||||
|
input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)]
|
||||||
|
output_qubit = cirq.GridQubit(qubit_count, 0)
|
||||||
|
|
||||||
|
# Выберите коэффициенты для оракула и создайте схему для его запроса
|
||||||
|
secret_bias_bit = random.randint(0, 1)
|
||||||
|
secret_factor_bits = [random.randint(0, 1) for _ in range(qubit_count)]
|
||||||
|
|
||||||
|
oracle = make_oracle(
|
||||||
|
input_qubits, output_qubit, secret_factor_bits, secret_bias_bit
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"Secret function:\nf(x) = x*<{}> + {} (mod 2)".format(
|
||||||
|
", ".join(str(e) for e in secret_factor_bits), secret_bias_bit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Встраиваем оракул в специальную квантовую схему, запрашивая ее ровно один раз
|
||||||
|
circuit = make_bernstein_vazirani_circuit(input_qubits, output_qubit, oracle)
|
||||||
|
print("\nCircuit:")
|
||||||
|
print(circuit)
|
||||||
|
|
||||||
|
# Выберем из схемы пару раз
|
||||||
|
simulator = cirq.Simulator()
|
||||||
|
result = simulator.run(circuit, repetitions=circuit_sample_count)
|
||||||
|
frequencies = result.histogram(key="result", fold_func=bitstring)
|
||||||
|
print("\nSampled results:\n{}".format(frequencies))
|
||||||
|
|
||||||
|
# Проверить, действительно ли мы нашли секретное значение
|
||||||
|
most_common_bitstring = frequencies.most_common(1)[0][0]
|
||||||
|
print(
|
||||||
|
"\nMost common matches secret factors:\n{}".format(
|
||||||
|
most_common_bitstring == bitstring(secret_factor_bits)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_oracle(input_qubits, output_qubit, secret_factor_bits, secret_bias_bit):
|
||||||
|
"""Вентили, реализующие функцию f(a) = a*factors + bias (mod 2)."""
|
||||||
|
if secret_bias_bit:
|
||||||
|
yield cirq.X(output_qubit)
|
||||||
|
|
||||||
|
for qubit, bit in zip(input_qubits, secret_factor_bits):
|
||||||
|
if bit:
|
||||||
|
yield cirq.CNOT(qubit, output_qubit)
|
||||||
|
|
||||||
|
|
||||||
|
def make_bernstein_vazirani_circuit(input_qubits, output_qubit, oracle):
|
||||||
|
"""Находит множители в f (a) = a * factors + bias (mod 2) с помощью одного запроса."""
|
||||||
|
c = cirq.Circuit()
|
||||||
|
|
||||||
|
# Инициализировать кубиты
|
||||||
|
c.append(
|
||||||
|
[
|
||||||
|
cirq.X(output_qubit),
|
||||||
|
cirq.H(output_qubit),
|
||||||
|
cirq.H.on_each(*input_qubits),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Запрос оракула
|
||||||
|
c.append(oracle)
|
||||||
|
|
||||||
|
# Измерение по оси X
|
||||||
|
c.append([cirq.H.on_each(*input_qubits), cirq.measure(*input_qubits, key="result")])
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def bitstring(bits):
|
||||||
|
"""Создает битовую строку из итерации битов."""
|
||||||
|
return "".join(str(int(b)) for b in bits)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
104
task5/main.py
Normal file
104
task5/main.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
import cirq
|
||||||
|
import numpy as np
|
||||||
|
import scipy as sp
|
||||||
|
|
||||||
|
|
||||||
|
def main(qubit_count=3):
|
||||||
|
|
||||||
|
data = [] # we'll store here the results
|
||||||
|
|
||||||
|
# define a secret string:
|
||||||
|
secret_string = np.random.randint(2, size=qubit_count)
|
||||||
|
|
||||||
|
print(f"Secret string = {secret_string}")
|
||||||
|
|
||||||
|
n_samples = 100
|
||||||
|
for _ in range(n_samples):
|
||||||
|
flag = False # check if we have a linearly independent set of measures
|
||||||
|
while not flag:
|
||||||
|
# Choose qubits to use.
|
||||||
|
input_qubits = [cirq.GridQubit(i, 0) for i in range(qubit_count)] # input x
|
||||||
|
output_qubits = [
|
||||||
|
cirq.GridQubit(i + qubit_count, 0) for i in range(qubit_count)
|
||||||
|
] # output f(x)
|
||||||
|
|
||||||
|
# Pick coefficients for the oracle and create a circuit to query it.
|
||||||
|
oracle = make_oracle(input_qubits, output_qubits, secret_string)
|
||||||
|
|
||||||
|
# Embed oracle into special quantum circuit querying it exactly once
|
||||||
|
circuit = make_simon_circuit(input_qubits, output_qubits, oracle)
|
||||||
|
|
||||||
|
# Sample from the circuit a n-1 times (n = qubit_count).
|
||||||
|
simulator = cirq.Simulator()
|
||||||
|
results = [
|
||||||
|
simulator.run(circuit).measurements["result"][0]
|
||||||
|
for _ in range(qubit_count - 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Classical Post-Processing:
|
||||||
|
flag = post_processing(data, results)
|
||||||
|
|
||||||
|
freqs = Counter(data)
|
||||||
|
print("Circuit:")
|
||||||
|
print(circuit)
|
||||||
|
print(f"Most common answer was : {freqs.most_common(1)[0]}")
|
||||||
|
|
||||||
|
|
||||||
|
def make_oracle(input_qubits, output_qubits, secret_string):
|
||||||
|
"""Gates implementing the function f(a) = f(b) iff a ⨁ b = s"""
|
||||||
|
# Copy contents to output qubits:
|
||||||
|
for control_qubit, target_qubit in zip(input_qubits, output_qubits):
|
||||||
|
yield cirq.CNOT(control_qubit, target_qubit)
|
||||||
|
|
||||||
|
# Create mapping:
|
||||||
|
if sum(secret_string): # check if the secret string is non-zero
|
||||||
|
# Find significant bit of secret string (first non-zero bit)
|
||||||
|
significant = list(secret_string).index(1)
|
||||||
|
|
||||||
|
# Add secret string to input according to the significant bit:
|
||||||
|
for j in range(len(secret_string)):
|
||||||
|
if secret_string[j] > 0:
|
||||||
|
yield cirq.CNOT(input_qubits[significant], output_qubits[j])
|
||||||
|
|
||||||
|
|
||||||
|
def make_simon_circuit(input_qubits, output_qubits, oracle):
|
||||||
|
"""Solves for the secret period s of a 2-to-1 function such that
|
||||||
|
f(x) = f(y) iff x ⨁ y = s
|
||||||
|
"""
|
||||||
|
|
||||||
|
c = cirq.Circuit()
|
||||||
|
|
||||||
|
# Initialize qubits.
|
||||||
|
c.append([cirq.H.on_each(*input_qubits)])
|
||||||
|
|
||||||
|
# Query oracle.
|
||||||
|
c.append(oracle)
|
||||||
|
|
||||||
|
# Measure in X basis.
|
||||||
|
c.append([cirq.H.on_each(*input_qubits), cirq.measure(*input_qubits, key="result")])
|
||||||
|
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
def post_processing(data, results):
|
||||||
|
"""Solves a system of equations with modulo 2 numbers"""
|
||||||
|
sing_values = sp.linalg.svdvals(results)
|
||||||
|
tolerance = 1e-5
|
||||||
|
if (
|
||||||
|
sum(sing_values < tolerance) == 0
|
||||||
|
): # check if measurements are linearly dependent
|
||||||
|
flag = True
|
||||||
|
null_space = sp.linalg.null_space(results).T[0]
|
||||||
|
solution = np.around(null_space, 3) # chop very small values
|
||||||
|
minval = abs(min(solution[np.nonzero(solution)], key=abs))
|
||||||
|
solution = (solution / minval % 2).astype(int) # renormalize vector mod 2
|
||||||
|
data.append(str(solution))
|
||||||
|
return flag
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user