Giter VIP home page Giter VIP logo

squanch's Introduction

Simulator for quantum networks and channels

The Simulator for Quantum Networks and Channels (SQUANCH) is an open-source Python library for creating parallelized simulations of distributed quantum information processing. The framework includes many features of a general-purpose quantum computing simulator, but it is optimized specifically for simulating quantum networks. It includes functionality to allow users to easily design complex multi-party quantum networks, extensible classes for modeling noisy quantum channels, and a multiprocessed NumPy backend for performant simulations.

A schematic overview of the modules available in SQUANCH is shown below. (Refer to the documentation or the whitepaper for more details.)

Overview of SQUANCH framework structure

SQUANCH is developed as part of the Intelligent Quantum Networks and Technologies (INQNET) program, a collaboration between AT&T and the California Institute of Technology.

Documentation

Documentation for this package is available at the documentation website or as a pdf manual. We encourage interested users to read the whitepaper for the SQUANCH platform, "A distributed simulation framework for quantum networks and channels" (arXiv: 1808.07047), which provides an overview of the framework and a primer on quantum information.

Installation

You can install SQUANCH directly using the Python package manager, pip:

pip install squanch

If you don't have pip, you can get it using easy_install pip.

Demonstrations

Demonstrations of various quantum protocols can be found in the demos folder and in the documentation:

Example: quantum interception attack

As an example to put in this readme, let's consider a scenario where Alice wants to send data to Bob. For security, she transmits her message through quantum superdense coding. In this scenario, shown below as a circuit diagram, we have four Agents, who act as follows:

  • Charlie generates entangled pairs of qubits, which he sends to Alice and Bob.
  • Alice receives Charlie's qubit. She encodes two bits of her data in it and sends it Bob.
  • Bob receives the qubits from Charlie and Alice. He operates jointly on them and measures them to reconstruct Alice's two bits of information.
  • However, the fourth agent, Eve, wants to know Alice's data. She intercepts every qubit Alice sends to Bob, measures it, and re-transmits it to Bob, hoping he won't notice.

An implementation of this scenario in SQUANCH is given below.

import numpy as np
import matplotlib.image as image
from squanch import *

class Charlie(Agent):
    '''Charlie sends Bell pairs to Alice and Bob'''
    def run(self):
        for qsys in self.qstream:
            a, b = qsys.qubits
            H(a)
            CNOT(a, b)
            self.qsend(alice, a)
            self.qsend(bob, b)
            
class Alice(Agent):
    '''Alice tries to send data to Bob, but Eve intercepts'''
    def run(self):
        for _ in self.qstream:
            bit1 = self.data.pop(0)
            bit2 = self.data.pop(0)
            q = self.qrecv(charlie)
            if bit2 == 1: X(q)
            if bit1 == 1: Z(q)
            # Alice unknowingly sends the qubit to Eve
            self.qsend(eve, q) 
            
class Eve(Agent):
    '''Eve naively tries to intercept Alice's data'''
    def run(self):
        bits = [] 
        for _ in self.qstream:
            a = self.qrecv(alice)
            bits.append(a.measure())
            self.qsend(bob, a)
        self.output(bits)
            
class Bob(Agent):
    '''Bob receives Eve's intercepted data'''
    def run(self):
        bits = []
        for _ in self.qstream:
            a = self.qrecv(eve)
            c = self.qrecv(charlie)
            CNOT(a, c)
            H(a)
            bits.extend([a.measure(), c.measure()])
        self.output(bits)
    
# Load Alice's data (an image) and serialize it to a bitstream
img = image.imread("docs/source/img/foundryLogo.bmp") 
bitstream = list(np.unpackbits(img))

# Prepare an appropriately sized quantum stream
qstream = QStream(2, int(len(bitstream) / 2))
out = Agent.shared_output()

# Instantiate agents
alice = Alice(qstream, out, data=bitstream)
bob = Bob(qstream, out)
charlie = Charlie(qstream, out)
eve = Eve(qstream, out)

# Connect the agents to form the network
alice.qconnect(bob)
alice.qconnect(eve)
alice.qconnect(charlie)
bob.qconnect(charlie)
bob.qconnect(eve)

# Run the simulation
Simulation(alice, eve, bob, charlie).run()

# Display the images Alice sent, Eve intercepted, and Bob received
# (Plotting code omitted for brevity; results shown below)

Images sent by Alice, intercepted by Eve, and received by Bob

Citation

If you are doing research using SQUANCH, please cite our whitepaper:

B. Bartlett, "A distributed simulation framework for quantum networks and channels," arXiv: 1808.07047 [quant-ph], Aug. 2018.

squanch's People

Contributors

bencbartlett avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

squanch's Issues

TypeError: cannot pickle 'weakref' object

When I executed the 4th code cell in the 'quantum-teleportation.ipynb', I got the following error.

TypeError                                 Traceback (most recent call last)
<ipython-input-5-6b43832d0e46> in <module>
     15 # Run everything
     16 alice.start()
---> 17 bob.start()
     18 alice.join()
     19 bob.join()

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/process.py in start(self)
    119                'daemonic processes are not allowed to have children'
    120         _cleanup()
--> 121         self._popen = self._Popen(self)
    122         self._sentinel = self._popen.sentinel
    123         # Avoid a refcycle if the target function holds an indirect

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/context.py in _Popen(process_obj)
    222     @staticmethod
    223     def _Popen(process_obj):
--> 224         return _default_context.get_context().Process._Popen(process_obj)
    225 
    226 class DefaultContext(BaseContext):

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/context.py in _Popen(process_obj)
    281         def _Popen(process_obj):
    282             from .popen_spawn_posix import Popen
--> 283             return Popen(process_obj)
    284 
    285     class ForkServerProcess(process.BaseProcess):

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_spawn_posix.py in __init__(self, process_obj)
     30     def __init__(self, process_obj):
     31         self._fds = []
---> 32         super().__init__(process_obj)
     33 
     34     def duplicate_for_child(self, fd):

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_fork.py in __init__(self, process_obj)
     17         self.returncode = None
     18         self.finalizer = None
---> 19         self._launch(process_obj)
     20 
     21     def duplicate_for_child(self, fd):

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/popen_spawn_posix.py in _launch(self, process_obj)
     45         try:
     46             reduction.dump(prep_data, fp)
---> 47             reduction.dump(process_obj, fp)
     48         finally:
     49             set_spawning_popen(None)

/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/multiprocessing/reduction.py in dump(obj, file, protocol)
     58 def dump(obj, file, protocol=None):
     59     '''Replacement for pickle.dump() using ForkingPickler.'''
---> 60     ForkingPickler(file, protocol).dump(obj)
     61 
     62 #

TypeError: cannot pickle 'weakref' object

Does anybody have an idea to remove this error?

1 way quantum computation not working

Hi Ben!

I've been having a lot of trouble lately with Squanch. This may very well be because I for some reason am blind to an obvious bug in my code, but this also may be because of a problem with the squanch CU gate, H gate or qsys.

What I'm trying to code is somthing pretty close to usual quantum teleportation. We start in the 5 qubit state

|p> - |+> - |+> - |+> - |+>

Where p is some arbitrary state and |+> is the usual + state and - represents CZ entanglement (so the CZ gate was applied to neighboring qubits). According to 1 way quantum computation, you should be able to measure each qubit 0 to 3 (0 indexing form the left) in the X basis, getting the results s_0, s_1, s_2, s_3 and be left with the rightmost qubit in the state X^{s_1 + s_3}Z^{s_0 + s_2}| p >

I was able to implement this in pyquil. Here is the code:

'''
practice.py

testing to see if I can implement a 1 way quantum computer works in pyquil
'''

from pyquil.quil import Program
from pyquil.gates import *
from pyquil.api import QVMConnection

# measures qubit at index i in the basis of X
def measureX(i):
	p = Program()
	p.inst(H(i)).measure(i, i)
	return p

# after this propagation, we need to correct the final qubit
# the final qubit will be in the state X^{s_1 + s_3}Z^{s_0 + s_2}|\psi>
# where s_i is the result of measuring qubit i using measureX
# and |\psi> is the initial state of qubit 0
# after the steps prepareEntanglements() + measureX(0)  + measureX(1) + measureX(2) + measureX(3)
# in transportation

# After the corrections have been made, we should leave qubit 4 in the state |\psi>
def correctAndMeasure(i):
	thenX_branch = Program(X(i))
	elseX_branch = Program()
	thenZ_branch = Program(Z(i))
	elseZ_branch = Program()

	p = Program()
	p.inst().if_then(1, thenX_branch, elseX_branch).if_then(3, thenX_branch, elseX_branch).if_then(0, thenZ_branch, elseZ_branch).if_then(2, thenZ_branch, elseZ_branch).measure(i, i)
	return p

# prepares the state:
# |0> - |+> - |+> - |+> - |+>
# where - represents CZ entanglements and |1> and |+> are as usual
def prepareEntanglements():
	state_prep = Program().inst(I(0), H(1), H(2), H(3), H(4), CZ(0, 1), CZ(1, 2), CZ(2, 3), CZ(3, 4))
	return state_prep


if __name__ == "__main__":
	qvm = QVMConnection()
	
	# wavefunction = qvm.wavefunction(state_prep)
	# print(wavefunction)

	trasportation = prepareEntanglements() + measureX(0)  + measureX(1) + measureX(2) + measureX(3) + correctAndMeasure(4)

	print(trasportation)
	results = qvm.run(trasportation, [0, 1, 2, 3, 4], 10)
	print(results)

	# see if it all worked out
	for run in results:
		if run[4] == 1:
			print("Failed")
			quit(1)
	print("Okay cool, so it looks like it is working")

But the same sort of implementation in squanch doesn't seem to be working. Here is my code for that:

'''
transporting.py

Working with different lengths of transportation

'''



from squanch import *
import numpy as np

_Z = np.array([[1, 0],[0, -1]])

def transport4(a, b, c, d, e):
	# measures qubit at index i in the basis of X
	H(a)
	a_res = a.measure()
	H(b)
	b_res = b.measure()
	H(c)
	c_res = c.measure()
	H(d)
	d_res = d.measure()

	# after this propagation, we need to correct the final qubit
	# the final qubit will be in the state X^{s_1 + s_3}Z^{s_0 + s_2}|\psi>
	# where s_i is the result of measuring qubit i using measureX
	# and |\psi> is the initial state of qubit 0
	# after the steps prepareEntanglements() + measureX(0)  + measureX(1) + measureX(2) + measureX(3)
	# in transportation

	# After the corrections have been made, we should leave qubit 4 in the state |\psi>
	if (b_res == 1 or d_res == 1) and not (b_res == 1 and d_res == 1):
		# print("applied X")
		X(e)
	if (a_res == 1 or c_res == 1) and not (a_res == 1 and c_res == 1):
		# print("applied Z")
		Z(e)
	return a_res, b_res, c_res, d_res

# our goal here is to do a simple 1 way Quantum computation
def testtransportlen4():
	results = []

	for _ in range(1):
		qsys = QSystem(5)
		a, b, c, d, e = qsys.qubits
		# prepares the state:
		# |0> - |+> - |+> - |+> - |+>
		# where - represents CZ entanglements and |1> and |+> are as usual
		I(a)
		H(b)
		H(c)
		H(d)
		H(e)
		CU(a, b, _Z)
		CU(b, c, _Z)
		CU(c, d, _Z)
		CU(d, e, _Z)
		# measure
		a_res, b_res, c_res, d_res = transport4(a, b, c, d, e)

		e_res = c.measure()

		results.append((a_res, b_res, c_res, d_res, e_res))

	print(results)

if __name__ == "__main__":
	testtransportlen4()

I may just be using Squanch wrong, and so if that is so, I'm sorry for bothering you. Haha, I will be digging into this problem now in more depth, looking at the implementation of CU and looking at the matrices I am making more closely for the time being now, but I thought I would ask you to make sure that I was using Squanch correctly.

Also I apologize if my code is very messing, it is all scrap code. If you would like more comments or if you want a better organization of the code, just ask.

Thanks!

Code test error

First of all, I wish you success in your work.
I get the following error when I test the code.
I'd appreciate it if you could help me.
Thank you

BrokenPipeError Traceback (most recent call last)
in
69
70 # Run the simulation
---> 71 Simulation(alice, eve, bob, charlie).run()
72
73 # Display the images Alice sent, Eve intercepted, and Bob received

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\site-packages\squanch\simulate.py in run(self, monitor_progress)
76
77 for agent in self.agents:
---> 78 agent.start()
79
80 if monitor_progress:

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\process.py in start(self)
103 'daemonic processes are not allowed to have children'
104 _cleanup()
--> 105 self._popen = self._Popen(self)
106 self._sentinel = self._popen.sentinel
107 # Avoid a refcycle if the target function holds an indirect

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\context.py in _Popen(process_obj)
221 @staticmethod
222 def _Popen(process_obj):
--> 223 return _default_context.get_context().Process._Popen(process_obj)
224
225 class DefaultContext(BaseContext):

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\context.py in _Popen(process_obj)
320 def _Popen(process_obj):
321 from .popen_spawn_win32 import Popen
--> 322 return Popen(process_obj)
323
324 class SpawnContext(BaseContext):

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\popen_spawn_win32.py in init(self, process_obj)
63 try:
64 reduction.dump(prep_data, to_child)
---> 65 reduction.dump(process_obj, to_child)
66 finally:
67 set_spawning_popen(None)

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\reduction.py in dump(obj, file, protocol)
58 def dump(obj, file, protocol=None):
59 '''Replacement for pickle.dump() using ForkingPickler.'''
---> 60 ForkingPickler(file, protocol).dump(obj)
61
62 #

BrokenPipeError: [Errno 32] Broken pipe

Phase Shift Gate

Hi Ben!

Maybe it would be beneficial to add the phase shift gate to the provided gates!

Such as:

_0 = np.array([[1, 0],[0, 0]])
_1 = np.array([[0, 0],[0, 1]])
def Phi(qubit, angle):
	'''
	Applies the single qubit phase shift operator to the specified qubit, updating the qsystem state.
    '''
	gate = _0 + np.exp(1j * angle) * _1
	qubit.qsystem.apply(expand(gate, qubit.index, qubit.qsystem.num_qubits, "Phi" + str(angle / np.pi)))

Or even an interface that allows for easily programmable gates!

If you are too busy to add them I'd be happy to add these

Thanks

Small typos in Documentation

Hi Ben!

There are just two small bugs that I found in your sample code that you may want to change:

both are in Getting Started and both are just variable names being inconsistent, so not big.

First I believe

msg = "Hello, Bob!"
bits = string_to_bits(message)

Should become

msg = "Hello, Bob!" 
bits = string_to_bits(msg)

Similarly later

mem = Agent.shared_hilbert_space(1, len(msgBits))  
out = Agent.shared_output()

should become

mem = Agent.shared_hilbert_space(1, len(bits))   
out = Agent.shared_output()

BrokenPipeError: [Errno 32] Broken pipe

In my thesis I wanted to test the application to send a data on the Quantum Network.
I get the following error.
I'd appreciate it if you could help me. In my thesis I will cite your work.

BrokenPipeError Traceback (most recent call last)
in
69
70 # Run the simulation
---> 71 Simulation(alice, eve, bob, charlie).run()
72
73 # Display the images Alice sent, Eve intercepted, and Bob received

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\site-packages\squanch\simulate.py in run(self, monitor_progress)
76
77 for agent in self.agents:
---> 78 agent.start()
79
80 if monitor_progress:

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\process.py in start(self)
103 'daemonic processes are not allowed to have children'
104 _cleanup()
--> 105 self._popen = self._Popen(self)
106 self._sentinel = self._popen.sentinel
107 # Avoid a refcycle if the target function holds an indirect

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\context.py in _Popen(process_obj)
221 @staticmethod
222 def _Popen(process_obj):
--> 223 return _default_context.get_context().Process._Popen(process_obj)
224
225 class DefaultContext(BaseContext):

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\context.py in _Popen(process_obj)
320 def _Popen(process_obj):
321 from .popen_spawn_win32 import Popen
--> 322 return Popen(process_obj)
323
324 class SpawnContext(BaseContext):

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\popen_spawn_win32.py in init(self, process_obj)
63 try:
64 reduction.dump(prep_data, to_child)
---> 65 reduction.dump(process_obj, to_child)
66 finally:
67 set_spawning_popen(None)

c:\program files (x86)\microsoft visual studio\shared\python36_64\lib\multiprocessing\reduction.py in dump(obj, file, protocol)
58 def dump(obj, file, protocol=None):
59 '''Replacement for pickle.dump() using ForkingPickler.'''
---> 60 ForkingPickler(file, protocol).dump(obj)
61
62 #

BrokenPipeError: [Errno 32] Broken pipe

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.