Compare commits

...

2 Commits

Author SHA1 Message Date
a512e5a534 Алгоритм Саймона 2025-09-30 18:51:03 +03:00
b85f09e680 Алгоритм Бернштейна–Вазирани 2025-09-30 18:50:00 +03:00
2 changed files with 195 additions and 0 deletions

91
task4/main.py Normal file
View 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
View 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()