├── src
├── QuantumComputing
│ ├── packages.config
│ ├── Mathematics
│ │ ├── Numerics.cs
│ │ └── LinearAlgebra.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Qubit.cs
│ ├── QuantumComputing.csproj
│ ├── QuantumRegister.cs
│ └── QuantumGate.cs
└── QuantumComputing.Tests
│ ├── packages.config
│ ├── QubitTests.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── QuantumGateTests.cs
│ ├── QuantumRegisterTests.cs
│ └── QuantumComputing.Tests.csproj
├── .gitattributes
├── QuantumComputing.sln
├── README.md
└── .gitignore
/src/QuantumComputing/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/QubitTests.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using MathNet.Numerics.LinearAlgebra;
8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
9 | using System;
10 | using System.Numerics;
11 |
12 | namespace Lachesis.QuantumComputing.Tests
13 | {
14 | [TestClass]
15 | public class QubitTests
16 | {
17 | [TestMethod]
18 | public void Qubit_Zero_IsZero()
19 | {
20 | Assert.AreEqual(Qubit.Zero.Vector, Vector.Build.SparseOfArray(new Complex[] { Complex.One, Complex.Zero }));
21 | }
22 |
23 | [TestMethod]
24 | public void Qubit_One_IsOne()
25 | {
26 | Assert.AreEqual(Qubit.One.Vector, Vector.Build.SparseOfArray(new Complex[] { Complex.Zero, Complex.One }));
27 | }
28 |
29 | [TestMethod]
30 | public void Qubit_FromComplex_IsValid()
31 | {
32 | Assert.AreEqual((new Qubit(new Complex(1, 0), new Complex(0, 0))), Qubit.Zero);
33 | }
34 |
35 | [TestMethod]
36 | public void Qubit_FromDouble_IsValid()
37 | {
38 | Assert.AreEqual((new Qubit(0, 0, 1, 0)), Qubit.One);
39 | }
40 |
41 | [TestMethod]
42 | public void Qubit_FromBlochCoordinates_IsValid()
43 | {
44 | Assert.IsTrue((new Qubit(Math.PI, 0)).AlmostEquals(Qubit.One));
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/QuantumComputing/Mathematics/Numerics.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using System;
8 | using System.Numerics;
9 |
10 | namespace Lachesis.QuantumComputing.Mathematics
11 | {
12 | public static class Numerics
13 | {
14 | /*
15 | * Complex exponential
16 | */
17 | public static Complex ComplexExp(Complex value)
18 | {
19 | if (value.Equals(Complex.ImaginaryOne * Math.PI / 2))
20 | {
21 | return Complex.ImaginaryOne;
22 | }
23 | else if (value.Equals(Complex.ImaginaryOne * Math.PI))
24 | {
25 | return -Complex.One;
26 | }
27 | else if (value.Equals(Complex.ImaginaryOne * 3 * Math.PI / 2))
28 | {
29 | return -Complex.ImaginaryOne;
30 | }
31 | else {
32 | return Complex.Exp(value);
33 | }
34 | }
35 |
36 | /*
37 | * Next strictly larger power of two
38 | */
39 | public static int NextStrictlyLargerPowerOfTwo(int value)
40 | {
41 | value |= (value >> 1);
42 | value |= (value >> 2);
43 | value |= (value >> 4);
44 | value |= (value >> 8);
45 | value |= (value >> 16);
46 |
47 | return value + 1;
48 | }
49 |
50 | /*
51 | * Binary logarithm
52 | */
53 | public static int Log2(int value)
54 | {
55 | int log2 = 1;
56 |
57 | for (int bitCount = 16; bitCount > 0; bitCount /= 2)
58 | {
59 | if (value >= 1 << bitCount) {
60 | value >>= bitCount;
61 | log2 += bitCount;
62 | }
63 | }
64 |
65 | return log2;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/QuantumComputing/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("QuantumComputing")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("QuantumComputing")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("d5ec7b3d-0ba2-43e3-b1d8-88b5da2ce813")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("QuantumComputing.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("QuantumComputing.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("1dd6adc4-f9ba-4a18-8e31-6bb931ce1c81")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/QuantumComputing.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantumComputing", "src\QuantumComputing\QuantumComputing.csproj", "{D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantumComputing.Tests", "src\QuantumComputing.Tests\QuantumComputing.Tests.csproj", "{1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/src/QuantumComputing/Mathematics/LinearAlgebra.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using MathNet.Numerics.LinearAlgebra;
8 | using System;
9 | using System.Numerics;
10 |
11 | namespace Lachesis.QuantumComputing.Mathematics
12 | {
13 | public static class LinearAlgebra
14 | {
15 | /*
16 | * Cartesian product of two vectors
17 | */
18 | public static Vector CartesianProduct(Vector vector1, Vector vector2)
19 | {
20 | Complex[] cartesianProductArray = new Complex[vector1.Count * vector2.Count];
21 |
22 | for (int i = 0; i < vector1.Count; i++)
23 | {
24 | for (int j = 0; j < vector2.Count; j++)
25 | {
26 | cartesianProductArray[i * vector2.Count + j] = vector1.At(i) * vector2.At(j);
27 | }
28 | }
29 |
30 | return Vector.Build.SparseOfArray(cartesianProductArray);
31 | }
32 |
33 | /*
34 | * Vector representation of an integer
35 | */
36 | public static Vector VectorFromInteger(int value, int bitCount = 0)
37 | {
38 | int order;
39 |
40 | if (bitCount == 0)
41 | {
42 | order = Mathematics.Numerics.NextStrictlyLargerPowerOfTwo(value);
43 | }
44 | else
45 | {
46 | order = 1 << bitCount;
47 | }
48 |
49 | if (order <= value)
50 | {
51 | throw new ArgumentException("The submitted value cannot be stored on the given bit count.");
52 | }
53 |
54 | Vector vector = Vector.Build.Sparse(order);
55 | vector.At(value, Complex.One);
56 |
57 | return vector;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/QuantumComputing/Qubit.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using System;
8 | using System.Numerics;
9 |
10 | namespace Lachesis.QuantumComputing
11 | {
12 | public class Qubit : QuantumRegister
13 | {
14 | /*
15 | * Probability amplitude for state |0>
16 | */
17 | public Complex ZeroAmplitude
18 | {
19 | get
20 | {
21 | return this.Vector.At(0);
22 | }
23 | private set
24 | {
25 | this.Vector.At(0, value);
26 | }
27 | }
28 |
29 | /*
30 | * Probability amplitude for state |1>
31 | */
32 | public Complex OneAmplitude
33 | {
34 | get
35 | {
36 | return this.Vector.At(1);
37 | }
38 | private set
39 | {
40 | this.Vector.At(1, value);
41 | }
42 | }
43 |
44 | /*
45 | * Constructor from probability amplitudes
46 | */
47 | public Qubit(Complex zeroAmplitude, Complex oneAmplitude) : base(zeroAmplitude, oneAmplitude) { }
48 |
49 | /*
50 | * Constructor from parts of probability amplitudes
51 | */
52 | public Qubit(double zeroAmplitudeReal, double zeroAmplitudeImaginary, double oneAmplitudeReal, double oneAmplitudeImaginary) : base(new Complex(zeroAmplitudeReal, zeroAmplitudeImaginary), new Complex(oneAmplitudeReal, oneAmplitudeImaginary)) { }
53 |
54 | /*
55 | * Constructor from Bloch sphere coordinates
56 | */
57 | public Qubit(double colatitude, double longitude) : base(Math.Cos(colatitude / 2), Math.Sin(colatitude / 2) * Mathematics.Numerics.ComplexExp(Complex.ImaginaryOne * longitude)) { }
58 |
59 | /*
60 | * Normalizes a qubit
61 | */
62 | protected override void Normalize()
63 | {
64 | // Normalize magnitude
65 | base.Normalize();
66 |
67 | // Normalize phase
68 | if (this.ZeroAmplitude.Phase != 0)
69 | {
70 | this.ZeroAmplitude = this.ZeroAmplitude * Complex.FromPolarCoordinates(1, -this.ZeroAmplitude.Phase);
71 | this.OneAmplitude = this.OneAmplitude * Complex.FromPolarCoordinates(1, -this.ZeroAmplitude.Phase);
72 | }
73 | }
74 |
75 | /*
76 | * |0>
77 | */
78 | public static Qubit Zero
79 | {
80 | get
81 | {
82 | return new Qubit(Complex.One, Complex.Zero);
83 | }
84 | }
85 |
86 | /*
87 | * |1>
88 | */
89 | public static Qubit One
90 | {
91 | get
92 | {
93 | return new Qubit(Complex.Zero, Complex.One);
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/QuantumGateTests.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using MathNet.Numerics.IntegralTransforms;
8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
9 | using System;
10 | using System.Numerics;
11 |
12 | namespace Lachesis.QuantumComputing.Tests
13 | {
14 | [TestClass]
15 | public class QuantumGateTests
16 | {
17 | [TestMethod]
18 | public void QuantumGate_HadamardGateOfLength2_IsValid()
19 | {
20 | Assert.IsTrue(QuantumGate.HadamardGateOfLength(2).AlmostEquals(new QuantumGate(new Complex[,] {
21 | { 0.5, 0.5, 0.5, 0.5 },
22 | { 0.5, -0.5, 0.5, -0.5 },
23 | { 0.5, 0.5, -0.5, -0.5 },
24 | { 0.5, -0.5, -0.5, 0.5 },
25 | })));
26 | }
27 |
28 | [TestMethod]
29 | public void QuantumGate_PhaseShiftGateFromPiOverTwo_IsValid()
30 | {
31 | Assert.IsTrue(QuantumGate.PhaseShiftGate(Math.PI / 2).AlmostEquals(new QuantumGate(new Complex[,] {
32 | { 1, 0 },
33 | { 0, Complex.ImaginaryOne },
34 | })));
35 | }
36 |
37 | [TestMethod]
38 | public void QuantumGate_ControlledGateFromNotGate_IsValid()
39 | {
40 | Assert.AreEqual(QuantumGate.ControlledGate(QuantumGate.NotGate), new QuantumGate(new Complex[,] {
41 | { 1, 0, 0, 0 },
42 | { 0, 1, 0, 0 },
43 | { 0, 0, 0, 1 },
44 | { 0, 0, 1, 0 },
45 | }));
46 | }
47 |
48 | [TestMethod]
49 | [ExpectedException(typeof(ArgumentException))]
50 | public void QuantumGate_ControlledGateFromControlledNotGate_ThrowsArgumentException()
51 | {
52 | QuantumGate quantumGate = QuantumGate.ControlledGate(QuantumGate.ControlledGate(QuantumGate.NotGate));
53 | }
54 |
55 | [TestMethod]
56 | public void QuantumGate_QuantumFourierTranform_IsValid()
57 | {
58 | // Start with unnormalized samples
59 | Complex[] samples = new Complex[] { Complex.One, Complex.One + Complex.ImaginaryOne, Complex.ImaginaryOne, Complex.One - Complex.ImaginaryOne, Complex.One, Complex.Zero, Complex.ImaginaryOne, Complex.ImaginaryOne };
60 |
61 | // Create a quantum register from samples
62 | QuantumRegister quantumRegister = new QuantumRegister(samples);
63 |
64 | // Get normalized samples
65 | samples = quantumRegister.Vector.ToArray();
66 |
67 | // Transform quantum register
68 | quantumRegister = QuantumGate.QuantumFourierTransform(3) * quantumRegister;
69 |
70 | // Transform samples independently using Math.NET
71 | Fourier.Inverse(samples);
72 |
73 | // Compare results
74 | Assert.IsTrue(quantumRegister.AlmostEquals(new QuantumRegister(samples)));
75 | }
76 |
77 | [TestMethod]
78 | public void QuantumGate_ApplicationToQuantumRegister_IsValid()
79 | {
80 | Assert.AreEqual(QuantumGate.NotGate * Qubit.Zero, Qubit.One);
81 | }
82 |
83 | [TestMethod]
84 | public void QuantumGate_CombinedApplicationToQuantumRegister_IsValid()
85 | {
86 | QuantumGate quantumGate = new QuantumGate(QuantumGate.NotGate, QuantumGate.IdentityGate);
87 | QuantumRegister quantumRegister = new QuantumRegister(Qubit.Zero, Qubit.One);
88 | Assert.AreEqual(quantumGate * quantumRegister, new QuantumRegister(Qubit.One, Qubit.One));
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/QuantumComputing/QuantumComputing.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D5EC7B3D-0BA2-43E3-B1D8-88B5DA2CE813}
8 | Library
9 | Properties
10 | QuantumComputing
11 | QuantumComputing
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 | ..\..\packages\MathNet.Numerics.3.19.0\lib\net40\MathNet.Numerics.dll
35 | True
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
69 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/QuantumRegisterTests.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using Microsoft.VisualStudio.TestTools.UnitTesting;
8 | using Moq;
9 | using System;
10 | using System.Numerics;
11 |
12 | namespace Lachesis.QuantumComputing.Tests
13 | {
14 | [TestClass]
15 | public class QuantumRegisterTests
16 | {
17 | private static Random Random;
18 |
19 | [ClassInitialize]
20 | public static void ClassInit(TestContext context)
21 | {
22 | QuantumRegisterTests.Random = new Random();
23 | }
24 |
25 | [TestMethod]
26 | public void QuantumRegister_FromInteger_IsValid()
27 | {
28 | Assert.AreEqual(new QuantumRegister(15), new QuantumRegister(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1));
29 | }
30 |
31 | [TestMethod]
32 | public void QuantumRegister_FromIntegerWithBitCount_IsValid()
33 | {
34 | Assert.AreEqual(new QuantumRegister(7, 4), new QuantumRegister(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0));
35 | }
36 |
37 | [TestMethod]
38 | [ExpectedException(typeof(ArgumentException))]
39 | public void QuantumRegister_FromIntegerWithLowBitCount_ThrowsArgumentException()
40 | {
41 | QuantumRegister quantumRegister = new QuantumRegister(7, 2);
42 | }
43 |
44 | [TestMethod]
45 | public void QuantumRegister_FromQuantumRegisters_IsValid()
46 | {
47 | Assert.AreEqual(new QuantumRegister(Qubit.One, QuantumRegister.EPRPair), new QuantumRegister(0, 0, 0, 0, 1 / Math.Sqrt(2), 0, 0, 1 / Math.Sqrt(2)));
48 | }
49 |
50 | [TestMethod]
51 | public void QuantumRegister_FromVector_IsValid()
52 | {
53 | Assert.AreEqual(new QuantumRegister(QuantumRegister.EPRPair.Vector), QuantumRegister.EPRPair);
54 | }
55 |
56 | [TestMethod]
57 | [ExpectedException(typeof(ArgumentException))]
58 | public void QuantumRegister_FromVectorNotInAPowerOfTwoDimension_ThrowsArgumentException()
59 | {
60 | QuantumRegister quantumRegister = new QuantumRegister(Complex.One, Complex.Zero, Complex.One);
61 | }
62 |
63 | [TestMethod]
64 | public void QuantumRegister_CollapsePureState_StaysTheSame()
65 | {
66 | QuantumRegister zeroOne = new QuantumRegister(Qubit.Zero, Qubit.One);
67 | zeroOne.Collapse(QuantumRegisterTests.Random);
68 | Assert.AreEqual(zeroOne, new QuantumRegister(Qubit.Zero, Qubit.One));
69 | }
70 |
71 | [TestMethod]
72 | public void QuantumRegister_CollapseEPRPair_Is00Or11()
73 | {
74 | QuantumRegister quantumRegister = QuantumRegister.EPRPair;
75 | quantumRegister.Collapse(QuantumRegisterTests.Random);
76 | Assert.IsTrue(quantumRegister.Equals(new QuantumRegister(Qubit.Zero, Qubit.Zero)) || quantumRegister.Equals(new QuantumRegister(Qubit.One, Qubit.One)));
77 | }
78 |
79 | [TestMethod]
80 | public void QuantumRegister_CollapseWState_WithRandomMock_Is001()
81 | {
82 | QuantumRegister quantumRegister = QuantumRegister.WState;
83 | Random randomMock = Mock.Of();
84 | Mock.Get(randomMock).Setup(random => random.NextDouble()).Returns(0.2);
85 | quantumRegister.Collapse(randomMock);
86 | Assert.IsTrue(quantumRegister.Equals(new QuantumRegister(Qubit.Zero, Qubit.Zero, Qubit.One)));
87 | }
88 |
89 | [TestMethod]
90 | public void QuantumRegister_GetValue_IsValid()
91 | {
92 | QuantumRegister quantumRegister = new QuantumRegister(27);
93 |
94 | Assert.AreEqual(quantumRegister.GetValue(), 27);
95 | Assert.AreEqual(quantumRegister.GetValue(1), 11);
96 | Assert.AreEqual(quantumRegister.GetValue(1, 3), 5);
97 | }
98 |
99 | [TestMethod]
100 | [ExpectedException(typeof(ArgumentException))]
101 | public void QuantumRegister_GetValueWithOverflow_ThrowsArgumentException()
102 | {
103 | QuantumRegister quantumRegister = new QuantumRegister(5);
104 | quantumRegister.GetValue(1, 3);
105 | }
106 |
107 | [TestMethod]
108 | [ExpectedException(typeof(SystemException))]
109 | public void QuantumRegister_GetValueOnMixedState_ThrowsSystemException()
110 | {
111 | Qubit.EPRPair.GetValue();
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/QuantumComputing.Tests/QuantumComputing.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {1DD6ADC4-F9BA-4A18-8E31-6BB931CE1C81}
7 | Library
8 | Properties
9 | QuantumComputing.Tests
10 | QuantumComputing.Tests
11 | v4.5.2
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll
40 | True
41 |
42 |
43 | ..\..\packages\MathNet.Numerics.3.17.0\lib\net40\MathNet.Numerics.dll
44 | True
45 |
46 |
47 | ..\..\packages\Moq.4.7.9\lib\net45\Moq.dll
48 | True
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | {d5ec7b3d-0ba2-43e3-b1d8-88b5da2ce813}
77 | QuantumComputing
78 |
79 |
80 |
81 |
82 |
83 |
84 | False
85 |
86 |
87 | False
88 |
89 |
90 | False
91 |
92 |
93 | False
94 |
95 |
96 |
97 |
98 |
99 |
100 |
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quantum.NET (Lachesis.QuantumComputing)
2 |
3 | ## Description
4 |
5 | A library to manipulate qubits and simulate quantum circuits.
6 |
7 | ## Usage
8 |
9 | A qubit can be created from its probability amplitudes:
10 |
11 | ```csharp
12 | Qubit qubit = new Qubit(Complex.One / Math.Sqrt(2), Complex.ImaginaryOne / Math.Sqrt(2)); // (|0> + i |1>) / √2
13 | ```
14 |
15 | Or from its amplitudes' real and imaginary parts:
16 |
17 | ```csharp
18 | Qubit qubit = new Qubit(1 / Math.Sqrt(2), 0, 0, 1 / Math.Sqrt(2)); // (|0> + i |1>) / √2
19 | ```
20 |
21 | It can also be created from its colatitude and longitude on the [Bloch sphere](https://en.wikipedia.org/wiki/Bloch_sphere):
22 |
23 | ```csharp
24 | Qubit qubit = new Qubit(Math.PI / 2, 0); // (|0> + |1>) / √2
25 | ```
26 |
27 | Shortcuts are available for notable qubits:
28 |
29 | ```csharp
30 | Qubit zero = Qubit.Zero; // |0>
31 | Qubit one = Qubit.One; // |1>
32 | ```
33 |
34 | A qubit is a quantum register of length 1 and can be manipulated as such. The `Qubit` class is merely a subclass of `QuantumRegister` designed for ease of use:
35 |
36 | ```csharp
37 | QuantumRegister quantumRegister = Qubit.Zero;
38 | ```
39 |
40 | Shortcuts are also available for notable quantum registers:
41 |
42 | ```csharp
43 | QuantumRegister EPRPair = QuantumRegister.EPRPair; // (|00> + |11>) / √2 (Einstein–Podolsky–Rosen pair)
44 | QuantumRegister WState = QuantumRegister.WState; // (|001> + |010> + |100>) / √3 (W state)
45 | QuantumRegister WState4 = QuantumRegister.WStateOfLength(4); // (|0001> + |0010> + |0100> + |1000>) / 2 (generalized W state for 4 qubits)
46 | QuantumRegister GHZState = QuantumRegister.GHZState; // (|000> + |111>) / √2 (simplest Greenberger–Horne–Zeilinger state)
47 | QuantumRegister GHZState4 = QuantumRegister.GHZStateOfLength(4); // (|0000> + |1111>) / √2 (GHZ state for 4 qubits)
48 | ```
49 |
50 | A quantum register can be created from other quantum registers (variadic constructor, also works with `QuantumRegister[]` and `IEnumerable`):
51 |
52 | ```csharp
53 | QuantumRegister quantumRegister = new QuantumRegister(Qubit.Zero, QuantumRegister.EPRPair); // (|000> + |011>) / √2
54 | ```
55 |
56 | Or from the 2n complex probability amplitudes of each of its pure states (variadic constructor, also works with `Complex[]` and `IEnumerable`):
57 |
58 | ```csharp
59 | QuantumRegister quantumRegister = new QuantumRegister(0, 1 / Math.Sqrt(2), 1 / Math.Sqrt(2), 0); // (|01> + |10>) / √2
60 | QuantumRegister error = new QuantumRegister(0, 1, 0); // the number of amplitudes is not a power of 2; throws System.ArgumentException
61 | ```
62 |
63 | Quantum registers are mostly used to represent numbers and can therefore be created from integers (this will naturally generate pure states):
64 |
65 | ```csharp
66 | QuantumRegister seven = new QuantumRegister(7); // |111>
67 | QuantumRegister threeOnThreeBits = new QuantumRegister(3, 3); // |011>
68 | ```
69 |
70 | A quantum register can be observed and collapse into a pure state (note: use your own `Random` instance to avoid issues with pseudorandom number generator determinism):
71 |
72 | ```csharp
73 | Random random = new Random();
74 | QuantumRegister quantumRegister = QuantumRegister.EPRPair;
75 | quantumRegister.Collapse(random); // |00> or |11>
76 | ```
77 |
78 | A pure state quantum register can be read to obtain the number it represents, with optional offset and length parameters to read a subsection only:
79 |
80 | ```csharp
81 | QuantumRegister quantumRegister = new QuantumRegister(27); // |11011>
82 | int a = quantumRegister.GetValue(); // 27 (0b11011)
83 | int b = quantumRegister.GetValue(1); // 11 (0b1011)
84 | int c = quantumRegister.GetValue(1, 3); // 5 (0b101)
85 | int d = Qubit.EPRPair.GetValue(); // cannot be used on a mixed state; throws System.SystemException
86 | ```
87 |
88 | Quantum gates are required to operate on quantum registers. Shortcuts are also available for notable quantum gates:
89 |
90 | * `QuantumGate.IdentityGate`
91 | * `QuantumGate.IdentityGateOfLength(int registerLength)`
92 | * `QuantumGate.HadamardGate`
93 | * `QuantumGate.HadamardGateOfLength(int registerLength)`
94 | * `QuantumGate.NotGate`
95 | * `QuantumGate.PauliYGate`
96 | * `QuantumGate.PauliZGate`
97 | * `QuantumGate.SquareRootNotGate`
98 | * `QuantumGate.PhaseShiftGate(double phase)`
99 | * `QuantumGate.SwapGate`
100 | * `QuantumGate.SquareRootSwapGate`
101 | * `QuantumGate.ControlledNotGate`
102 | * `QuantumGate.ControlledGate(QuantumGate gate)`
103 | * `QuantumGate.ToffoliGate`
104 | * `QuantumGate.FredkinGate`
105 | * `QuantumGate.QuantumFourierTransform(int registerLength)`
106 |
107 | A quantum gate can be created from other quantum gates (variadic constructor, also works with `QuantumGate[]` and `IEnumerable`):
108 |
109 | ```csharp
110 | QuantumGate quantumGate = new QuantumGate(QuantumGate.PauliZGate, QuantumGate.IdentityGate); // This gate will apply the Pauli-Z gate to the first qubit and leave the second one unchanged
111 | ```
112 |
113 | Or from a bidimensional array of complex numbers:
114 |
115 | ```csharp
116 | QuantumGate quantumGate = new QuantumGate(new Complex[,] {
117 | { 1, 1 },
118 | { 1, 0 },
119 | });
120 | ```
121 |
122 | Applying a quantum gate to a quantum register is as simple as using the multiplication operator on them:
123 |
124 | ```csharp
125 | QuantumRegister quantumRegister = Qubit.Zero; // |0>
126 | quantumRegister = QuantumGate.HadamardGate * quantumRegister; // (|0> + |1>) / √2
127 | quantumRegister = QuantumGate.HadamardGate * quantumRegister; // |0>
128 | quantumRegister = QuantumGate.NotGate * quantumRegister; // |1>
129 | ```
130 |
131 | Unary gates only operate on one qubit, binary gates on two, etc.:
132 |
133 | ```csharp
134 | QuantumRegister error = QuantumGate.PauliYGate * QuantumRegister.EPRPair; // a unary gate cannot be applied to two qubits; throws System.ArgumentException
135 | ```
136 |
137 | Please note that this is not a literal arithmetic library. While measures have been taken to circumvent a range of errors caused by floating-point precision, the use of `QuantumRegister.AlmostEquals` might be required in places:
138 |
139 | ```csharp
140 | QuantumRegister almostOne = new Qubit(Complex.One, Math.Cos(Math.PI / 2) * Complex.One);
141 | QuantumRegister one = new Qubit(Complex.One, 0);
142 | almostOne.AlmostEquals(one); // true
143 | ```
144 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | # =========================
255 | # Operating System Files
256 | # =========================
257 |
258 | # OSX
259 | # =========================
260 |
261 | .DS_Store
262 | .AppleDouble
263 | .LSOverride
264 |
265 | # Thumbnails
266 | ._*
267 |
268 | # Files that might appear in the root of a volume
269 | .DocumentRevisions-V100
270 | .fseventsd
271 | .Spotlight-V100
272 | .TemporaryItems
273 | .Trashes
274 | .VolumeIcon.icns
275 |
276 | # Directories potentially created on remote AFP share
277 | .AppleDB
278 | .AppleDesktop
279 | Network Trash Folder
280 | Temporary Items
281 | .apdisk
282 |
283 | # Windows
284 | # =========================
285 |
286 | # Windows image file caches
287 | Thumbs.db
288 | ehthumbs.db
289 |
290 | # Folder config file
291 | Desktop.ini
292 |
293 | # Recycle Bin used on file shares
294 | $RECYCLE.BIN/
295 |
296 | # Windows Installer files
297 | *.cab
298 | *.msi
299 | *.msm
300 | *.msp
301 |
302 | # Windows shortcuts
303 | *.lnk
304 |
--------------------------------------------------------------------------------
/src/QuantumComputing/QuantumRegister.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using MathNet.Numerics.LinearAlgebra;
8 | using MathNet.Numerics;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Numerics;
13 |
14 | namespace Lachesis.QuantumComputing
15 | {
16 | public class QuantumRegister
17 | {
18 | /*
19 | * Vector representation of a quantum register
20 | */
21 | public Vector Vector { get; protected set; }
22 |
23 | /*
24 | * Constructor from integer
25 | */
26 | public QuantumRegister(int value, int bitCount = 0) : this(Mathematics.LinearAlgebra.VectorFromInteger(value, bitCount)) { }
27 |
28 | /*
29 | * Constructor from other quantum registers
30 | */
31 | public QuantumRegister(params QuantumRegister[] quantumRegisters) : this((IEnumerable)quantumRegisters) { }
32 |
33 | /*
34 | * Constructor from enumerable of other quantum registers
35 | */
36 | public QuantumRegister(IEnumerable quantumRegisters)
37 | {
38 | this.Vector = quantumRegisters.Aggregate(Vector.Build.Sparse(1, Complex.One), (vector, quantumRegister) => Mathematics.LinearAlgebra.CartesianProduct(vector, quantumRegister.Vector));
39 | }
40 |
41 | /*
42 | * Constructor from probability amplitudes
43 | */
44 | public QuantumRegister(params Complex[] array) : this((IEnumerable)array) { }
45 |
46 | /*
47 | * Constructor from enumerable of probability amplitudes
48 | */
49 | public QuantumRegister(IEnumerable enumerable) : this(Vector.Build.SparseOfEnumerable(enumerable)) { }
50 |
51 | /*
52 | * Constructor from vector representation
53 | */
54 | public QuantumRegister(Vector vector)
55 | {
56 | if ((vector.Count & (vector.Count - 1)) != 0)
57 | {
58 | throw new ArgumentException("A quantum register can only be initialized from a vector whose dimension is a power of 2.");
59 | }
60 |
61 | this.Vector = vector;
62 |
63 | this.Normalize();
64 | }
65 |
66 | /*
67 | * Normalizes a quantum register
68 | */
69 | protected virtual void Normalize()
70 | {
71 | // Normalize magnitude
72 | double magnitudeFactor = Math.Sqrt(this.Vector.Aggregate(0.0, (factor, amplitude) => factor + amplitude.MagnitudeSquared()));
73 | if (magnitudeFactor != 1)
74 | {
75 | this.Vector = this.Vector / magnitudeFactor;
76 | }
77 | }
78 |
79 | /*
80 | * Collapses a quantum register into a pure state
81 | */
82 | public void Collapse(Random random)
83 | {
84 | Vector collapsedVector = Vector.Build.Sparse(this.Vector.Count);
85 | double probabilitySum = 0d;
86 | double probabilityThreshold = random.NextDouble();
87 |
88 | for (int i = 0; i < this.Vector.Count; i++)
89 | {
90 | probabilitySum += this.Vector.At(i).MagnitudeSquared();
91 |
92 | if (probabilitySum > probabilityThreshold)
93 | {
94 | collapsedVector.At(i, Complex.One);
95 | break;
96 | }
97 | }
98 |
99 | this.Vector = collapsedVector;
100 | }
101 |
102 | /*
103 | * Returns the value contained in a quantum register, with optional portion start and length
104 | */
105 | public int GetValue(int portionStart = 0, int portionLength = 0)
106 | {
107 | int registerLength = Mathematics.Numerics.Log2(this.Vector.Count - 1);
108 |
109 | if (portionLength == 0)
110 | {
111 | portionLength = registerLength - portionStart;
112 | }
113 |
114 | int trailingBitCount = registerLength - portionStart - portionLength;
115 |
116 | if (trailingBitCount < 0)
117 | {
118 | throw new ArgumentException("The supplied portion overflows the given quantum register.");
119 | }
120 |
121 | int index = -1;
122 |
123 | for (int i = 0; i < this.Vector.Count; i++)
124 | {
125 | if (this.Vector.At(i) == 1)
126 | {
127 | index = i;
128 | break;
129 | }
130 | }
131 |
132 | if (index == -1)
133 | {
134 | throw new SystemException("A value can only be extracted from a pure state quantum register.");
135 | }
136 |
137 | // If trailing bits need to be removed
138 | if (trailingBitCount > 0)
139 | {
140 | index >>= trailingBitCount;
141 | }
142 |
143 | // If leading bits need to be removed
144 | if (portionStart > 0)
145 | {
146 | index &= (1 << portionLength) - 1;
147 | }
148 |
149 | return index;
150 | }
151 |
152 | /*
153 | * Einstein–Podolsky–Rosen pair
154 | */
155 | public static QuantumRegister EPRPair
156 | {
157 | get
158 | {
159 | return new QuantumRegister(Vector.Build.SparseOfArray(new Complex[] { Complex.One, Complex.Zero, Complex.Zero, Complex.One }) / Math.Sqrt(2));
160 | }
161 | }
162 |
163 | /*
164 | * W state
165 | */
166 | public static QuantumRegister WState
167 | {
168 | get
169 | {
170 | return QuantumRegister.WStateOfLength(3);
171 | }
172 | }
173 |
174 | /*
175 | * Generalized W state
176 | */
177 | public static QuantumRegister WStateOfLength(int length)
178 | {
179 | Vector vector = Vector.Build.Sparse(1 << length);
180 |
181 | for (int i = 0; i < length; i++)
182 | {
183 | vector.At(1 << i, Complex.One);
184 | }
185 |
186 | return new QuantumRegister(vector / Math.Sqrt(3));
187 | }
188 |
189 | /*
190 | * Simplest Greenberger–Horne–Zeilinger state
191 | */
192 | public static QuantumRegister GHZState
193 | {
194 | get
195 | {
196 | return QuantumRegister.GHZStateOfLength(3);
197 | }
198 | }
199 |
200 | /*
201 | * Greenberger–Horne–Zeilinger state
202 | */
203 | public static QuantumRegister GHZStateOfLength(int length)
204 | {
205 | Vector vector = Vector.Build.Sparse(1 << length);
206 |
207 | vector.At(0, Complex.One);
208 | vector.At((1 << length) - 1, Complex.One);
209 |
210 | return new QuantumRegister(vector / Math.Sqrt(2));
211 | }
212 |
213 | /*
214 | * String representation of a quantum register
215 | */
216 | public override string ToString()
217 | {
218 | string representation = "";
219 |
220 | for (int i = 0; i < this.Vector.Count; i++)
221 | {
222 | Complex amplitude = this.Vector.At(i);
223 |
224 | if (amplitude != 0)
225 | {
226 | string complexString = "";
227 |
228 | if (amplitude.Real < 0 || amplitude.Real == 0 && amplitude.Imaginary < 0)
229 | {
230 | complexString += " - ";
231 | amplitude = -amplitude;
232 | }
233 | else if (representation.Length > 0)
234 | {
235 | complexString += " + ";
236 | }
237 |
238 | if (amplitude != 1)
239 | {
240 | if (amplitude.Real != 0 && amplitude.Imaginary != 0)
241 | {
242 | complexString += "(";
243 | }
244 |
245 | if (amplitude.Real != 0)
246 | {
247 | complexString += amplitude.Real;
248 | }
249 |
250 | if (amplitude.Real != 0 && amplitude.Imaginary > 0)
251 | {
252 | complexString += " + ";
253 | }
254 |
255 | if (amplitude.Imaginary != 0)
256 | {
257 | complexString += amplitude.Imaginary + " i";
258 | }
259 |
260 | if (amplitude.Real != 0 && amplitude.Imaginary != 0)
261 | {
262 | complexString += ")";
263 | }
264 |
265 | complexString += " ";
266 | }
267 |
268 | representation += complexString + "|" + Convert.ToString(i, 2) + ">";
269 | }
270 | }
271 |
272 | return representation;
273 | }
274 |
275 | /*
276 | * Determines whether the specified quantum register is equal to the current quantum register
277 | */
278 | public override bool Equals(object obj)
279 | {
280 | QuantumRegister quantumRegister = obj as QuantumRegister;
281 |
282 | if (quantumRegister == null || this.Vector.Count != quantumRegister.Vector.Count)
283 | {
284 | return false;
285 | }
286 |
287 | return this.Vector.Equals(quantumRegister.Vector);
288 | }
289 |
290 | /*
291 | * Determines whether the specified quantum register is equal to the current quantum register, ignoring floating-point precision issues
292 | */
293 | public bool AlmostEquals(object obj)
294 | {
295 | QuantumRegister quantumRegister = obj as QuantumRegister;
296 |
297 | if (quantumRegister == null || this.Vector.Count != quantumRegister.Vector.Count)
298 | {
299 | return false;
300 | }
301 |
302 | return Precision.AlmostEqual(this.Vector, quantumRegister.Vector, 15);
303 | }
304 |
305 | /*
306 | * Serves as a hash function for a quantum register
307 | */
308 | public override int GetHashCode()
309 | {
310 | return this.Vector.GetHashCode();
311 | }
312 | }
313 | }
314 |
--------------------------------------------------------------------------------
/src/QuantumComputing/QuantumGate.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Quantum.NET
3 | * A library to manipulate qubits and simulate quantum circuits
4 | * Author: Pierre-Henry Baudin
5 | */
6 |
7 | using MathNet.Numerics.LinearAlgebra;
8 | using MathNet.Numerics;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Numerics;
13 |
14 | namespace Lachesis.QuantumComputing
15 | {
16 | public class QuantumGate
17 | {
18 | /*
19 | * Matrix representation of a quantum gate
20 | */
21 | public Matrix Matrix { get; private set; }
22 |
23 | /*
24 | * Constructor from other quantum gates
25 | */
26 | public QuantumGate(params QuantumGate[] quantumGates) : this((IEnumerable)quantumGates) { }
27 |
28 | /*
29 | * Constructor from enumerable of other quantum gates
30 | */
31 | public QuantumGate(IEnumerable quantumGates)
32 | {
33 | this.Matrix = quantumGates.Aggregate(Matrix.Build.Sparse(1, 1, Complex.One), (matrix, quantumGate) => matrix.KroneckerProduct(quantumGate.Matrix));
34 | }
35 |
36 | /*
37 | * Constructor from a bidimensional array of complex coefficients
38 | */
39 | public QuantumGate(Complex[,] coefficients) : this(Matrix.Build.SparseOfArray(coefficients)) { }
40 |
41 | /*
42 | * Constructor from matrix representation
43 | */
44 | public QuantumGate(Matrix matrix)
45 | {
46 | if ((matrix.ColumnCount & (matrix.ColumnCount - 1)) != 0 || matrix.ColumnCount != matrix.RowCount)
47 | {
48 | throw new ArgumentException("A quantum gate can only be initialized from a square matrix whose order is a power of 2.");
49 | }
50 |
51 | this.Matrix = matrix;
52 | }
53 |
54 | /*
55 | * Identity gate
56 | */
57 | public static QuantumGate IdentityGate
58 | {
59 | get
60 | {
61 | return QuantumGate.IdentityGateOfLength(1);
62 | }
63 | }
64 |
65 | /*
66 | * Stacked identity gates
67 | */
68 | public static QuantumGate IdentityGateOfLength(int registerLength)
69 | {
70 | return new QuantumGate(Matrix.Build.SparseIdentity(1 << registerLength));
71 | }
72 |
73 | /*
74 | * Hadamard gate
75 | */
76 | public static QuantumGate HadamardGate
77 | {
78 | get
79 | {
80 | return new QuantumGate(Matrix.Build.SparseOfArray(new Complex[,] {
81 | { 1, 1 },
82 | { 1, -1 },
83 | }) / Math.Sqrt(2));
84 | }
85 | }
86 |
87 | /*
88 | * Generalized Hadamard gate
89 | */
90 | public static QuantumGate HadamardGateOfLength(int registerLength)
91 | {
92 | if (registerLength == 1)
93 | {
94 | return QuantumGate.HadamardGate;
95 | }
96 | else
97 | {
98 | return new QuantumGate(QuantumGate.HadamardGate, QuantumGate.HadamardGateOfLength(registerLength - 1));
99 | }
100 | }
101 |
102 | /*
103 | * NOT gate (Pauli-X gate)
104 | */
105 | public static QuantumGate NotGate
106 | {
107 | get
108 | {
109 | return new QuantumGate(new Complex[,] {
110 | { 0, 1 },
111 | { 1, 0 },
112 | });
113 | }
114 | }
115 |
116 | /*
117 | * Pauli-Y gate
118 | */
119 | public static QuantumGate PauliYGate
120 | {
121 | get
122 | {
123 | return new QuantumGate(new Complex[,] {
124 | { 0, -Complex.ImaginaryOne },
125 | { Complex.ImaginaryOne, 0 },
126 | });
127 | }
128 | }
129 |
130 | /*
131 | * Pauli-Z gate
132 | */
133 | public static QuantumGate PauliZGate
134 | {
135 | get
136 | {
137 | return new QuantumGate(new Complex[,] {
138 | { 1, 0 },
139 | { 0, -1 },
140 | });
141 | }
142 | }
143 |
144 | /*
145 | * Square root of NOT gate
146 | */
147 | public static QuantumGate SquareRootNotGate
148 | {
149 | get
150 | {
151 | return new QuantumGate(Matrix.Build.SparseOfArray(new Complex[,] {
152 | { 1 + Complex.ImaginaryOne, 1 - Complex.ImaginaryOne },
153 | { 1 - Complex.ImaginaryOne, 1 + Complex.ImaginaryOne },
154 | }) / 2);
155 | }
156 | }
157 |
158 | /*
159 | * Phase shift gate
160 | */
161 | public static QuantumGate PhaseShiftGate(double phase)
162 | {
163 | return new QuantumGate(new Complex[,] {
164 | { 1, 0 },
165 | { 0, Mathematics.Numerics.ComplexExp(Complex.ImaginaryOne * phase)},
166 | });
167 | }
168 |
169 | /*
170 | * Swap gate
171 | */
172 | public static QuantumGate SwapGate
173 | {
174 | get
175 | {
176 | return new QuantumGate(new Complex[,] {
177 | { 1, 0, 0, 0 },
178 | { 0, 0, 1, 0 },
179 | { 0, 1, 0, 0 },
180 | { 0, 0, 0, 1 },
181 | });
182 | }
183 | }
184 |
185 | /*
186 | * Square root of swap gate
187 | */
188 | public static QuantumGate SquareRootSwapGate
189 | {
190 | get
191 | {
192 | return new QuantumGate(new Complex[,] {
193 | { 1, 0, 0, 0 },
194 | { 0, (1 + Complex.ImaginaryOne) / 2, (1 - Complex.ImaginaryOne) / 2, 0 },
195 | { 0, (1 - Complex.ImaginaryOne) / 2, (1 + Complex.ImaginaryOne) / 2, 0 },
196 | { 0, 0, 0, 1 },
197 | });
198 | }
199 | }
200 |
201 | /*
202 | * Controlled NOT gate
203 | */
204 | public static QuantumGate ControlledNotGate
205 | {
206 | get
207 | {
208 | return QuantumGate.ControlledGate(QuantumGate.NotGate);
209 | }
210 | }
211 |
212 | /*
213 | * Controlled gate
214 | */
215 | public static QuantumGate ControlledGate(QuantumGate gate)
216 | {
217 | if (gate.Matrix.ColumnCount != 2 || gate.Matrix.RowCount != 2)
218 | {
219 | throw new ArgumentException("A controlled gate can only be created from a unary gate.");
220 | }
221 |
222 | return new QuantumGate(new Complex[,] {
223 | { 1, 0, 0, 0 },
224 | { 0, 1, 0, 0 },
225 | { 0, 0, gate.Matrix.At(0, 0), gate.Matrix.At(0, 1) },
226 | { 0, 0, gate.Matrix.At(1, 0), gate.Matrix.At(1, 1) },
227 | });
228 | }
229 |
230 | /*
231 | * Toffoli gate
232 | */
233 | public static QuantumGate ToffoliGate
234 | {
235 | get
236 | {
237 | return new QuantumGate(new Complex[,] {
238 | { 1, 0, 0, 0, 0, 0, 0, 0 },
239 | { 0, 1, 0, 0, 0, 0, 0, 0 },
240 | { 0, 0, 1, 0, 0, 0, 0, 0 },
241 | { 0, 0, 0, 1, 0, 0, 0, 0 },
242 | { 0, 0, 0, 0, 1, 0, 0, 0 },
243 | { 0, 0, 0, 0, 0, 1, 0, 0 },
244 | { 0, 0, 0, 0, 0, 0, 0, 1 },
245 | { 0, 0, 0, 0, 0, 0, 1, 0 },
246 | });
247 | }
248 | }
249 |
250 | /*
251 | * Fredkin gate
252 | */
253 | public static QuantumGate FredkinGate
254 | {
255 | get
256 | {
257 | return new QuantumGate(new Complex[,] {
258 | { 1, 0, 0, 0, 0, 0, 0, 0 },
259 | { 0, 1, 0, 0, 0, 0, 0, 0 },
260 | { 0, 0, 1, 0, 0, 0, 0, 0 },
261 | { 0, 0, 0, 1, 0, 0, 0, 0 },
262 | { 0, 0, 0, 0, 1, 0, 0, 0 },
263 | { 0, 0, 0, 0, 0, 0, 1, 0 },
264 | { 0, 0, 0, 0, 0, 1, 0, 0 },
265 | { 0, 0, 0, 0, 0, 0, 0, 1 },
266 | });
267 | }
268 | }
269 |
270 | /*
271 | * Quantum Fourier transform
272 | */
273 | public static QuantumGate QuantumFourierTransform(int registerLength)
274 | {
275 | int order = 1 << registerLength;
276 |
277 | Matrix matrix = Matrix.Build.Sparse(order, order);
278 |
279 | // Only n distinct coefficients are found in the quantum Fourier transform matrix
280 | Complex[] coefficients = new Complex[order];
281 | for (int i = 0; i < order; i++)
282 | {
283 | coefficients[i] = Mathematics.Numerics.ComplexExp(Complex.ImaginaryOne * 2 * Math.PI * i / order) / Math.Sqrt(order);
284 | }
285 |
286 | // Populate matrix
287 | for (int i = 0; i < order; i++)
288 | {
289 | for (int j = 0; j < order; j++)
290 | {
291 | matrix.At(i, j, coefficients[i * j % order]);
292 | }
293 | }
294 |
295 | return new QuantumGate(matrix);
296 | }
297 |
298 | /*
299 | * Operator to apply a quantum gate to a quantum register
300 | */
301 | public static QuantumRegister operator *(QuantumGate quantumGate, QuantumRegister quantumRegister)
302 | {
303 | return new QuantumRegister(quantumGate.Matrix * quantumRegister.Vector);
304 | }
305 |
306 | /*
307 | * String representation of a quantum gate
308 | */
309 | public override string ToString()
310 | {
311 | return this.Matrix.ToString();
312 | }
313 |
314 | /*
315 | * Determines whether the specified quantum gate is equal to the current quantum gate
316 | */
317 | public override bool Equals(object obj)
318 | {
319 | QuantumGate quantumGate = obj as QuantumGate;
320 |
321 | if (quantumGate == null || this.Matrix.ColumnCount != quantumGate.Matrix.ColumnCount || this.Matrix.RowCount != quantumGate.Matrix.RowCount)
322 | {
323 | return false;
324 | }
325 |
326 | return this.Matrix.Equals(quantumGate.Matrix);
327 | }
328 |
329 | /*
330 | * Determines whether the specified quantum gate is equal to the current quantum gate, ignoring floating-point precision issues
331 | */
332 | public bool AlmostEquals(object obj)
333 | {
334 | QuantumGate quantumGate = obj as QuantumGate;
335 |
336 | if (quantumGate == null || this.Matrix.ColumnCount != quantumGate.Matrix.ColumnCount || this.Matrix.RowCount != quantumGate.Matrix.RowCount)
337 | {
338 | return false;
339 | }
340 |
341 | return Precision.AlmostEqual(this.Matrix, quantumGate.Matrix, 15);
342 | }
343 |
344 | /*
345 | * Serves as a hash function for a quantum gate
346 | */
347 | public override int GetHashCode()
348 | {
349 | return this.Matrix.GetHashCode();
350 | }
351 | }
352 | }
353 |
--------------------------------------------------------------------------------