diff --git a/QuantumPseudoTelepathy/Math/ComplexMatrix.cs b/QuantumPseudoTelepathy/Math/ComplexMatrix.cs index 867e440..fe375cf 100644 --- a/QuantumPseudoTelepathy/Math/ComplexMatrix.cs +++ b/QuantumPseudoTelepathy/Math/ComplexMatrix.cs @@ -11,29 +11,59 @@ public struct ComplexMatrix { private ComplexMatrix(IEnumerable> columns) { if (columns == null) throw new ArgumentNullException("columns"); this._columns = columns.Select(e => e.ToArray()).ToArray(); - //if (_columns.Any(col => col.Count != _columns.Count)) throw new ArgumentException("Not square"); + + var span = _columns.Length; + if (_columns.Any(e => e.Length != span)) throw new ArgumentOutOfRangeException("columns", "Not square"); + } + + public int Span { get { return _columns == null ? 0 : _columns.Length; } } + public IReadOnlyList> Columns { get { return _columns ?? ReadOnlyList.Empty>(); } } + public IReadOnlyList> Rows { + get { + var r = Columns; + return new AnonymousReadOnlyList>( + r.Count, + row => new AnonymousReadOnlyList( + r.Count, + col => r[col][row])); + } } public static ComplexMatrix FromColumns(IEnumerable> columns) { return new ComplexMatrix(columns); } + public static ComplexMatrix FromSquareData(params Complex[] cells) { + if (cells == null) throw new ArgumentNullException("cells"); + + var size = (int)Math.Round(Math.Sqrt(cells.Length)); + if (size * size != cells.Length) throw new ArgumentOutOfRangeException("cells", "cells.Length is not square"); + + var cols = cells.Deinterleave(size); + return FromColumns(cols); + } + public bool IsIdentity() { return Columns.Select((e, i) => e.Select((f, j) => (f - (j == i ? 1 : 0)).Magnitude < 0.0001).All(f => f)).All(e => e); } public bool IsUnitary() { return (this*this.Dagger()).IsIdentity(); } - public static ComplexMatrix FromCellData(params Complex[] cells) { - var size = (int)Math.Sqrt(cells.Length); - var cols = cells.Deinterleave(size); - return FromColumns(cols); + /// Determines if this * c == other, for some c where |c| == 1 + public bool IsPhased(ComplexMatrix other) { + var self = this; + return (from c in self.Span.Range() + from r in self.Span.Range() + let v = self.Columns[c][r] + where v != 0 + let ov = other.Columns[c][r] + select self * (ov / v) == other + ).FirstOrDefault(); } - public static ComplexMatrix FromMatrixData(params ComplexMatrix[] cells) { - var inSize = cells.First().Span; - var outSize = (int)Math.Sqrt(cells.Length); - var size = inSize * outSize; - return FromColumns(size.Range().Select(c => size.Range().Select(r => cells.Deinterleave(outSize)[c / inSize][r / inSize].Columns[c % inSize][r % inSize]).ToArray()).ToArray()); + /// Determines adjusting the row phases of other can make it equal to this. + public bool IsMultiRowPhased(ComplexMatrix other) { + return Rows.Zip(other.Rows, (c1, c2) => new ComplexVector(c1).IsPhased(new ComplexVector(c2))).All(e => e); } + public ComplexMatrix TensorSquare() { return this.TensorProduct(this); } @@ -49,56 +79,12 @@ public struct ComplexMatrix { public ComplexMatrix Transpose() { return FromColumns(Rows); } - public ComplexMatrix ExpandToApplyToMoreWires(int wireCount, int[] correspondingWiresForEachState) { - if ((1 << correspondingWiresForEachState.Length) != Span) throw new ArgumentOutOfRangeException(); - if ((1 << wireCount) < Span) throw new ArgumentOutOfRangeException(); - - var otherWires = wireCount.Range().Except(correspondingWiresForEachState).ToArray(); - var x = this; - var result = from col in new[] {0, 1}.ChooseWithReplacement(wireCount) - select from row in new[] {0, 1}.ChooseWithReplacement(wireCount) - let r = correspondingWiresForEachState.Select((e, i) => row[e] << i).Sum() - let c = correspondingWiresForEachState.Select((e, i) => col[e] << i).Sum() - let xr = otherWires.Select((e, i) => row[e] << i).Sum() - let xc = otherWires.Select((e, i) => col[e] << i).Sum() - select xr == xc ? x.Columns[c][r] : 0; - return FromColumns(result); - } + ///Returns the result of conjugating the elements of and tranposing this matrix. public ComplexMatrix Dagger() { return FromColumns(this.Rows.Select(e => e.Select(x => new Complex(x.Real, -x.Imaginary)))); } - public int Span { get { return _columns == null ? 0 : _columns.Length; } } - public IReadOnlyList> Columns { get { return _columns ?? ReadOnlyList.Empty>(); } } - public IReadOnlyList> Rows { - get { - var r = Columns; - return new AnonymousReadOnlyList>( - r.Count, - row => new AnonymousReadOnlyList( - r.Count, - col => r[col][row])); - } - } - public bool IsMultiRowPhased(ComplexMatrix other) { - return Rows.Zip(other.Rows, (c1, c2) => new ComplexVector(c1).IsPhased(new ComplexVector(c2))).All(e => e); - } - public bool IsPhased(ComplexMatrix other) { - var self = this; - return (from c in self.Span.Range() - from r in self.Span.Range() - let v = self.Columns[c][r] - where v != 0 - let ov = other.Columns[c][r] - select self*(ov/v) == other - ).FirstOrDefault(); - } - public bool IsSuperSimple() { - return Columns.Select((e, i) => (e[i].Magnitude - 1).Abs() < 0.00001).All(e => e); - } - public bool IsSimple() { - return Columns.All(e => e.Count(c => c != 0) == 1); - } + public static ComplexVector operator *(ComplexMatrix matrix, ComplexVector vector) { return new ComplexVector( matrix.Rows @@ -139,9 +125,16 @@ public struct ComplexMatrix { return obj is ComplexMatrix && (ComplexMatrix)obj == this; } public override int GetHashCode() { - return Columns.SelectMany(e => e).Aggregate(Span.GetHashCode(), (a, e) => a*3 + Math.Round(e.Real*1000).GetHashCode()*5 + Math.Round(e.Imaginary*1000).GetHashCode()); + // This is a hack that works in the cases that I needed it to work in. + // It groups most approximately equal matrices, but not ones across the third digit after decimal boundaries. + return Columns.SelectMany(e => e).Aggregate( + Span.GetHashCode(), + (a, e) => a*3 + Math.Round(e.Real*1000).GetHashCode()*5 + Math.Round(e.Imaginary*1000).GetHashCode()); } public override string ToString() { - return Rows.Select(r => r.Select(c => "| " + c.ToPrettyString().PadRight(6)).StringJoin("") + " |").StringJoin(Environment.NewLine); + return Rows.Select(r => r.Select(c => "| " + c.ToPrettyString().PadRight(6)) + .StringJoin("") + + " |") + .StringJoin(Environment.NewLine); } -} \ No newline at end of file +} diff --git a/QuantumPseudoTelepathy/Quantum/Gates.cs b/QuantumPseudoTelepathy/Quantum/Gates.cs index 5866471..ed6b7f8 100644 --- a/QuantumPseudoTelepathy/Quantum/Gates.cs +++ b/QuantumPseudoTelepathy/Quantum/Gates.cs @@ -3,77 +3,77 @@ public static class Gates { private static readonly Complex i = Complex.ImaginaryOne; - public static readonly ComplexMatrix NoGate = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix NoGate = ComplexMatrix.FromSquareData( 1, 0, 0, 1); // Hadamard gate - public static readonly ComplexMatrix H = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix H = ComplexMatrix.FromSquareData( 1, 1, 1, -1)/Math.Sqrt(2); // Pauli X gate - public static readonly ComplexMatrix X = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix X = ComplexMatrix.FromSquareData( 0, 1, 1, 0); // Pauli Y gate - public static readonly ComplexMatrix Y = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Y = ComplexMatrix.FromSquareData( 0, -i, i, 0); // Pauli Z gate - public static readonly ComplexMatrix Z = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Z = ComplexMatrix.FromSquareData( 1, 0, 0, -1); // R2 gate = pi/2 phase gate - public static readonly ComplexMatrix Phase = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Phase = ComplexMatrix.FromSquareData( 1, 0, 0, i); // 'Square root of not' gate - public static readonly ComplexMatrix SqrtNot = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix SqrtNot = ComplexMatrix.FromSquareData( 1, -1, 1, 1) / Math.Sqrt(2); // Half-mirror gate - public static readonly ComplexMatrix BeamSplit = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix BeamSplit = ComplexMatrix.FromSquareData( 1, i, i, 1) / Math.Sqrt(2); - public static readonly ComplexMatrix ControlledNot2When1 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix ControlledNot2When1 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); - public static readonly ComplexMatrix ControlledNot1When2 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix ControlledNot1When2 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0); - public static readonly ComplexMatrix Swap = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Swap = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1); - public static readonly ComplexMatrix Increment = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Increment = ComplexMatrix.FromSquareData( 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0); public static readonly ComplexMatrix Decrement = Increment.Dagger(); - public static readonly ComplexMatrix Phase00 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Phase00 = ComplexMatrix.FromSquareData( i, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - public static readonly ComplexMatrix Phase01 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Phase01 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, i, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - public static readonly ComplexMatrix Phase10 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Phase10 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, i, 0, 0, 0, 0, 1); - public static readonly ComplexMatrix Phase11 = ComplexMatrix.FromCellData( + public static readonly ComplexMatrix Phase11 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, diff --git a/QuantumPseudoTelepathy/Quantum/PseudoTelepathyCircuits.cs b/QuantumPseudoTelepathy/Quantum/PseudoTelepathyCircuits.cs index 915f507..e4f48dd 100644 --- a/QuantumPseudoTelepathy/Quantum/PseudoTelepathyCircuits.cs +++ b/QuantumPseudoTelepathy/Quantum/PseudoTelepathyCircuits.cs @@ -18,7 +18,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.Swap) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 1, 0, 0, i, 0, 1,-i, 0, 0,-i, 1, 0, @@ -37,7 +37,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.ControlledNot2When1) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 1, i, i, 1, 1,-i, i,-1, 1, i,-i,-1, @@ -55,7 +55,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.H.OnWire1Of2()) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 1, 1, 1,-1, 1, 1,-1, 1, 1,-1, 1, 1, @@ -73,7 +73,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.Swap) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 1,-1, i, i, 1, 1,-i, i, 1, 1, i,-i, @@ -91,7 +91,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.BeamSplit.OnWire1Of2()) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 1, i,-1, i, 1,-i, 1, i, 1, i, 1,-i, @@ -108,7 +108,7 @@ public static class PseudoTelepathyCircuits { .Then(Gates.SqrtNot.OnWire2Of2()) : //matrix (row phases are arbitrary): - ComplexMatrix.FromCellData( + ComplexMatrix.FromSquareData( 0, 1,-1, 0, 0, 1, 1, 0, 1, 0, 0,-1, diff --git a/QuantumPseudoTelepathyTest/ComplexMatrixTest.cs b/QuantumPseudoTelepathyTest/ComplexMatrixTest.cs index 0498c38..2bf8bd3 100644 --- a/QuantumPseudoTelepathyTest/ComplexMatrixTest.cs +++ b/QuantumPseudoTelepathyTest/ComplexMatrixTest.cs @@ -7,10 +7,10 @@ public class ComplexMatrixTest { [TestMethod] public void TestIsMultiPhase() { var i = Complex.ImaginaryOne; - var r1 = ComplexMatrix.FromCellData(1, 0, 0, 1); - var r2 = ComplexMatrix.FromCellData(i, 0, 0, 1); - var r3 = ComplexMatrix.FromCellData(0, 1, 1, 0); - var r4 = ComplexMatrix.FromCellData(1, 1, 1, -1)/Math.Sqrt(2); + var r1 = ComplexMatrix.FromSquareData(1, 0, 0, 1); + var r2 = ComplexMatrix.FromSquareData(i, 0, 0, 1); + var r3 = ComplexMatrix.FromSquareData(0, 1, 1, 0); + var r4 = ComplexMatrix.FromSquareData(1, 1, 1, -1)/Math.Sqrt(2); Assert.IsTrue(r1.IsMultiRowPhased(r1)); Assert.IsTrue(r1.IsMultiRowPhased(r2)); @@ -25,17 +25,17 @@ public class ComplexMatrixTest { } [TestMethod] public void TestMultiplication() { - var M1 = ComplexMatrix.FromCellData( + var M1 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0); - var M2 = ComplexMatrix.FromCellData( + var M2 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1); - var M3 = ComplexMatrix.FromCellData( + var M3 = ComplexMatrix.FromSquareData( 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, @@ -44,7 +44,7 @@ public class ComplexMatrixTest { } [TestMethod] public void TestVectorMultiplication() { - var M1 = ComplexMatrix.FromCellData( + var M1 = ComplexMatrix.FromSquareData( 10, 11, 12, 13, 14, 15, 16, 17, 18); @@ -54,7 +54,7 @@ public class ComplexMatrixTest { } [TestMethod] public void TestVectorMultiplication2() { - var M1 = ComplexMatrix.FromCellData( + var M1 = ComplexMatrix.FromSquareData( 10, 11, 12, 13, 14, 15, 16, 17, 18); @@ -64,15 +64,15 @@ public class ComplexMatrixTest { } [TestMethod] public void TestMultiplication2() { - var M1 = ComplexMatrix.FromCellData( + var M1 = ComplexMatrix.FromSquareData( -1, 2, 3, 4, 5, 6, 7, 8, 9); - var M2 = ComplexMatrix.FromCellData( + var M2 = ComplexMatrix.FromSquareData( 10, 11, 12, 13, 14, 15, 16, 17, 18); - var M3 = ComplexMatrix.FromCellData( + var M3 = ComplexMatrix.FromSquareData( 64, 68, 72, 201, 216, 231, 318, 342, 366);