diff --git a/docs/examples/notebooks/basic_quantum.ipynb b/docs/examples/notebooks/basic_quantum.ipynb
index 2b48dc1..cab53ad 100644
--- a/docs/examples/notebooks/basic_quantum.ipynb
+++ b/docs/examples/notebooks/basic_quantum.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"
Basic Symbolic Quantum Mechanics
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":7},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Bras and Kets
"},{"code":"phi, psi = Ket('phi'), Ket('psi')\nalpha, beta = symbols('alpha beta', complex=True)","cell_type":"code","prompt_number":9},{"code":"state = alpha*psi + beta*phi; state\n","cell_type":"code","prompt_number":10},{"code":"ip = Dagger(state)*state; ip\n","cell_type":"code","prompt_number":11},{"code":"qapply(expand(ip))\n","cell_type":"code","prompt_number":12},{"cell_type":"text","text":"Operators
"},{"code":"A = Operator('A')\nB = Operator('B')\nC = Operator('C')","cell_type":"code","prompt_number":13},{"code":"A*B == B*A\n","cell_type":"code","prompt_number":14},{"code":"expand((A+B)**2)","cell_type":"code","prompt_number":15},{"code":"comm = Commutator(A,B); comm\n","cell_type":"code","prompt_number":16},{"code":"comm.doit()","cell_type":"code","prompt_number":17},{"code":"comm = Commutator(A*B,B+C); comm","cell_type":"code","prompt_number":18},{"code":"comm.expand(commutator=True)","cell_type":"code","prompt_number":19},{"code":"_.doit().expand()\n","cell_type":"code","prompt_number":20},{"code":"Dagger(_)","cell_type":"code","prompt_number":21},{"code":"%notebook save basic_quantum.ipynb","cell_type":"code","prompt_number":16},{"code":"%notebook load quantum_computing.ipynb","cell_type":"code","prompt_number":19}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Basic Symbolic Quantum Mechanics
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Bras and Kets
"},{"cell_type":"text","text":"Create symbolic states"},{"code":"phi, psi = Ket('phi'), Ket('psi')\nalpha, beta = symbols('alpha beta', complex=True)","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"Create a superposition"},{"code":"state = alpha*psi + beta*phi; state\n","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"Dagger the superposition and multiply the original"},{"code":"ip = Dagger(state)*state; ip\n","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Distribute"},{"code":"qapply(expand(ip))\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"Operators
"},{"cell_type":"text","text":"Create symbolic operators"},{"code":"A = Operator('A')\nB = Operator('B')\nC = Operator('C')","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"Test commutativity"},{"code":"A*B == B*A\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Distribute A+B squared"},{"code":"expand((A+B)**2)","cell_type":"code","prompt_number":9},{"cell_type":"text","text":"Create a commutator"},{"code":"comm = Commutator(A,B); comm\n","cell_type":"code","prompt_number":10},{"cell_type":"text","text":"Carry out the commutator"},{"code":"comm.doit()","cell_type":"code","prompt_number":11},{"cell_type":"text","text":"Create a more fancy commutator"},{"code":"comm = Commutator(A*B,B+C); comm","cell_type":"code","prompt_number":12},{"cell_type":"text","text":"Expand the commutator"},{"code":"comm.expand(commutator=True)","cell_type":"code","prompt_number":13},{"cell_type":"text","text":"Carry out and expand the commutators"},{"code":"_.doit().expand()\n","cell_type":"code","prompt_number":14},{"cell_type":"text","text":"Take the dagger"},{"code":"Dagger(_)","cell_type":"code","prompt_number":15},{"code":"%notebook save basic_quantum.ipynb","cell_type":"code","prompt_number":16},{"code":"%notebook load quantum_computing.ipynb","cell_type":"code","prompt_number":19}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/decompose.ipynb b/docs/examples/notebooks/decompose.ipynb
index 23e59a5..586e6f4 100644
--- a/docs/examples/notebooks/decompose.ipynb
+++ b/docs/examples/notebooks/decompose.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Gate Decomposition
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Example 1
"},{"code":"CY10 = CGate(1, Y(0)); CY10\n","cell_type":"code","prompt_number":3},{"code":"CY10.decompose()\n","cell_type":"code","prompt_number":4},{"code":"circuit_plot(CY10.decompose(), nqubits=2)","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Example 2
"},{"code":"CZ01 = CGate(0, Z(1)); CZ01\n","cell_type":"code","prompt_number":6},{"code":"CZ01.decompose()\n","cell_type":"code","prompt_number":7},{"code":"circuit_plot(CZ01.decompose(), nqubits=2)","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Example 3
"},{"code":"SWAP10 = SWAP(1, 0); SWAP10\n","cell_type":"code","prompt_number":9},{"code":"SWAP10.decompose()","cell_type":"code","prompt_number":10},{"code":"circuit_plot(SWAP10.decompose(), nqubits=2)","cell_type":"code","prompt_number":11},{"cell_type":"text","text":"All together now
"},{"code":"gates = [CGate(1,Y(0)), CGate(0,Z(1)), SWAP(1, 0)]","cell_type":"code","prompt_number":12},{"code":"for g in gates:\n dg = g.decompose()\n display(Eq(g, dg))\n circuit_plot(g, nqubits=2)\n circuit_plot(dg, nqubits=2) ","cell_type":"code","prompt_number":13},{"code":"%notebook save decompose.ipynb","cell_type":"code","prompt_number":30},{"code":"%notebook load gate_rules.ipynb","cell_type":"code","prompt_number":53}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Gate Decomposition
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Example 1
"},{"cell_type":"text","text":"Create a symbolic controlled-Y gate"},{"code":"CY10 = CGate(1, Y(0)); CY10\n","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"Decompose it into elementary gates and plot it"},{"code":"CY10.decompose()\n","cell_type":"code","prompt_number":4},{"code":"circuit_plot(CY10.decompose(), nqubits=2)","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Example 2
"},{"cell_type":"text","text":"Create a controlled-Z gate"},{"code":"CZ01 = CGate(0, Z(1)); CZ01\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"Decompose and plot it"},{"code":"CZ01.decompose()\n","cell_type":"code","prompt_number":7},{"code":"circuit_plot(CZ01.decompose(), nqubits=2)","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Example 3
"},{"cell_type":"text","text":"Create a SWAP gate"},{"code":"SWAP10 = SWAP(1, 0); SWAP10\n","cell_type":"code","prompt_number":9},{"cell_type":"text","text":"Decompose and plot it"},{"code":"SWAP10.decompose()","cell_type":"code","prompt_number":10},{"code":"circuit_plot(SWAP10.decompose(), nqubits=2)","cell_type":"code","prompt_number":11},{"cell_type":"text","text":"All together now
"},{"code":"gates = [CGate(1,Y(0)), CGate(0,Z(1)), SWAP(1, 0)]","cell_type":"code","prompt_number":12},{"code":"for g in gates:\n dg = g.decompose()\n display(Eq(g, dg))\n circuit_plot(g, nqubits=2)\n circuit_plot(dg, nqubits=2) ","cell_type":"code","prompt_number":13},{"code":"%notebook save decompose.ipynb","cell_type":"code","prompt_number":30},{"code":"%notebook load gate_rules.ipynb","cell_type":"code","prompt_number":53}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/density_matrix.ipynb b/docs/examples/notebooks/density_matrix.ipynb
index f08a09d..5f84e93 100644
--- a/docs/examples/notebooks/density_matrix.ipynb
+++ b/docs/examples/notebooks/density_matrix.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Symbolic Density Matrices
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":2},{"code":"from sympy import sqrt, symbols, Rational, S\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot\nfrom sympy.physics.quantum.densityOp import *","cell_type":"code","prompt_number":4},{"code":"state = Density([Qubit('00'),0.5],[(Qubit('00')+Qubit('11'))/sqrt(2),0.5]); state","cell_type":"code","prompt_number":6},{"code":"represent(state, nqubits=2)","cell_type":"code","prompt_number":7},{"code":"qapply(state.operate_on(HadamardGate(0)))\n","cell_type":"code","prompt_number":9},{"code":"state.entropy(nqubits=2)","cell_type":"code","prompt_number":10},{"code":"Density([Qubit('00'),1]).entropy(nqubits=2)\n","cell_type":"code","prompt_number":11},{"code":"%notebook save density_matrix.ipynb","cell_type":"code","prompt_number":16},{"code":"%notebook load qerror.ipynb","cell_type":"code","prompt_number":19}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Symbolic Density Matrices
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational, S\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot\nfrom sympy.physics.quantum.densityOp import *","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Density Operators are used to represent systems which has both classical mixtures as well as quantum superpositions."},{"code":"state = Density([Qubit('00'),0.5],[(Qubit('00')+Qubit('11'))/sqrt(2),0.5]); state","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"In addition to Dirac notation, code can represent the state as a matrix."},{"code":"represent(state, nqubits=2)","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"Gate operators can be applied to density operators."},{"code":"qapply(state.operate_on(HadamardGate(0)))\n","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Von Neumann Entropy can be calculated."},{"code":"state.entropy(nqubits=2)","cell_type":"code","prompt_number":6},{"code":"Density([Qubit('00'),1]).entropy(nqubits=2)\n","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"We can also create symbolic states."},{"code":"genState = Density([Ket('psi'),.5],[Ket('phi'),.5]); genState","cell_type":"code","prompt_number":8},{"code":"%notebook save density_matrix.ipynb","cell_type":"code","prompt_number":16},{"code":"%notebook load qerror.ipynb","cell_type":"code","prompt_number":19}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/gate_rules.ipynb b/docs/examples/notebooks/gate_rules.ipynb
index bf3e8b4..59a2f69 100644
--- a/docs/examples/notebooks/gate_rules.ipynb
+++ b/docs/examples/notebooks/gate_rules.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Gate rules and circuit simplification
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot\nfrom sympy.physics.quantum.gaterules import *","cell_type":"code","prompt_number":2},{"code":"h0 = match_gate_rules(H(0))\nfor rule in h0:\n display(Eq(H(0),rule))","cell_type":"code","prompt_number":5},{"code":"z0 = match_gate_rules(Z(0))\nfor rule in z0:\n display(Eq(Z(0),rule))","cell_type":"code","prompt_number":7},{"code":"x0 = match_gate_rules(X(0))\nfor rule in x0:\n display(Eq(X(0),rule))","cell_type":"code","prompt_number":9},{"code":"circuit_plot(CNOT(1,0), nqubits=2)\n","cell_type":"code","prompt_number":10},{"code":"c10 = match_gate_rules(CNOT(1,0))","cell_type":"code","prompt_number":12},{"code":"circuit_plot(c10[8], nqubits=2)","cell_type":"code","prompt_number":13},{"code":"%notebook save gate_rules.ipynb","cell_type":"code","prompt_number":16},{"code":"","cell_type":"code","prompt_number":25}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Gate rules and circuit simplification
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot\nfrom sympy.physics.quantum.gaterules import *","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"The computational cost of a quantum algorithm is related to the number of gates in the circuit that implements that algorithm.\nJust like a classical computer, we would like to reduce the computational cost by optimizing the circuit. This can be done by\nsearching for relationships (or \"rules\") between gates. Many such rules exist, but so far, there has been little work done to find, classify and use these rules in a systematic way.
\nSymPy's symbolic capabilities are perfect for this work as we don't have to represent the gates as $2^N\\times2^N$ dimensional matrices. "},{"cell_type":"text","text":"Find circuits equivalent to the Hadamard gate"},{"code":"h0 = match_gate_rules(H(0))\nfor rule in h0:\n display(Eq(H(0),rule))","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"Find circuits equivalent to the Z gate"},{"code":"z0 = match_gate_rules(Z(0))\nfor rule in z0:\n display(Eq(Z(0),rule))","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"Find circuits equivalent to the X gate"},{"code":"x0 = match_gate_rules(X(0))\nfor rule in x0:\n display(Eq(X(0),rule))","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Display a CNOT gate"},{"code":"circuit_plot(CNOT(1,0), nqubits=2)\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"Find and display a circuit equivalent to the CNOT gate"},{"code":"c10 = match_gate_rules(CNOT(1,0))","cell_type":"code","prompt_number":7},{"code":"circuit_plot(c10[8], nqubits=2)","cell_type":"code","prompt_number":8},{"code":"%notebook save gate_rules.ipynb","cell_type":"code","prompt_number":16},{"code":"","cell_type":"code","prompt_number":25}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/grovers.ipynb b/docs/examples/notebooks/grovers.ipynb
index e30b703..ff0e886 100644
--- a/docs/examples/notebooks/grovers.ipynb
+++ b/docs/examples/notebooks/grovers.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Grover's Algorithm
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"code":"nqubits = 3\n","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"Define a black box function that returns True if it is passed the state we are searching for."},{"code":"def black_box(qubits):\n return True if qubits == IntQubit(1, qubits.nqubits) else False\n","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"Build a uniform superposition state to start the search."},{"code":"psi = superposition_basis(nqubits); psi\n","cell_type":"code","prompt_number":5},{"cell_type":"text","text":"Wrap that black box function in an oracle gate."},{"code":"v = OracleGate(nqubits, black_box)\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"Perform two iterations of Grover's algorithm. Each iteration, the amplitude of the target state increases."},{"code":"iter1 = qapply(grover_iteration(psi, v)); iter1\n","cell_type":"code","prompt_number":7},{"code":"iter2 = qapply(grover_iteration(iter1, v)); iter2\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"A single shot measurement is performed to retrieve the target state."},{"code":"measure_all_oneshot(iter2)\n","cell_type":"code","prompt_number":9},{"code":"%notebook save grovers.ipynb","cell_type":"code","prompt_number":28},{"code":"%notebook load qft.ipynb","cell_type":"code","prompt_number":63}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Grover's Algorithm
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"code":"nqubits = 3\n","cell_type":"code","prompt_number":3},{"cell_type":"text","text":"Grover's algorithm is a quantum algorithm which searches an unordered database (inverts a function).
\nProvides polynomial speedup over classical brute-force search ($O(\\sqrt{N}) vs. O(N))$ "},{"cell_type":"text","text":"Define a black box function that returns True if it is passed the state we are searching for."},{"code":"def black_box(qubits):\n return True if qubits == IntQubit(1, qubits.nqubits) else False\n","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"Build a uniform superposition state to start the search."},{"code":"psi = superposition_basis(nqubits); psi\n","cell_type":"code","prompt_number":5},{"code":"v = OracleGate(nqubits, black_box)\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"Perform two iterations of Grover's algorithm. Each iteration, the amplitude of the target state increases."},{"code":"iter1 = qapply(grover_iteration(psi, v)); iter1\n","cell_type":"code","prompt_number":7},{"code":"iter2 = qapply(grover_iteration(iter1, v)); iter2\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"A single shot measurement is performed to retrieve the target state."},{"code":"measure_all_oneshot(iter2)\n","cell_type":"code","prompt_number":9},{"code":"%notebook save grovers.ipynb","cell_type":"code","prompt_number":28},{"code":"%notebook load qft.ipynb","cell_type":"code","prompt_number":63}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/qft.ipynb b/docs/examples/notebooks/qft.ipynb
index a2c1e50..3c66eff 100644
--- a/docs/examples/notebooks/qft.ipynb
+++ b/docs/examples/notebooks/qft.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Quantum Fourier Transform
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"QFT Gate and Circuit
"},{"cell_type":"text","text":"Build a 3 qubit QFT and decompose it into primitive gates."},{"code":"fourier = QFT(0,3).decompose(); fourier\n","cell_type":"code","prompt_number":3},{"code":"circuit_plot(fourier, nqubits=3)","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"The QFT circuit can be represented in various symbolic forms."},{"code":"m = represent(fourier, nqubits=3)","cell_type":"code","prompt_number":5},{"code":"m","cell_type":"code","prompt_number":6},{"code":"represent(Fourier(0,3), nqubits=3)*4/sqrt(2)\n","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"QFT in Action
"},{"cell_type":"text","text":"Build a 3 qubit state to take the QFT of."},{"code":"state = (Qubit('000') + Qubit('010') + Qubit('100') + Qubit('110'))/sqrt(4); state\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Perform the QFT."},{"code":"qapply(fourier*state)\n","cell_type":"code","prompt_number":9},{"code":"%notebook save qft.ipynb","cell_type":"code","prompt_number":23},{"code":"%notebook load density_matrix.ipynb","cell_type":"code","prompt_number":207}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Quantum Fourier Transform
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"QFT is useful for a quantum algorithm for factoring numbers which is exponentially faster than what is thought to be possible on a classical machine.
\nThe transform does a DFT on the state of a quantum system
\nThere is a simple decomposition of the QFT in terms of a few elementary gates."},{"cell_type":"text","text":"QFT Gate and Circuit
"},{"cell_type":"text","text":"Build a 3 qubit QFT and decompose it into primitive gates."},{"code":"fourier = QFT(0,3).decompose(); fourier\n","cell_type":"code","prompt_number":3},{"code":"circuit_plot(fourier, nqubits=3)","cell_type":"code","prompt_number":4},{"cell_type":"text","text":"The QFT circuit can be represented in various symbolic forms."},{"code":"m = represent(fourier, nqubits=3)","cell_type":"code","prompt_number":5},{"code":"m","cell_type":"code","prompt_number":6},{"code":"represent(Fourier(0,3), nqubits=3)*4/sqrt(2)\n","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"QFT in Action
"},{"cell_type":"text","text":"Build a 3 qubit state to take the QFT of."},{"code":"state = (Qubit('000') + Qubit('010') + Qubit('100') + Qubit('110'))/sqrt(4); state\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Perform the QFT."},{"code":"qapply(fourier*state)\n","cell_type":"code","prompt_number":9},{"code":"%notebook save qft.ipynb","cell_type":"code","prompt_number":23},{"code":"%notebook load density_matrix.ipynb","cell_type":"code","prompt_number":207}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/quantum_computing.ipynb b/docs/examples/notebooks/quantum_computing.ipynb
index 2451d7f..b6cb875 100644
--- a/docs/examples/notebooks/quantum_computing.ipynb
+++ b/docs/examples/notebooks/quantum_computing.ipynb
@@ -1 +1 @@
-{"cells":[{"cell_type":"text","text":"Symbolic Quantum Computing
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Qubits
"},{"code":"alpha, beta = symbols('alpha beta',real=True)","cell_type":"code","prompt_number":3},{"code":"psi = alpha*Qubit('00') + beta*Qubit('11'); psi\n","cell_type":"code","prompt_number":4},{"code":"Dagger(psi)\n","cell_type":"code","prompt_number":5},{"code":"qapply(Dagger(Qubit('00'))*psi)\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"SymPy supports many different types of measurements."},{"code":"for state, prob in measure_all(psi):\n display(state)\n display(prob)\n","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"Qubits can be represented in the computational basis."},{"code":"represent(psi)\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Gates
"},{"code":"g = X(0); g\n","cell_type":"code","prompt_number":9},{"code":"represent(g, nqubits=2)\n","cell_type":"code","prompt_number":10},{"code":"c = H(0)*Qubit('00'); c\n","cell_type":"code","prompt_number":11},{"code":"qapply(c)\n","cell_type":"code","prompt_number":12},{"code":"for gate in [H,X,Y,Z,S,T]:\n for state in [Qubit('0'),Qubit('1')]:\n lhs = gate(0)*state\n rhs = qapply(lhs)\n display(Eq(lhs,rhs))","cell_type":"code","prompt_number":13},{"cell_type":"text","text":"Symbolic gate rules and circuit simplification
"},{"code":"for g1 in (Y,Z,H):\n for g2 in (Y,Z,H):\n e = Commutator(g1(0),g2(0))\n if g1 != g2:\n display(Eq(e,e.doit()))\n","cell_type":"code","prompt_number":14},{"code":"c = H(0)*X(1)*H(0)**2*CNOT(0,1)*X(1)**3*X(0)*Z(1)**2; c\n","cell_type":"code","prompt_number":15},{"code":"circuit_plot(c, nqubits=2)","cell_type":"code","prompt_number":16},{"cell_type":"text","text":"This performs a commutator/anticommutator aware bubble sort algorithm to simplify a circuit."},{"code":"gate_simp(c)\n","cell_type":"code","prompt_number":17},{"code":"circuit_plot(gate_simp(c),nqubits=2)","cell_type":"code","prompt_number":18},{"code":"%notebook save quantum_computing.ipynb","cell_type":"code","prompt_number":35},{"code":"%notebook load grovers.ipynb","cell_type":"code","prompt_number":90}]}
\ No newline at end of file
+{"cells":[{"cell_type":"text","text":"Symbolic Quantum Computing
"},{"code":"%load_ext sympyprinting","cell_type":"code","prompt_number":1},{"code":"from sympy import sqrt, symbols, Rational\nfrom sympy import expand, Eq, Symbol, simplify, exp, sin\nfrom sympy.physics.quantum import *\nfrom sympy.physics.quantum.qubit import *\nfrom sympy.physics.quantum.gate import *\nfrom sympy.physics.quantum.grover import *\nfrom sympy.physics.quantum.qft import QFT, IQFT, Fourier\nfrom sympy.physics.quantum.circuitplot import circuit_plot","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"Qubits
"},{"cell_type":"text","text":"The state of a set of qubits (Two state systems) is the quantum state that is of interest in Quantum Computing."},{"code":"alpha, beta = symbols('alpha beta',real=True)","cell_type":"code","prompt_number":3},{"code":"psi = alpha*Qubit('00') + beta*Qubit('11'); psi\n","cell_type":"code","prompt_number":4},{"code":"Dagger(psi)\n","cell_type":"code","prompt_number":5},{"code":"qapply(Dagger(Qubit('00'))*psi)\n","cell_type":"code","prompt_number":6},{"cell_type":"text","text":"SymPy supports many different types of measurements."},{"code":"for state, prob in measure_all(psi):\n display(state)\n display(prob)\n","cell_type":"code","prompt_number":7},{"cell_type":"text","text":"Qubits can be represented in the computational basis."},{"code":"represent(psi)\n","cell_type":"code","prompt_number":8},{"cell_type":"text","text":"Gates
"},{"cell_type":"text","text":"Gate objects are the operators which act on a quantum state."},{"code":"g = X(0); g\n","cell_type":"code","prompt_number":9},{"code":"represent(g, nqubits=2)\n","cell_type":"code","prompt_number":10},{"code":"c = H(0)*Qubit('00'); c\n","cell_type":"code","prompt_number":11},{"code":"qapply(c)\n","cell_type":"code","prompt_number":12},{"code":"for gate in [H,X,Y,Z,S,T]:\n for state in [Qubit('0'),Qubit('1')]:\n lhs = gate(0)*state\n rhs = qapply(lhs)\n display(Eq(lhs,rhs))","cell_type":"code","prompt_number":13},{"cell_type":"text","text":"Symbolic gate rules and circuit simplification
"},{"code":"for g1 in (Y,Z,H):\n for g2 in (Y,Z,H):\n e = Commutator(g1(0),g2(0))\n if g1 != g2:\n display(Eq(e,e.doit()))\n","cell_type":"code","prompt_number":14},{"code":"c = H(0)*X(1)*H(0)**2*CNOT(0,1)*X(1)**3*X(0)*Z(1)**2; c\n","cell_type":"code","prompt_number":15},{"code":"circuit_plot(c, nqubits=2)","cell_type":"code","prompt_number":16},{"cell_type":"text","text":"This performs a commutator/anticommutator aware bubble sort algorithm to simplify a circuit."},{"code":"gate_simp(c)\n","cell_type":"code","prompt_number":17},{"code":"circuit_plot(gate_simp(c),nqubits=2)","cell_type":"code","prompt_number":18},{"code":"%notebook save quantum_computing.ipynb","cell_type":"code","prompt_number":35},{"code":"%notebook load grovers.ipynb","cell_type":"code","prompt_number":90}]}
\ No newline at end of file
diff --git a/docs/examples/notebooks/smooth_dos.ipynb b/docs/examples/notebooks/smooth_dos.ipynb
new file mode 100644
index 0000000..20918df
--- /dev/null
+++ b/docs/examples/notebooks/smooth_dos.ipynb
@@ -0,0 +1 @@
+{"cells":[{"code":"%notebook save dos.ipynb","cell_type":"code","prompt_number":5},{"code":"from sympy import *\nimport numpy as np\nimport math","cell_type":"code","prompt_number":47},{"cell_type":"text","text":"Strutinsky Energy Averaging Method
"},{"cell_type":"text","text":"Define a callable class for computing the smooth part of the density of states $\\tilde{g}_m(E)$ with curvature\ncorrection of order $2M$."},{"code":"class SmoothDOS(object):\n\n def __init__(self, energies):\n self.energies = energies\n\n def gaussian_smoothing_func(self, M, x):\n return (mpmath.laguerre(M,0.5,x**2)*exp(-x**2)/sqrt(pi)).evalf()\n\n def __call__(self, e, M=3, gamma=1.0):\n return sum(self.gaussian_smoothing_func(M, (e-ei)/gamma)/gamma for ei in self.energies)","cell_type":"code","prompt_number":67},{"code":"def avgf(M, x):\n return (mpmath.laguerre(M,0.5,x**2)*exp(-x**2)/sqrt(pi)).evalf()","cell_type":"code","prompt_number":14},{"code":"def smooth_dos(gamma, M, e, energies):\n return sum(avgf(M, (e-ei)/gamma)/gamma for ei in energies)","cell_type":"code","prompt_number":2},{"cell_type":"text","text":"1D Simple Harmonic Oscillator DOS
"},{"code":"def sho_smooth_dos(e):\n \"\"\"Compute the exact smooth DOS.\"\"\"\n return 1","cell_type":"code","prompt_number":50},{"code":"def sho_spectrum(nmax):\n \"\"\"Compute the first nmax energies of the 1D SHO.\"\"\"\n return [n+0.5 for n in range(nmax)]","cell_type":"code","prompt_number":51},{"code":"sho_evalues = np.linspace(0.0,20,100)","cell_type":"code","prompt_number":63},{"code":"sho_dos = SmoothDOS(sho_spectrum(30))","cell_type":"code","prompt_number":68},{"code":"sho_exact_dos = [sho_smooth_dos(e) for e in evalues]","cell_type":"code","prompt_number":69},{"code":"sho_approx_dos = [sho_dos(e,M=3,gamma=10.0) for e in evalues]","cell_type":"code","prompt_number":72},{"code":"plot(evalues, sho_exact, label=\"exact\")\nplot(evalues, sho_approx, label=\"approx\")\ntitle(\"Smooth part of the DOS for the 1D SHO\")\nxlabel(\"Energy\"); ylabel(\"$g(E)$\")\nlegend(loc=4)","cell_type":"code","prompt_number":73},{"cell_type":"text","text":"Note how the exact smoothed DOS and the Strutinsky approximation agree once the energy is away from\n0. In general, these are edge effects and are also present at the right limit if you don't use enough energy\nlevels. Here we have used 30, so the right side doesn't show these artifacts."},{"cell_type":"text","text":"1D Particle in a BOX (PIAB) DOS
"},{"code":"def piab_smooth_dos(e):\n \"\"\"Compute the exact smooth DOS.\"\"\"\n return 1.0/(2.0*math.sqrt(e*math.pi**2/2))","cell_type":"code","prompt_number":76},{"code":"def piab_spectrum(nmax):\n \"\"\"Compute the first nmax energies of the 1D PIAB.\"\"\"\n return [0.5*math.pi**2*(n+1)**2 for n in range(nmax)]","cell_type":"code","prompt_number":77},{"code":"piab_evalues = linspace(1.0,1000.0,100)","cell_type":"code","prompt_number":78},{"code":"piab_dos = SmoothDOS(piab_spectrum(20))","cell_type":"code","prompt_number":79},{"code":"piab_exact_dos = [piab_smooth_dos(e) for e in piab_evalues]","cell_type":"code","prompt_number":80},{"code":"piab_approx_dos = [piab_dos(e, M=4, gamma=150.0) for e in piab_evalues]","cell_type":"code","prompt_number":81},{"code":"plot(piab_evalues, piab_exact, label=\"exact\")\nplot(piab_evalues, piab_approx, label=\"approx\")\ntitle(\"Smooth part of the DOS for the 1D PIAB\")\nxlabel(\"Energy\"); ylabel(\"$g(E)$\")\nlegend(loc=1)","cell_type":"code","prompt_number":85},{"code":"","cell_type":"code","prompt_number":24}]}
\ No newline at end of file