diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..ee89540
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,24 @@
+### Summary
+
+Short summary of the changes.
+
+### Rationale
+
+Explain the rationale for the changes (links to relevant issue(s)).
+
+#### Implementation Details
+
+#### Additional notes
+
+
+
+***Check before merging:***
+
+- [ ] All discussions are resolved
+- [ ] New code is covered by appropriate tests
+- [ ] Tests are passing locally and on CI
+- [ ] The documentation is consistent with changes
+- [ ] Any code that was copied from other sources has the paper/url in a comment and is compatible with the MIT licence
+- [ ] Notebooks/examples not covered by unittests have been tested and updated as required
+- [ ] The feature branch is up-to-date with the master branch (rebase if behind)
+- [ ] Incremented the version string in Project.toml file
diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml
new file mode 100644
index 0000000..cba9134
--- /dev/null
+++ b/.github/workflows/CompatHelper.yml
@@ -0,0 +1,16 @@
+name: CompatHelper
+on:
+ schedule:
+ - cron: 0 0 * * *
+ workflow_dispatch:
+jobs:
+ CompatHelper:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Pkg.add("CompatHelper")
+ run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
+ - name: CompatHelper.main()
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}
+ run: julia -e 'using CompatHelper; CompatHelper.main()'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..5493af5
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,64 @@
+name: CI
+on:
+ - push
+ - pull_request
+jobs:
+ test:
+ name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ version:
+ - '1.5'
+ - 'nightly'
+ os:
+ - ubuntu-latest
+ - macOS-latest
+ - windows-latest
+ arch:
+ - x64
+ steps:
+ - uses: actions/checkout@v2
+ - uses: julia-actions/setup-julia@v1
+ with:
+ version: ${{ matrix.version }}
+ arch: ${{ matrix.arch }}
+ - uses: actions/cache@v1
+ env:
+ cache-name: cache-artifacts
+ with:
+ path: ~/.julia/artifacts
+ key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
+ restore-keys: |
+ ${{ runner.os }}-test-${{ env.cache-name }}-
+ ${{ runner.os }}-test-
+ ${{ runner.os }}-
+ - uses: julia-actions/julia-buildpkg@v1
+ - uses: julia-actions/julia-runtest@v1
+ - uses: julia-actions/julia-processcoverage@v1
+ - uses: codecov/codecov-action@v1
+ with:
+ file: lcov.info
+ docs:
+ name: Documentation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: julia-actions/setup-julia@v1
+ with:
+ version: '1'
+ - run: |
+ julia --project=docs -e '
+ using Pkg
+ Pkg.develop(PackageSpec(path=pwd()))
+ Pkg.instantiate()'
+ - run: |
+ julia --project=docs -e '
+ using Documenter: doctest
+ using QXSim
+ doctest(QXSim)'
+ - run: julia --project=docs docs/make.jl
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
diff --git a/Project.toml b/Project.toml
index 7e5c088..55ff62b 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,15 +1,26 @@
name = "QXZoo"
uuid = "f27fdc93-0c88-4b5a-91cb-e8275adac0f6"
-authors = ["Lee J. O'Riordan "]
+authors = ["QuantEx Team"]
version = "0.1.0"
[deps]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
-Memoize = "c03570c3-d221-55d1-a50c-7939bbd78826"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
-Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestSetExtensions = "98d24dd4-01ad-11ea-1b02-c9a08f80db04"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
+
+[compat]
+DataStructures = "0.18"
+Reexport = "1.0"
+StaticArrays = "1.0"
+TestSetExtensions = "2.0.0"
+julia = "1.5"
+
+[extras]
+Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
+[targets]
+test = ["Test"]
diff --git a/docs/Project.toml b/docs/Project.toml
index dfa65cd..3879473 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -1,2 +1,5 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
+
+[compat]
+Documenter = "0.26"
\ No newline at end of file
diff --git a/docs/make.jl b/docs/make.jl
index 610479f..7e74c31 100644
--- a/docs/make.jl
+++ b/docs/make.jl
@@ -1,5 +1,5 @@
push!(LOAD_PATH,"./src/")
-using Documenter, QXZoo
+using Documenter, QXZoo, Random
makedocs(
modules = [QXZoo],
@@ -16,9 +16,17 @@ makedocs(
"Home" => "index.md",
"Examples" => "examples.md",
"Manual" => Any[
- "Gates" => Any["gates_circuits/GateOps.md", "gates_circuits/DefaultGates.md", "gates_circuits/GateMap.md"],
+ "Gates" => Any[ "gates_circuits/GateOps.md",
+ "gates_circuits/DefaultGates.md",
+ "gates_circuits/CompositeGates.md",
+ "gates_circuits/GateMap.md",
+ ],
"Circuits" => "gates_circuits/circuits.md",
- "Algorithms" => Any[ "NCU" => "algo/ncu.md", "Grover" => "algo/grover.md" ],
+ "Algorithms" => Any[ "NCU" => "algo/ncu.md",
+ "Grover" => "algo/grover.md",
+ "QFT" => "algo/qft.md",
+ "RQC" => "algo/rqc.md"
+ ],
],
]
)
diff --git a/docs/src/algo/grover.md b/docs/src/algo/grover.md
index 9240456..00c52df 100644
--- a/docs/src/algo/grover.md
+++ b/docs/src/algo/grover.md
@@ -4,9 +4,8 @@ The Grover.jl module implements a Grover's search use-case. Assisted by Oracle.j
To apply the Grover search algorithm, we require additional functionalities in the form an oracle to select the required state, and a diffusion operator to shift the state ampltiudes.
## API
-### oracle.jl
```@docs
-QXZoo.Grover.bitstring_ncu!(cct::QXZoo.Circuit.Circ, bitstring::Integer, ctrl_indices::Vector, tgt_idx, U::QXZoo.GateOps.GateSymbol, aux_indices::Vector=Int[])
+QXZoo.Grover.bitstring_ncu!(cct::QXZoo.Circuit.Circ, bitstring::Integer, ctrl_indices::Vector, tgt_idx::Int, U::QXZoo.GateOps.GateSymbol, aux_indices::Vector=Int[])
QXZoo.Grover.bitstring_phase_oracle!(cct::QXZoo.Circuit.Circ, bitstring::Integer, ctrl_indices::Vector, tgt_idx::Int, aux_indices::Vector=Int[])
QXZoo.Grover.apply_diffusion!(cct::QXZoo.Circuit.Circ, ctrl_indices::Vector, tgt_index::Int, aux_indices::Vector=Int[])
QXZoo.Grover.run_grover!(cct::QXZoo.Circuit.Circ, qubit_indices::Vector, state::Integer)
@@ -22,27 +21,40 @@ To use the Grover module, we provide example code below to search for a state in
```@example 1
using QXZoo
-# Set 5-qubit limit on circuit
-num_qubits = 5
+# Set 10-qubit limit on circuit
+num_qubits = 10
# Set bit-pattern to 11 (0b01011)
bit_pattern = 11
-# Do not use optimised routines
-use_aux_qubits = false
-
# Create empty circuit with qiven qubit count
cct = QXZoo.Circuit.Circ(num_qubits)
-# Initialise intermediate gates for use in NCU
-QXZoo.NCU.init_intermed_gates(cct, num_qubits-1)
-
# Run Grover algorithm for given oracle bit-pattern
-QXZoo.Grover.run_grover!(cct, collect(0:num_qubits-1), bit_pattern)
+QXZoo.Grover.run_grover!(cct, collect(1:num_qubits), bit_pattern)
+
+println(cct)
```
-From here we can examine how many operations were generated as
+Similarly, for an optimised variant of the same operations using more qubits:
+
+```@example 2
+using QXZoo
+
+# Set 10-qubit limit on Grover circuit (aux assisted)
+num_qubits = 17
+
+qubits_range = 1:Int((num_qubits+1)/2) + 1
+aux_range = Int((num_qubits+1)/2 + 2):num_qubits
+
+# Set bit-pattern to 11 (0b01011)
+bit_pattern = 11
+
+# Create empty circuit with qiven qubit count
+cct = QXZoo.Circuit.Circ(num_qubits)
+
+# Run Grover algorithm for given oracle bit-pattern
+QXZoo.Grover.run_grover!(cct, collect(qubits_range), bit_pattern, collect(aux_range))
-```@example 1
println(cct)
```
\ No newline at end of file
diff --git a/docs/src/algo/ncu.md b/docs/src/algo/ncu.md
index ea4ca88..9780c2a 100644
--- a/docs/src/algo/ncu.md
+++ b/docs/src/algo/ncu.md
@@ -8,9 +8,6 @@ The general principle follows the work of Barenco *et al.*, Phys. Rev. A 52, 345
```@docs
QXZoo.NCU.apply_ncu!(circuit::QXZoo.Circuit.Circ, q_ctrl::Vector, q_aux::Vector, q_tgt, U::QXZoo.GateOps.GateSymbol)
-QXZoo.NCU.init_intermed_gates(circ::QXZoo.Circuit.Circ, num_ctrl::Union{Nothing, Int})
-QXZoo.NCU.register_gate(circ::QXZoo.Circuit.Circ, U::QXZoo.GateOps.GateSymbol, gate_f::Function)
-QXZoo.NCU.gen_intermed_gates(ctrl_depth::Int, U::QXZoo.GateOps.GateSymbol)
QXZoo.NCU.get_intermed_gate(U::QXZoo.GateOps.GateSymbol)
```
@@ -21,18 +18,18 @@ To use the NCU module, we provide example code below to apply an n-controlled Pa
```@example
using QXZoo
-# Set 5-qubit limit on circuit
+# Set 10-qubit limit on circuit
num_qubits = 10
# Create Pauli-Z gate-label for application
-gate_z = QXZoo.DefaultGates.GateSymbols.z
+gate_z = QXZoo.DefaultGates.GateSymbols.c_z
# Create empty circuit with qiven qubit count
cct = QXZoo.Circuit.Circ(num_qubits)
-ctrl = collect(range(0, length=num_qubits-1 ) )
+ctrl = collect(range(1, length=num_qubits ) )
aux = []
-tgt = num_qubits-1
+tgt = num_qubits
for i in ctrl
QXZoo.Circuit.add_gatecall!(cct, QXZoo.DefaultGates.x(i) )
@@ -56,15 +53,15 @@ num_qubits = 19
cct = QXZoo.Circuit.Circ(num_qubits)
-ctrl = collect(range(0, length=convert(Int, (num_qubits+1)/2 )))
-aux = collect(range( convert(Int, (num_qubits+1)/2+1), stop=num_qubits-1))
-tgt = convert(Int, maximum(ctrl)+1 )
+ctrl = collect(1:10)
+tgt = 11
+aux = collect(11:19)
for i in ctrl
cct << QXZoo.DefaultGates.x(i)
end
-QXZoo.NCU.apply_ncu!(cct, ctrl, aux, tgt, QXZoo.GateOps.GateSymbol(:z))
+QXZoo.NCU.apply_ncu!(cct, ctrl, aux, tgt, DefaultGates.GateSymbols.c_z)
println(cct)
```
\ No newline at end of file
diff --git a/docs/src/algo/qft.md b/docs/src/algo/qft.md
index e69de29..4b43860 100644
--- a/docs/src/algo/qft.md
+++ b/docs/src/algo/qft.md
@@ -0,0 +1,30 @@
+# Quantum Fourier Transform (QFT)
+The `QFT` module enables the creation of circuit for $n$-qubit quantum Fourier transforms, and their inverses.
+
+## API
+### rqc.jl
+```@docs
+QXZoo.QFT.apply_qft!(cct::QXZoo.Circuit.Circ, qubit_indices::Vector)
+QXZoo.QFT.apply_qft!(cct::QXZoo.Circuit.Circ)
+QXZoo.QFT.apply_iqft!(cct::QXZoo.Circuit.Circ, qubit_indices::Vector)
+QXZoo.QFT.apply_iqft!(cct::QXZoo.Circuit.Circ)
+QXZoo.QFT.swap_idx(qubit_indices::Vector)
+```
+
+## Example
+The following demonstrates the application of the QFT to a subset of qubits in the register, and the IQFT to the entire register.
+
+```@example 1
+using QXZoo
+
+cct = QXZoo.Circuit.Circ(8)
+
+QXZoo.QFT.apply_qft!(cct, collect(1:4))
+QXZoo.QFT.apply_iqft!(cct)
+
+println(cct)
+
+for i in cct.circ_ops
+ println(i)
+end
+```
diff --git a/docs/src/algo/rqc.md b/docs/src/algo/rqc.md
new file mode 100644
index 0000000..c0b3aeb
--- /dev/null
+++ b/docs/src/algo/rqc.md
@@ -0,0 +1,32 @@
+# Random Quantum Circuits (RQC)
+The `RQC` module aims to generate RQC capable of demonstrating results as those of Villalonga et al (npj Quantum Inf 5, 86 (2019)) and Arute et al. (Nature volume 574, 505–510 (2019)).
+
+## API
+### rqc.jl
+```@docs
+QXZoo.RQC.RQC_DS(n::Int, m::Int)
+QXZoo.RQC.random_gate!(rqc::QXZoo.RQC.RQC_DS, i::Int, j::Int, rng::Random.MersenneTwister)
+QXZoo.RQC.patterns(rqc::QXZoo.RQC.RQC_DS)
+QXZoo.RQC.create_RQC(rows::Int, cols::Int, depth::Int, seed::Union{Int, Nothing}=nothing; use_iswap::Bool=false, final_Hadamard_layer::Bool=false)
+```
+
+## Example
+To use the Grover module, we provide example code below to search for a state in a 5-qubit quantum register marked by bit-pattern 11 (0b01011).
+
+```@example 1
+using QXZoo
+
+# Set 2D qubit grid size and circuit depth
+rows = 4
+cols = 5
+depth = 7
+
+# Create RQC circuit using built-in generator
+cct = QXZoo.RQC.create_RQC(rows, cols, depth)
+
+println(cct)
+
+for i in cct.circ_ops
+ println(i)
+end
+```
\ No newline at end of file
diff --git a/docs/src/gates_circuits/CompositeGates.md b/docs/src/gates_circuits/CompositeGates.md
index e69de29..691a8de 100644
--- a/docs/src/gates_circuits/CompositeGates.md
+++ b/docs/src/gates_circuits/CompositeGates.md
@@ -0,0 +1,18 @@
+# Composite Gates
+This module is used for gates that can be composed of more fundamental gate operations. For simplicity, we refer to these as `Composite Gates`, and represent them as their numerical matrix values.
+
+## CompositeGates.GateSymbols
+As in `DefaultGates`, we store symbols for the gates available in CompositeGates, and generator functions for parameteric variants of these gates. This allows us to track the mappings as to be used by the gate type hierarchy and architecture.
+
+### Two Qubit Gates: static
+```@docs
+QXZoo.CompositeGates.swap(q_target1::Int, q_target2::Int)
+QXZoo.CompositeGates.iswap(q_target1::Int, q_target2::Int)
+```
+
+### Two Qubit Gates: rotation
+```@docs
+QXZoo.CompositeGates.xx(q_target1::Int, q_target2::Int, θ::Number)
+QXZoo.CompositeGates.yy(q_target1::Int, q_target2::Int, θ::Number)
+QXZoo.CompositeGates.zz(q_target1::Int, q_target2::Int, θ::Number)
+```
\ No newline at end of file
diff --git a/docs/src/gates_circuits/DefaultGates.md b/docs/src/gates_circuits/DefaultGates.md
index 2aeea5a..2a49be0 100644
--- a/docs/src/gates_circuits/DefaultGates.md
+++ b/docs/src/gates_circuits/DefaultGates.md
@@ -1,7 +1,7 @@
# DefaultGates
## DefaultGates.GateSymbols
-Here we store symbols for the gates available in DefaultGates, and generator functions for parameteric variants of these gates. This allos us to track the mappings as to be used by the gate type hierarchy and architecture.
+Here we store symbols for the gates available in DefaultGates, and generator functions for parameteric variants of these gates. This allows us to track the mappings as to be used by the gate type hierarchy and architecture.
## Commonly used gates
diff --git a/docs/src/gates_circuits/GateMap.md b/docs/src/gates_circuits/GateMap.md
index 95a102f..22c6eea 100644
--- a/docs/src/gates_circuits/GateMap.md
+++ b/docs/src/gates_circuits/GateMap.md
@@ -30,6 +30,8 @@ QXZoo.GateMap.x()
QXZoo.GateMap.y()
QXZoo.GateMap.z()
QXZoo.GateMap.h()
+QXZoo.GateMap.s()
+QXZoo.GateMap.t()
QXZoo.GateMap.I()
QXZoo.GateMap.r_x(θ::Number)
@@ -40,4 +42,9 @@ QXZoo.GateMap.r_phase(θ::Number)
QXZoo.GateMap.c_x()
QXZoo.GateMap.c_y()
QXZoo.GateMap.c_z()
+
+QXZoo.GateMap.c_r_x(θ::Number)
+QXZoo.GateMap.c_r_y(θ::Number)
+QXZoo.GateMap.c_r_z(θ::Number)
+QXZoo.GateMap.c_r_phase(θ::Number)
```
\ No newline at end of file
diff --git a/docs/src/index.md b/docs/src/index.md
index 25ef47c..3deef54 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -2,4 +2,4 @@
*QXZoo.jl* is a generator suite for quantum algorithms. Using a high-level approach to quantum circuit design, we create quantum circuits taking note of all intermediate gate-calls between qubits, performing operation caching and optimisation where possible.
-Currently, we support a limited set of quantum algorithms (see the `Algorithms` dropdown for details). Details of the circuit generator modules and structs are given in the `Gates` and `Circuits` dropdowns.
+Currently, we support a limited set of quantum algorithms (see the `MAnual/Algorithms` dropdown for details). Details of the circuit generator modules and structs are given in the `Gates` and `Circuits` dropdowns.
diff --git a/src/algorithms/evolution.jl b/src/algorithms/evolution.jl
index dc93da9..a7e37d2 100644
--- a/src/algorithms/evolution.jl
+++ b/src/algorithms/evolution.jl
@@ -6,7 +6,7 @@ using QXZoo.DefaultGates
"""
- pauli_string(θ::Number, pauli_gates::Vector{GateCall1})
+ apply_pauli_string(θ::Number, pauli_gates::Vector{GateCall1})
Create a circuit representating a given exp Pauli string (eg exp(-i0.5*X*X*Y*Y))
diff --git a/src/algorithms/qft.jl b/src/algorithms/qft.jl
index 09f0860..a3e0aad 100644
--- a/src/algorithms/qft.jl
+++ b/src/algorithms/qft.jl
@@ -5,6 +5,8 @@ using QXZoo.Circuit
using QXZoo.DefaultGates
using QXZoo.CompositeGates
+export apply_qft!, apply_iqft!
+
"""
apply_qft!(cct::Circuit.Circ, qubit_indices::Vector)
@@ -17,8 +19,9 @@ function apply_qft!(cct::Circuit.Circ, qubit_indices::Vector)
cct << DefaultGates.c_r_phase(qubit_indices[idx], qubit_indices[jdx], 2π/(2^(qubit_indices[jdx]-qubit_indices[idx]+1)))
end
end
- for i = 1:convert(Int, floor(length(qubit_indices)//2))
- cct << CompositeGates.swap(i, length(qubit_indices)-i+1)
+ lhs, rhs = swap_idx(qubit_indices)
+ for i in 1:length(lhs)
+ cct << CompositeGates.swap(lhs[i], rhs[i])
end
;
end
@@ -36,9 +39,12 @@ apply_qft!(cct::Circuit.Circ) = apply_qft!(cct, collect(1:cct.num_qubits))
Apply the inverse quantum Fourier transform over the given qubit index range.
"""
function apply_iqft!(cct::Circuit.Circ, qubit_indices::Vector)
- for i = convert(Int, floor(length(qubit_indices)//2)):-1:1
- cct << CompositeGates.swap(i, length(qubit_indices)-i+1)
+ lhs, rhs = swap_idx(qubit_indices)
+
+ for i in 1:length(lhs)
+ cct << CompositeGates.swap(lhs[i], rhs[i])
end
+
for idx in length(qubit_indices):-1:1
for jdx in length(qubit_indices):-1:idx+1
cct << DefaultGates.c_r_phase(qubit_indices[idx], qubit_indices[jdx], -2π/(2^(qubit_indices[jdx]-qubit_indices[idx]+1)))
@@ -55,4 +61,22 @@ Apply the inverse quantum Fourier transform over the entire qubit register
"""
apply_iqft!(cct::Circuit.Circ) = apply_iqft!(cct, collect(1:cct.num_qubits))
-end
\ No newline at end of file
+
+"""
+ swap_idx(qubit_indices::Vector)
+
+Return the indices of the qubits required to apply the swap operations as part of the transform.
+"""
+function swap_idx(qubit_indices::Vector)
+ is_even = (length(qubit_indices) & 1 === 0)
+ mp = convert(Int, floor(length(qubit_indices)//2))
+ lhs = @view qubit_indices[1:mp]
+ if is_even
+ rhs = @view qubit_indices[end:-1:mp+1]
+ else
+ rhs = @view qubit_indices[end:-1:mp+2]
+ end
+ return lhs, rhs
+end
+
+end
diff --git a/src/algorithms/rqc.jl b/src/algorithms/rqc.jl
index 66e2322..bfc83d1 100644
--- a/src/algorithms/rqc.jl
+++ b/src/algorithms/rqc.jl
@@ -5,6 +5,8 @@ using QXZoo.DefaultGates
using QXZoo.GateOps
using Random
+export create_RQC
+
# *************************************************************************** #
# RQC functions
# *************************************************************************** #
@@ -50,7 +52,11 @@ struct RQC_DS
single_qubit_gates::Dict{Int, AGateSymbol}
end
+"""
+ RQC creation structure.
+Holds the circuit, and generator datatypes
+"""
function RQC_DS(n::Int, m::Int)
RQC_DS(n, m, Circuit.Circ(n*m), -ones(Int, n, m),
Dict(1=>DefaultGates.GateSymbols.t, 2=>sqrt(DefaultGates.GateSymbols.x), 3=>sqrt(DefaultGates.GateSymbols.y)) )
diff --git a/test/test_qft.jl b/test/test_qft.jl
index c4e3331..194355a 100644
--- a/test/test_qft.jl
+++ b/test/test_qft.jl
@@ -47,8 +47,8 @@
QXZoo.QFT.apply_iqft!(cct1, collect(1:num_qubits))
- cct2 << CompositeGates.swap(2,4)
cct2 << CompositeGates.swap(1,5)
+ cct2 << CompositeGates.swap(2,4)
cct2 << DefaultGates.h(5)
cct2 << DefaultGates.c_r_phase(4, 5, -π/2)