├── 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 | --------------------------------------------------------------------------------