Spaces:
Runtime error
Runtime error
| import numpy as np | |
| from qiskit import BasicAer, QuantumCircuit, QuantumRegister, ClassicalRegister, execute | |
| from qiskit import IBMQ | |
| # provider = IBMQ.load_account() | |
| # def misere_step(ones,piles): | |
| # # even number of piles of 1 eg (1,1,3,0) or (0,0,3,0) | |
| # if ones%2 == 0: | |
| # objects_to_remove = [] | |
| # removable_amount = 1 | |
| # for i in range(len(piles)): | |
| # if piles[i] > 1: | |
| # objects_to_remove.append(piles[i]-1) | |
| # else: | |
| # objects_to_remove.append(0) | |
| # # odd number of piles of 1 eg (1,1,3,1) | |
| # else: | |
| # objects_to_remove = [] | |
| # removable_amount = 1 | |
| # for i in range(len(piles)): | |
| # if piles[i] > 1: | |
| # objects_to_remove.append(piles[i]) | |
| # else: | |
| # objects_to_remove.append(0) | |
| # return objects_to_remove, removable_amount | |
| def get_piles_to_remove(piles): | |
| nim_sum = 0 | |
| for p in piles: | |
| nim_sum = nim_sum ^ p | |
| objects_to_remove = [] | |
| removable_amount = 0 | |
| for p in piles: | |
| new_p = p^nim_sum | |
| if new_p < p: | |
| objects_to_remove.append(p-new_p) | |
| removable_amount = removable_amount + 1 | |
| else: | |
| objects_to_remove.append(0) | |
| return objects_to_remove, removable_amount | |
| def custom_qft(data_qubits): | |
| qr_data = QuantumRegister(data_qubits) | |
| qc = QuantumCircuit(qr_data) | |
| i = data_qubits | |
| while i>=1: | |
| n = i - 1 | |
| qc.h(qr_data[n]) | |
| for qubit in range(n): | |
| qc.cp(np.pi/2**(n-qubit), qr_data[qubit], qr_data[n]) | |
| i = i-1 | |
| return qc | |
| def subroutine_add_const(data_qubits: int, const: int, to_gate=True): | |
| qc = QuantumCircuit(data_qubits) | |
| for i in range(data_qubits): | |
| angle = const*np.pi/(2**i) | |
| qc.p(angle,i) | |
| return qc.to_gate(label=" ["+str(const)+"] ") if to_gate else qc | |
| def diffusion_operation(qc, address, flag, removable_pile): | |
| def nim_oracle(qc,address,flag,removable_pile): | |
| # 0001 -> 001 | |
| if removable_pile[0] != 0: | |
| qc.x(address[1]) | |
| qc.x(address[2]) | |
| qc.mct(address[:],flag) | |
| qc.x(address[2]) | |
| qc.x(address[1]) | |
| # 0010 -> 010 | |
| if removable_pile[1] != 0: | |
| qc.x(address[0]) | |
| qc.x(address[2]) | |
| qc.mct(address[:],flag) | |
| qc.x(address[2]) | |
| qc.x(address[0]) | |
| # 0100 -> 011 | |
| if removable_pile[2] != 0: | |
| qc.x(address[2]) | |
| qc.mct(address[:],flag) | |
| qc.x(address[2]) | |
| # 1000 -> 100 | |
| if removable_pile[3] != 0: | |
| qc.x(address[0]) | |
| qc.x(address[1]) | |
| qc.mct(address[:],flag) | |
| qc.x(address[1]) | |
| qc.x(address[0]) | |
| qc.x(flag) | |
| qc.h(flag) | |
| qc.h(address[:]) | |
| nim_oracle(qc,address,flag,removable_pile) | |
| qc.h(address[:]) | |
| qc.x(address[:]) | |
| qc.h(address[2]) | |
| qc.mct(address[0:2], address[2]) | |
| qc.h(address[2]) | |
| qc.x(address[:]) | |
| qc.h(address[:]) | |
| def qc_process(qc,objects_to_remove,address,flag,piles,removable_pile,removable_count): | |
| if removable_count == 0: | |
| for i in range(len(removable_pile)): | |
| if piles[i] > 0: | |
| removable_pile[i] = 1 | |
| removable_count += 1 | |
| if removable_count == 4: | |
| removable_pile[removable_pile.index(min(removable_pile))] = 0 | |
| removable_count = removable_count - 1 | |
| qft_gate = custom_qft(3).to_gate() | |
| inverse_qft_gate = custom_qft(3).inverse().to_gate() | |
| if removable_count == 1: | |
| qc.swap(objects_to_remove[0],objects_to_remove[2]) | |
| qc.append(qft_gate,objects_to_remove[:]) | |
| # 0001 -> 001 | |
| if removable_pile[0] != 0: | |
| add_gate = subroutine_add_const(3,removable_pile[0]) | |
| qc.x(address[0]) | |
| # 0010 -> 010 | |
| elif removable_pile[1] != 0: | |
| add_gate = subroutine_add_const(3,removable_pile[1]) | |
| qc.x(address[1]) | |
| # 0100 -> 011 | |
| elif removable_pile[2] != 0: | |
| add_gate = subroutine_add_const(3,removable_pile[2]) | |
| qc.x(address[0]) | |
| qc.x(address[1]) | |
| # 1000 -> 100 | |
| elif removable_pile[3] != 0: | |
| add_gate = subroutine_add_const(3,removable_pile[3]) | |
| qc.x(address[2]) | |
| qc.append(add_gate,objects_to_remove[:]) | |
| qc.append(inverse_qft_gate,objects_to_remove[:]) | |
| qc.swap(objects_to_remove[0],objects_to_remove[2]) | |
| else: | |
| diffusion_operation(qc,address, flag, removable_pile) | |
| qc.swap(objects_to_remove[0],objects_to_remove[2]) | |
| qc.append(qft_gate,objects_to_remove[:]) | |
| for i,remove_amount in enumerate(removable_pile): | |
| if remove_amount != 0: | |
| bin_i = list(bin(i+1)[2:]) | |
| while len(bin_i) != 3: | |
| bin_i.insert(0,'0') | |
| bin_i = bin_i[::-1] | |
| for j in range(len(bin_i)): | |
| if bin_i[j] == '0': | |
| qc.x(address[j]) | |
| controlled_add_gate = subroutine_add_const(3,remove_amount).control(3) | |
| qc.append(controlled_add_gate,address[:]+objects_to_remove[:]) | |
| for j in range(len(bin_i)): | |
| if bin_i[j] == '0': | |
| qc.x(address[j]) | |
| qc.append(inverse_qft_gate,objects_to_remove[:]) | |
| qc.swap(objects_to_remove[0],objects_to_remove[2]) | |
| def get_quantum_move(piles, backend=None): | |
| # REMOVE MISERE STEP | |
| # ones = piles.count(1) | |
| # zeros = piles.count(0) | |
| # non_zeros = 4 - (ones+zeros) | |
| # # all zeros except one eg (0,0,0,7) OR some zeros some ones some non_zeros | |
| # # leave odd piles of 1s | |
| # if non_zeros == 1: | |
| # removable_pile, removable_count = misere_step(ones, piles) | |
| # else: | |
| # removable_pile, removable_count = get_piles_to_remove(piles) | |
| removable_pile, removable_count = get_piles_to_remove(piles) | |
| objects_to_remove = QuantumRegister(3,'piles') | |
| flag = QuantumRegister(1,'flag') | |
| output_piles = ClassicalRegister(3,'final_piles') | |
| address = QuantumRegister(3,'address') | |
| pick_pile = ClassicalRegister(3,'choose_pile') | |
| qc = QuantumCircuit(objects_to_remove,address,flag,output_piles,pick_pile) | |
| qc_process(qc,objects_to_remove,address,flag,piles,removable_pile,removable_count) | |
| qc.measure(address[:],pick_pile[:]) | |
| qc.measure(objects_to_remove[:],output_piles[:]) | |
| if backend == None: | |
| backend = BasicAer.get_backend('qasm_simulator') | |
| # backend = provider.backends.ibmq_qasm_simulator | |
| job = execute(qc,backend,shots=500) | |
| result = job.result() | |
| counts = result.get_counts() | |
| try: | |
| qc_move = (counts.most_frequent()) | |
| except Exception as e: | |
| print(e) | |
| vals = list(dict(counts).values()) | |
| max_count = max(vals,key=vals.count) | |
| for key in counts: | |
| if counts[key] == max_count: | |
| qc_move = key | |
| break | |
| board_choice = qc_move.split(' ')[0] | |
| board_choice = int(board_choice,2) - 1 | |
| print("Pick from:",board_choice+1) | |
| board_state = qc_move.split(' ')[1] | |
| board_state = board_state[::-1] | |
| amount = int(board_state,2) | |
| print("Amount:", amount) | |
| return board_choice,amount | |