From a512e5a534586f066642feeaf304db7a7c6fbac7 Mon Sep 17 00:00:00 2001 From: Arity-T Date: Tue, 30 Sep 2025 18:51:03 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=BB=D0=B3=D0=BE=D1=80=D0=B8=D1=82?= =?UTF-8?q?=D0=BC=20=D0=A1=D0=B0=D0=B9=D0=BC=D0=BE=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task5/main.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 task5/main.py diff --git a/task5/main.py b/task5/main.py new file mode 100644 index 0000000..d088ef4 --- /dev/null +++ b/task5/main.py @@ -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()