// register A - initially loaded with a // register B - initially loaded with b // register C - initially 0, exactly one bit wider than A, stores overflow bit // register N - initially loaded with N // after computation in register B: (a+b) mod N // other registers dont change their states // register B must be exactly one bit wider than A to store carry bit // register B must be exactly one bit wider than N to store carry bit // registers A, N must be the same length // Insecure version: registers widths etc. are not checked public static void AddModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, ulong valueN) { RegisterRef carry = b[b.Width - 1]; RegisterRef overflow = c[c.Width - 1]; comp.Add(a, b, c); comp.InverseAdd(N, b, c); comp.SigmaX(carry); comp.CNot(overflow, carry); comp.SigmaX(carry); //resetting N comp.LoadNumber(N, valueN, overflow); comp.Add(N, b, c); // now we have [(a+b) mod N] in B register // next steps lead to recover the initial state of registers N and overflow bit //setting N back comp.LoadNumber(N, valueN, overflow); comp.InverseAdd(a, b, c); comp.CNot(overflow, carry); comp.Add(a, b, c); }
// controlled loading a number into register // using Toffoli gates // if controlBits are empty, the number is loaded unconditionally public static void LoadNumber(this QuantumComputer comp, Register target, ulong number, params RegisterRef[] controlBits) { Validate(target, number); int controlLength = controlBits.Length; int i = 0; ulong tmpN = number; while (tmpN > 0) { int rest = (int)(tmpN % 2); tmpN = tmpN / 2; if (rest == 1) { if (controlLength > 1) { comp.Toffoli(target[i], controlBits); } else if (controlLength > 0) { comp.CNot(target[i], controlBits[0]); } else { target.SigmaX(i); } } i++; } }
// Add(a, b, 0) -> (a, a+b, 0) // Registers a, b and c must not overlap // Registers a and b have the same width // Register c is used for storing carries and must be minimum one bit wider than register a (or b) // Initial value of c must be 0 public static void Add(this QuantumComputer comp, Register a, Register b, Register c) { if (comp.Group) { object[] parameters = new object[] { comp, a, b, c }; comp.AddParametricGate("Add", parameters); return; } else { comp.Group = true; } int width = a.Width; int i = 0; for (; i < width - 1; i++) { comp.Carry(c[i], a[i], b[i], c[i + 1]); } comp.Carry(c[i], a[i], b[i], b[i + 1]); comp.CNot(b[i], a[i]); comp.Sum(c[i], a[i], b[i]); i--; for (; i >= 0; i--) { comp.InverseCarry(c[i], a[i], b[i], c[i + 1]); comp.Sum(c[i], a[i], b[i]); } }
// register A - initially loaded with a // register B - initially loaded with b // register C - initially 0, exactly one bit wider than A, stores overflow bit // register N - initially loaded with N // after computation in register B: (a+b) mod N // other registers dont change their states // register B must be exactly one bit wider than A to store carry bit // register B must be exactly one bit wider than N to store carry bit // registers A, N must be the same length // Insecure version: registers widths etc. are not checked public static void AddModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, ulong valueN) { if (comp.Group) { object[] parameters = new object[] { comp, a, b, c, N, valueN }; comp.AddParametricGate("AddModulo", parameters); return; } else { comp.Group = true; } RegisterRef carry = b[b.Width - 1]; RegisterRef overflow = c[c.Width - 1]; comp.Add(a, b, c); comp.InverseAdd(N, b, c); comp.SigmaX(carry); comp.CNot(overflow, carry); comp.SigmaX(carry); //resetting N comp.LoadNumber(N, valueN, overflow); comp.Add(N, b, c); // now we have [(a+b) mod N] in B register // next steps lead to recover the initial state of registers N and overflow bit //setting N back comp.LoadNumber(N, valueN, overflow); comp.InverseAdd(a, b, c); comp.CNot(overflow, carry); comp.Add(a, b, c); }
public static void AddModuloQFTPhi(this QuantumComputer comp, ulong a, ulong N, RegisterRef ctrl, Register b, params RegisterRef[] controls) { comp.AddQFTPhi(a, b, controls); comp.InverseAddQFTPhi(N, b); comp.InverseQFT(b); comp.CNot(ctrl, b[b.Width - 1]); comp.QFT(b); comp.AddQFTPhi(N, b, ctrl); comp.InverseAddQFTPhi(a, b, controls); comp.InverseQFT(b); comp.SigmaX(b[b.Width - 1]); comp.CNot(ctrl, b[b.Width - 1]); comp.SigmaX(b[b.Width - 1]); comp.QFT(b); comp.AddQFTPhi(a, b, controls); }
// controlled loading a number into register // using Toffoli gates // if controlBits are empty, the number is loaded unconditionally public static void LoadNumber(this QuantumComputer comp, Register target, ulong number, params RegisterRef[] controlBits) { if (comp.Group) { object[] parameters = new object[] { comp, target, number, controlBits }; comp.AddParametricGate("LoadNumber", parameters); return; } else { comp.Group = true; } Validate(target, number); int controlLength = controlBits.Length; int i = 0; ulong tmpN = number; while (tmpN > 0) { int rest = (int)(tmpN % 2); tmpN = tmpN / 2; if (rest == 1) { if (controlLength > 1) { comp.Toffoli(target[i], controlBits); } else if (controlLength > 0) { comp.CNot(target[i], controlBits[0]); } else { target.SigmaX(i); } } i++; } }
/// <summary> /// <para> /// Adds two registers. The result is stored in the second. An extra register is needed for storing carry bits. /// </para> /// <para> /// Add(a, b, 0) -> (a, a+b, 0) /// </para> /// <para> /// In order to improve performance, this method do not check if arguments are valid. /// They must satisfy following conditions: /// <list type="bullet"> /// <item>Registers a, b and c must not overlap</item> /// <item>Registers a and c must have the same width</item> /// <item>Register b must be exactly one bit wider than register a (or c)</item> /// <item>Initial value of c must be 0</item> /// </list> /// </para> /// </summary> /// <param name="comp">The QuantumComputer instance.</param> /// <param name="a">The first register to sum. Its value remains unchanged.</param> /// <param name="b">The second register to sum. After performing this operation, it contains the sum result.</param> /// <param name="c">The extra register for storing carry bits.</param> public static void Add(this QuantumComputer comp, Register a, Register b, Register c) { int width = a.Width; int i = 0; for (; i < width - 1; i++) { comp.Carry(c[i], a[i], b[i], c[i + 1]); } comp.Carry(c[i], a[i], b[i], b[i + 1]); comp.CNot(b[i], a[i]); comp.Sum(c[i], a[i], b[i]); i--; for (; i >= 0; i--) { comp.InverseCarry(c[i], a[i], b[i], c[i + 1]); comp.Sum(c[i], a[i], b[i]); } }
// Insecure version: registers widths etc. are not checked public static void InverseAddModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, ulong valueN) { RegisterRef carry = b[b.Width - 1]; RegisterRef overflow = c[c.Width - 1]; comp.InverseAdd(a, b, c); comp.CNot(overflow, carry); comp.Add(a, b, c); //resetting N: comp.LoadNumber(N, valueN, overflow); comp.InverseAdd(N, b, c); //setting N back: comp.LoadNumber(N, valueN, overflow); comp.SigmaX(carry); comp.CNot(overflow, carry); comp.SigmaX(carry); comp.Add(N, b, c); comp.InverseAdd(a, b, c); }
public static void AddModuloQFTPhi(this QuantumComputer comp, ulong a, ulong N, RegisterRef ctrl, Register b, params RegisterRef[] controls) { if (comp.Group) { object[] parameters = new object[] { comp, a, N, ctrl, b, controls }; comp.AddParametricGate("AddModuloQFTPhi", parameters); return; } else { comp.Group = true; } comp.AddQFTPhi(a, b, controls); comp.InverseAddQFTPhi(N, b); comp.InverseQFT(b); comp.CNot(ctrl, b[b.Width - 1]); comp.QFT(b); comp.AddQFTPhi(N, b, ctrl); comp.InverseAddQFTPhi(a, b, controls); comp.InverseQFT(b); comp.SigmaX(b[b.Width - 1]); comp.CNot(ctrl, b[b.Width - 1]); comp.SigmaX(b[b.Width - 1]); comp.QFT(b); comp.AddQFTPhi(a, b, controls); }
// Insecure version: registers widths etc. are not checked public static void InverseAddModulo( this QuantumComputer comp, Register a, Register b, Register c, Register N, ulong valueN) { if (comp.Group) { object[] parameters = new object[] { comp, a, b, c, N, valueN }; comp.AddParametricGate("InverseAddModulo", parameters); return; } else { comp.Group = true; } RegisterRef carry = b[b.Width - 1]; RegisterRef overflow = c[c.Width - 1]; comp.InverseAdd(a, b, c); comp.CNot(overflow, carry); comp.Add(a, b, c); //resetting N: comp.LoadNumber(N, valueN, overflow); comp.InverseAdd(N, b, c); //setting N back: comp.LoadNumber(N, valueN, overflow); comp.SigmaX(carry); comp.CNot(overflow, carry); comp.SigmaX(carry); comp.Add(N, b, c); comp.InverseAdd(a, b, c); }