def test_hologram(silent=True): if not silent: print("\nTesting Hologram") S = 2 qpm = 2 setup = PhotonicSetup(pathnames=['a'], S=S, qpm=qpm) setup.add_hologram(path='a') states = [ PhotonicStateVector.from_string( paths=setup.paths, string="1.0|20000>_a"), # 2 photons in -2 PhotonicStateVector.from_string( paths=setup.paths, string="1.0|02000>_a"), # 2 photons in -1 PhotonicStateVector.from_string( paths=setup.paths, string="1.0|00200>_a"), # 2 photons in 0 PhotonicStateVector.from_string( paths=setup.paths, string="1.0|00020>_a"), # 2 photons in 1 PhotonicStateVector.from_string( paths=setup.paths, string="1.0|00002>_a"), # 2 photons in 2 ] for i, start in enumerate(states): end = setup.simulate_wavefunction(initial_state=start) expected = states[(i + 1) % 5] if not silent: print("start =", start) print("end =", end) print("expected=", expected) assert (end == expected)
def test_mirror(silent=True): if not silent: print("\nTesting Mirror") S = 2 qpm = 2 setup = PhotonicSetup(pathnames=['a'], S=S, qpm=qpm) paths = setup.paths setup.add_mirror(path='a') statesx = [ PhotonicStateVector.from_string( paths=paths, string="1.0|20000>_a"), # 2 photons in -2 PhotonicStateVector.from_string( paths=paths, string="1.0|02000>_a"), # 2 photons in -1 PhotonicStateVector.from_string( paths=paths, string="1.0|00200>_a"), # 2 photons in 0 PhotonicStateVector.from_string( paths=paths, string="1.0|00020>_a"), # 2 photons in 1 PhotonicStateVector.from_string( paths=paths, string="1.0|00002>_a"), # 2 photons in 2 ] statesy = [ PhotonicStateVector.from_string(paths=paths, string="1.0|21301>_a"), PhotonicStateVector.from_string( paths=paths, string="1.0|33000>_a"), # 2 photons in -1 PhotonicStateVector.from_string( paths=paths, string="1.0|21312>_a"), # 2 photons in 0 PhotonicStateVector.from_string( paths=paths, string="1.0|00033>_a"), # 2 photons in 1 PhotonicStateVector.from_string( paths=paths, string="1.0|10312>_a"), # 2 photons in 2 ] for states in [statesx, statesy]: for i, start in enumerate(states): end = setup.simulate_wavefunction(initial_state=start) expected = states[-(i + 1)] if not silent: print( "Mirror Circuit:\n", SimulatorCirq().create_circuit( abstract_circuit=setup.setup)) print("start =", start) print("end =", end) print("expected=", expected) assert (end == expected)
def test_SPDC(silent=False): # Qubit Wavefunction for the expeced state: # here are the three basis functions for the -2,-1,0,1,2 mode representation # where each mode has 2 qubits # mp, minus plus, pm, plus minus, zz, zero zero def make_SPDC_state_vector(S, paths) -> PhotonicStateVector: """ Normalized SPDC State vector :param S: Spin number ( Modes will be -S ... 0 ... +S) :return: SPDC State in 2S+1 modes """ assert (len(paths.keys()) == 2) def one_photon_path(occ_mode: int) -> str: key = S + occ_mode tmp = ["0"] * (2 * S + 1) tmp[key] = "1" return "".join(tmp) def term(a: int, b: int, coeff: float = 1.0 / sqrt(3)) -> str: return "+" + str(coeff) + "|" + one_photon_path( occ_mode=a) + ">_a|" + one_photon_path(occ_mode=b) + ">_b" return PhotonicStateVector.from_string(paths=paths, string=term(1, -1) + term(0, 0) + term(-1, 1)) S = 2 qpm = 2 setup = PhotonicSetup(pathnames=['a', 'b'], S=S, qpm=qpm) paths = setup.paths expected = make_SPDC_state_vector(S=S, paths=paths) setup.prepare_SPDC_state(path_a='a', path_b='b') end = setup.simulate_wavefunction() if not silent: print("S =", S) print("q per m =", qpm) print("expected=", expected) print("end =", end) assert (end == expected)
def test_projector(qpm): S = 1 setup = PhotonicSetup(pathnames=['a', 'b'], S=S, qpm=qpm) state = PhotonicStateVector.from_string( paths=setup.paths, string="0.7071|001>_a|111>_b+0.7071|010>_a|111>_b") setup.prepare_unary_type_state(state=state) setup.add_one_photon_projector(path='a') wfn = setup.simulate_wavefunction() assert (str( PhotonicStateVector.from_string( paths=setup.paths, string="1.0|000>_a|111>_b")) == str(wfn)) counts = setup.sample(samples=100) reduced_paths = PhotonicPaths(path_names=['b'], S=S, qpm=qpm) assert (str( PhotonicStateVector.from_string(paths=reduced_paths, string="100|111>_b")) == str(counts))
def test_projector_prep(qpm, silent=True): S = 1 angles = [1.2309594173407747, 1.5707963267948966] setup = PhotonicSetup(pathnames=['a'], S=S, qpm=qpm) setup.add_parametrized_one_photon_projector(path='a', angles=angles, daggered=False) wfn = setup.simulate_wavefunction() result = PhotonicStateVector.from_string( paths=setup.paths, string="+ 0.5774|001>_a + 0.5774|010>_a + 0.5774|100>_a") if not silent: setup.print_circuit() print("wfn = ", wfn) print("expected= ", result) assert (str(result) == str(wfn))
def test_dove_prism(inout, silent=False): # dove prism is implemented with a global phase # but for this tests this is one # stupid qubit intitalization, but it makes the test better S = 1 qpm = 2 t = 1.0 setup = PhotonicSetup(pathnames=['a'], S=S, qpm=qpm) setup.add_doveprism(path='a', t=t) istate = setup.initialize_state(state=inout[0]) ostate = setup.initialize_state(state=inout[1]) end = setup.simulate_wavefunction(initial_state=istate) if not silent: print(setup.setup) print("t =", t) print("start =", istate) print("end =", end) print("expected=", ostate) assert (end == ostate)
from photonic import PhotonicSetup # Directly prepare the 332 state in the digital encoding using quantum gates # This is used in the the last part of the optimization # Note that this is not the optical setup if __name__ == "__main__": S = 1 # Modes will run from -S ... 0 ... +S (orbital angular momentum) qpm = 2 # Qubits per mode setup = PhotonicSetup(pathnames=['a', 'b', 'c'], S=S, qpm=qpm) setup.prepare_332_state(path_a='a', path_b='b', path_c='c', daggered=False) print("preparation circuti:\n", setup.setup) wfn = setup.simulate_wavefunction() print("Photonic Wavefunction = ", wfn) print("Qubit Wavefunction = ", wfn.state)
def test_332(silent=False): # Qubit Wavefunction for the expeced state: # In 3 Paths with -1 0 +1 mode, each mode with 2 qubits # Paths are constructed as # A(-1 0 1) B(-1 0 1) C(-1 0 1) # |XXXXXX|XXXXXX|XXXXXX> # The 332 State in Photonic Notation (one photon in each mode noted as |abc> where a = occupied mode in path a) # |state> = |1 -1 1> + |0 0 0> + |-1 1 1> # 332 State in Qudit notation # |state> = |0 0 1>_a|1 0 0>_b|0 0 1>_c # +|0 1 0>_a|0 1 0>_b|0 1 0>_c # +|1 0 0>_a|0 0 1>_b|0 0 1>_c # The 332 State for 2-Qubits per mode is # |state>= | 00 00 01 | 01 00 00 | 00 00 01 > # +| 00 01 00 | 00 01 00 | 00 01 00 > # +| 01 00 00 | 00 00 01 | 00 00 01 > def make_332_state_vector(S, paths) -> PhotonicStateVector: """ Normalized 332 State vector :param S: Spin number ( Modes will be -S ... 0 ... +S) :return: 332 State in 2S+1 modes """ def one_photon_path(occ_mode: int) -> str: key = S + occ_mode tmp = ["0"] * (2 * S + 1) tmp[key] = "1" return "".join(tmp) def term(a: int, b: int, c: int, coeff: float = 1.0 / sqrt(3)) -> str: return "+" + str(coeff) + "|" + one_photon_path( occ_mode=a) + ">_a|" + one_photon_path( occ_mode=b) + ">_b|" + one_photon_path(occ_mode=c) + ">_c" return PhotonicStateVector.from_string(paths=paths, string=term(-1, 1, -1) + term(0, 0, 0) + term(-1, -1, 1)) for S in [1, 2]: for qpm in [1, 2]: # path_a = dict() # path_b = dict() # path_c = dict() # qubit_counter = 0 # # for path in [path_a, path_b, path_c]: # for m in range(-S, S+1, 1): # path[m] = PhotonicMode(qubits=[q for q in range(qubit_counter, qubit_counter + n_qubits_per_mode)], # name=str(m)) # qubit_counter = qubit_counter + n_qubits_per_mode setup = PhotonicSetup(pathnames=['a', 'b', 'c'], S=S, qpm=qpm) paths = setup.paths expected = make_332_state_vector(S=S, paths=paths) setup.prepare_332_state(path_a='a', path_b='b', path_c='c') if not silent: print(setup.setup) print("Paths:\n", paths) end = setup.simulate_wavefunction() if not silent: print("S =", S) print("q per m =", qpm) print("end =", end) print("expected=", expected) assert (end == expected)
""" # If you want to change S and qpm you need to think about new encodings for the P1 projector S = 1 # Can not be changed for this example. Hamiltonians are wrong otherwise qpm = 1 # Can not be changed for this example. Hamiltonians are wrong otherwise trotter_steps = 1 # number of trotter steps for the BeamSplitter (for S=1 and qpm=1, one trotter step is fine) if __name__ == "__main__": param_dove = tq.Variable( name="t" ) # the dove prism is already defined in units of pi within PhotonicSetup angle0 = tq.numpy.pi * tq.Variable(name="angle0") # angles in units of pi angle1 = tq.numpy.pi * tq.Variable(name="angle1") # angles in units of pi # Use the PhotonicSetup helper class to initialize the mapped parametrized photonic setup setup = PhotonicSetup(pathnames=['a', 'b', 'c', 'd'], S=S, qpm=qpm) setup.prepare_SPDC_state(path_a='a', path_b='b') setup.prepare_SPDC_state(path_a='c', path_b='d') setup.add_beamsplitter(path_a='b', path_b='c', t=0.25, steps=trotter_steps) setup.add_doveprism(path='c', t=param_dove) setup.add_beamsplitter(path_a='b', path_b='c', t=0.25, steps=trotter_steps) setup.add_parametrized_one_photon_projector(path='a', angles=[angle0, angle1]) # this is the mapped photonic setup U_pre = setup.setup # now we will add the optimization parts which are only done on the digital quantum computer setup = PhotonicSetup(pathnames=['a', 'b', 'c', 'd'], S=S, qpm=qpm) # we have included the 332 state preparation on the digital machine into the PhotonicSetup class # for convenience
from photonic import PhotonicSetup, PhotonicStateVector import tequila as tq if __name__ == "__main__": """ Set The Parameters here: """ S = 0 # Modes will run from -S ... 0 ... +S qpm = 2 # Qubits per mode initial_state = "|1>_a|1>_b" # Notation has to be consistent with your S trotter_steps = 20 # number of trotter steps for the BeamSplitter samples = 1000 # number of samples to simulate simulator = None # Pick the Simulator (None -> let tequila do it) t = 0.25 # beam-splitter parameter setup = PhotonicSetup(pathnames=['a', 'b'], S=S, qpm=qpm) # the beam splitter is parametrized as phi=i*pi*t setup.add_beamsplitter(path_a='a', path_b='b', t=t, steps=trotter_steps) # need explicit circuit for initial state state = setup.initialize_state(state=initial_state) # can only do product states right now, alltough more general ones are possible # with code adaption Ui = tq.QCircuit() assert (len(state.state) == 1) key = [k for k in state.state.keys()][0] for i, q in enumerate(key.array): if q == 1: Ui += tq.gates.X(target=i)