public Gate(final String id, double angle, final Tools.AngleType angle_type) { this.id = id; this.IO_ports = 1; if (angle_type == Tools.AngleType.DEGREES) angle = Math.toRadians(angle); Complex[][] data = new Complex[][] { {new Complex(1), new Complex(0)}, {new Complex(0), new Complex(Tools.round(Math.cos(angle)), Tools.round(Math.sin(angle)))} }; mat = new Array2DRowFieldMatrix<Complex>(data); if (!valid()) throw new RuntimeException( "Matrix is not a valid quantum gate in Gate phase shift constructor"); }
public boolean valid() { // Checks if this is a control matrix Complex[][] data = new Complex[][] { {new Complex(Tools.CONTROL_VALUE), new Complex(0)}, {new Complex(0), new Complex(1)} }; FieldMatrix<Complex> control = new Array2DRowFieldMatrix<Complex>(data); if (mat.equals(control)) return true; final boolean is_dimension_power_of_2 = (mat.getColumnDimension() & (mat.getColumnDimension() - 1)) == 0; if (!mat.isSquare() || !is_dimension_power_of_2) return false; // Computes dagger of mat FieldMatrix<Complex> dagger = mat.transpose(); dagger.walkInOptimizedOrder(new MatrixConjugator()); // Checks if dagger * mat = identity matrix FieldMatrix<Complex> result = mat.multiply(dagger); Complex is_identity = result.walkInOptimizedOrder(new UnitaryChecker()); // 1+0i if true, 0+0i if false return is_identity.equals(new Complex(1)); }
private static FieldMatrix<Complex> kronecker(FieldMatrix<Complex> lhs, FieldMatrix<Complex> rhs) { FieldMatrix<Complex> result = new Array2DRowFieldMatrix<Complex>(ComplexField.getInstance(), lhs.getRowDimension() * rhs.getRowDimension(), lhs.getColumnDimension() * rhs.getColumnDimension()); for (int i = 0; i < lhs.getRowDimension(); i++) for (int j = 0; j < lhs.getColumnDimension(); j++) for (int k = 0; k < rhs.getRowDimension(); k++) for (int l = 0; l < rhs.getColumnDimension(); l++) { int row = i * rhs.getRowDimension() + k, col = j * rhs.getColumnDimension() + l; // The control value alters Kronecker product's behavior to create controlled gates if (lhs.getEntry(i, j).getReal() == Tools.CONTROL_VALUE) if (row == col) result.setEntry(row, col, new Complex(Tools.CONTROL_VALUE)); else result.setEntry(row, col, new Complex(0)); else result.setEntry(row, col, lhs.getEntry(i, j).multiply(rhs.getEntry(k, l))); } return result; }
/** Build the P matrix. * <p>The P matrix general terms are shifted (j+1) (-i)<sup>j</sup> terms * with i being the row number starting from 1 and j being the column * number starting from 1: * <pre> * [ -2 3 -4 5 ... ] * [ -4 12 -32 80 ... ] * P = [ -6 27 -108 405 ... ] * [ -8 48 -256 1280 ... ] * [ ... ] * </pre></p> * @param rows number of rows of the matrix * @return P matrix */ private FieldMatrix<BigFraction> buildP(final int rows) { final BigFraction[][] pData = new BigFraction[rows][rows]; for (int i = 1; i <= pData.length; ++i) { // build the P matrix elements from Taylor series formulas final BigFraction[] pI = pData[i - 1]; final int factor = -i; int aj = factor; for (int j = 1; j <= pI.length; ++j) { pI[j - 1] = new BigFraction(aj * (j + 1)); aj *= factor; } } return new Array2DRowFieldMatrix<BigFraction>(pData, false); }
/** Build the P matrix. * <p>The P matrix general terms are shifted (j+1) (-i)<sup>j</sup> terms * with i being the row number starting from 1 and j being the column * number starting from 1: * <pre> * [ -2 3 -4 5 ... ] * [ -4 12 -32 80 ... ] * P = [ -6 27 -108 405 ... ] * [ -8 48 -256 1280 ... ] * [ ... ] * </pre></p> * @param rows number of rows of the matrix * @return P matrix */ private FieldMatrix<T> buildP(final int rows) { final T[][] pData = MathArrays.buildArray(field, rows, rows); for (int i = 1; i <= pData.length; ++i) { // build the P matrix elements from Taylor series formulas final T[] pI = pData[i - 1]; final int factor = -i; T aj = field.getZero().add(factor); for (int j = 1; j <= pI.length; ++j) { pI[j - 1] = aj.multiply(j + 1); aj = aj.multiply(factor); } } return new Array2DRowFieldMatrix<T>(pData, false); }
/** Simple constructor. * @param stepSize step size used in the scaled and Nordsieck arrays * @param reference reference state from which Taylor expansion are estimated * @param scaled first scaled derivative * @param nordsieck Nordsieck vector * @param isForward integration direction indicator * @param globalPreviousState start of the global step * @param globalCurrentState end of the global step * @param softPreviousState start of the restricted step * @param softCurrentState end of the restricted step * @param equationsMapper mapper for ODE equations primary and secondary components */ private AdamsFieldStepInterpolator(final T stepSize, final FieldODEStateAndDerivative<T> reference, final T[] scaled, final Array2DRowFieldMatrix<T> nordsieck, final boolean isForward, final FieldODEStateAndDerivative<T> globalPreviousState, final FieldODEStateAndDerivative<T> globalCurrentState, final FieldODEStateAndDerivative<T> softPreviousState, final FieldODEStateAndDerivative<T> softCurrentState, final FieldEquationsMapper<T> equationsMapper) { super(isForward, globalPreviousState, globalCurrentState, softPreviousState, softCurrentState, equationsMapper); this.scalingH = stepSize; this.reference = reference; this.scaled = scaled.clone(); this.nordsieck = new Array2DRowFieldMatrix<T>(nordsieck.getData(), false); }
/** Build the P matrix. * <p>The P matrix general terms are shifted j (-i)<sup>j-1</sup> terms: * <pre> * [ -2 3 -4 5 ... ] * [ -4 12 -32 80 ... ] * P = [ -6 27 -108 405 ... ] * [ -8 48 -256 1280 ... ] * [ ... ] * </pre></p> * @param nSteps number of steps of the multistep method * (excluding the one being computed) * @return P matrix */ private FieldMatrix<BigFraction> buildP(final int nSteps) { final BigFraction[][] pData = new BigFraction[nSteps][nSteps]; for (int i = 0; i < pData.length; ++i) { // build the P matrix elements from Taylor series formulas final BigFraction[] pI = pData[i]; final int factor = -(i + 1); int aj = factor; for (int j = 0; j < pI.length; ++j) { pI[j] = new BigFraction(aj * (j + 2)); aj *= factor; } } return new Array2DRowFieldMatrix<BigFraction>(pData, false); }
public Gate(final String id, double angle_x, double angle_y, double angle_z, final Tools.AngleType angle_type) { this.id = id; this.IO_ports = 1; if (angle_type == Tools.AngleType.DEGREES) { angle_x = Math.toRadians(angle_x); angle_y = Math.toRadians(angle_y); angle_z = Math.toRadians(angle_z); } Complex[][] data_x_rot = new Complex[][] { {new Complex(Tools.round(Math.cos(angle_x / 2))), new Complex(0.0, Tools.round(-Math.sin(angle_x / 2)))}, {new Complex(0.0, Tools.round(-Math.sin(angle_x / 2))), new Complex(Tools.round(Math.cos(angle_x / 2)))} }; FieldMatrix<Complex> x_rot = new Array2DRowFieldMatrix<Complex>(data_x_rot); Complex[][] data_y_rot = new Complex[][] { {new Complex(Tools.round(Math.cos(angle_y / 2))), new Complex(Tools.round(-Math.sin(angle_y / 2)))}, {new Complex(Tools.round(Math.sin(angle_y / 2))), new Complex(Tools.round(Math.cos(angle_y / 2)))} }; FieldMatrix<Complex> y_rot = new Array2DRowFieldMatrix<Complex>(data_y_rot); Complex[][] data_z_rot = new Complex[][] { {new Complex(Tools.round(Math.cos(angle_z / 2)), Tools.round(-Math.sin(angle_z / 2))), new Complex(0.0)}, {new Complex(0.0), new Complex(Tools.round(Math.cos(angle_z / 2)), Tools.round(Math.sin(angle_z / 2)))} }; FieldMatrix<Complex> z_rot = new Array2DRowFieldMatrix<Complex>(data_z_rot); mat = z_rot.multiply(y_rot).multiply(x_rot); if (!valid()) throw new RuntimeException( "Matrix is not a valid quantum gate in Gate rotation constructor"); }
public static Gate create_pauli_x() { Complex[][] data = new Complex[][] { {new Complex(0), new Complex(1)}, {new Complex(1), new Complex(0)} }; return new Gate("X", new Array2DRowFieldMatrix<Complex>(data)); }
public static Gate create_pauli_y() { Complex[][] data = new Complex[][] { {new Complex(0), new Complex(0, -1)}, {new Complex(0, 1), new Complex(0)} }; return new Gate("Y", new Array2DRowFieldMatrix<Complex>(data)); }
public static Gate create_pauli_z() { Complex[][] data = new Complex[][] { {new Complex(1), new Complex(0)}, {new Complex(0), new Complex(-1)} }; return new Gate("Z", new Array2DRowFieldMatrix<Complex>(data)); }
public static Gate create_hadamard() { Complex[][] data = new Complex[][] { {new Complex(1), new Complex(1)}, {new Complex(1), new Complex(-1)} }; Array2DRowFieldMatrix<Complex> matrix = new Array2DRowFieldMatrix<Complex>(data); Complex multiplier = new Complex(1 / Math.sqrt(2)); return new Gate("H", matrix.scalarMultiply(multiplier)); }
public static Gate create_control() { Complex[][] data = new Complex[][] { {new Complex(Tools.CONTROL_VALUE), new Complex(0)}, {new Complex(0), new Complex(1)} }; return new Gate(Tools.CONTROL_ID, new Array2DRowFieldMatrix<Complex>(data)); }
/** Simple constructor. * @param n number of steps of the multistep method * (excluding the one being computed) */ private AdamsNordsieckTransformer(final int n) { final int rows = n - 1; // compute exact coefficients FieldMatrix<BigFraction> bigP = buildP(rows); FieldDecompositionSolver<BigFraction> pSolver = new FieldLUDecomposition<BigFraction>(bigP).getSolver(); BigFraction[] u = new BigFraction[rows]; Arrays.fill(u, BigFraction.ONE); BigFraction[] bigC1 = pSolver.solve(new ArrayFieldVector<BigFraction>(u, false)).toArray(); // update coefficients are computed by combining transform from // Nordsieck to multistep, then shifting rows to represent step advance // then applying inverse transform BigFraction[][] shiftedP = bigP.getData(); for (int i = shiftedP.length - 1; i > 0; --i) { // shift rows shiftedP[i] = shiftedP[i - 1]; } shiftedP[0] = new BigFraction[rows]; Arrays.fill(shiftedP[0], BigFraction.ZERO); FieldMatrix<BigFraction> bigMSupdate = pSolver.solve(new Array2DRowFieldMatrix<BigFraction>(shiftedP, false)); // convert coefficients to double update = MatrixUtils.bigFractionMatrixToRealMatrix(bigMSupdate); c1 = new double[rows]; for (int i = 0; i < rows; ++i) { c1[i] = bigC1[i].doubleValue(); } }
/** Simple constructor. * @param field field to which the time and state vector elements belong * @param n number of steps of the multistep method * (excluding the one being computed) */ private AdamsNordsieckFieldTransformer(final Field<T> field, final int n) { this.field = field; final int rows = n - 1; // compute coefficients FieldMatrix<T> bigP = buildP(rows); FieldDecompositionSolver<T> pSolver = new FieldLUDecomposition<T>(bigP).getSolver(); T[] u = MathArrays.buildArray(field, rows); Arrays.fill(u, field.getOne()); c1 = pSolver.solve(new ArrayFieldVector<T>(u, false)).toArray(); // update coefficients are computed by combining transform from // Nordsieck to multistep, then shifting rows to represent step advance // then applying inverse transform T[][] shiftedP = bigP.getData(); for (int i = shiftedP.length - 1; i > 0; --i) { // shift rows shiftedP[i] = shiftedP[i - 1]; } shiftedP[0] = MathArrays.buildArray(field, rows); Arrays.fill(shiftedP[0], field.getZero()); update = new Array2DRowFieldMatrix<T>(pSolver.solve(new Array2DRowFieldMatrix<T>(shiftedP, false)).getData()); }
/** Simple constructor. * @param stepSize step size used in the scaled and Nordsieck arrays * @param reference reference state from which Taylor expansion are estimated * @param scaled first scaled derivative * @param nordsieck Nordsieck vector * @param isForward integration direction indicator * @param globalPreviousState start of the global step * @param globalCurrentState end of the global step * @param equationsMapper mapper for ODE equations primary and secondary components */ AdamsFieldStepInterpolator(final T stepSize, final FieldODEStateAndDerivative<T> reference, final T[] scaled, final Array2DRowFieldMatrix<T> nordsieck, final boolean isForward, final FieldODEStateAndDerivative<T> globalPreviousState, final FieldODEStateAndDerivative<T> globalCurrentState, final FieldEquationsMapper<T> equationsMapper) { this(stepSize, reference, scaled, nordsieck, isForward, globalPreviousState, globalCurrentState, globalPreviousState, globalCurrentState, equationsMapper); }
/** Estimate state by applying Taylor formula. * @param reference reference state * @param time time at which state must be estimated * @param stepSize step size used in the scaled and Nordsieck arrays * @param scaled first scaled derivative * @param nordsieck Nordsieck vector * @return estimated state * @param <S> the type of the field elements */ public static <S extends RealFieldElement<S>> FieldODEStateAndDerivative<S> taylor(final FieldODEStateAndDerivative<S> reference, final S time, final S stepSize, final S[] scaled, final Array2DRowFieldMatrix<S> nordsieck) { final S x = time.subtract(reference.getTime()); final S normalizedAbscissa = x.divide(stepSize); S[] stateVariation = MathArrays.buildArray(time.getField(), scaled.length); Arrays.fill(stateVariation, time.getField().getZero()); S[] estimatedDerivatives = MathArrays.buildArray(time.getField(), scaled.length); Arrays.fill(estimatedDerivatives, time.getField().getZero()); // apply Taylor formula from high order to low order, // for the sake of numerical accuracy final S[][] nData = nordsieck.getDataRef(); for (int i = nData.length - 1; i >= 0; --i) { final int order = i + 2; final S[] nDataI = nData[i]; final S power = normalizedAbscissa.pow(order); for (int j = 0; j < nDataI.length; ++j) { final S d = nDataI[j].multiply(power); stateVariation[j] = stateVariation[j].add(d); estimatedDerivatives[j] = estimatedDerivatives[j].add(d.multiply(order)); } } S[] estimatedState = reference.getState(); for (int j = 0; j < stateVariation.length; ++j) { stateVariation[j] = stateVariation[j].add(scaled[j].multiply(normalizedAbscissa)); estimatedState[j] = estimatedState[j].add(stateVariation[j]); estimatedDerivatives[j] = estimatedDerivatives[j].add(scaled[j].multiply(normalizedAbscissa)).divide(x); } return new FieldODEStateAndDerivative<S>(time, estimatedState, estimatedDerivatives); }
/** {@inheritDoc} */ @Override protected Array2DRowFieldMatrix<T> initializeHighOrderDerivatives(final T h, final T[] t, final T[][] y, final T[][] yDot) { return transformer.initializeHighOrderDerivatives(h, t, y, yDot); }
/** Simple constructor. * @param nSteps number of steps of the multistep method * (excluding the one being computed) */ private AdamsNordsieckTransformer(final int nSteps) { // compute exact coefficients FieldMatrix<BigFraction> bigP = buildP(nSteps); FieldDecompositionSolver<BigFraction> pSolver = new FieldLUDecomposition<BigFraction>(bigP).getSolver(); BigFraction[] u = new BigFraction[nSteps]; Arrays.fill(u, BigFraction.ONE); BigFraction[] bigC1 = pSolver .solve(new ArrayFieldVector<BigFraction>(u, false)).toArray(); // update coefficients are computed by combining transform from // Nordsieck to multistep, then shifting rows to represent step advance // then applying inverse transform BigFraction[][] shiftedP = bigP.getData(); for (int i = shiftedP.length - 1; i > 0; --i) { // shift rows shiftedP[i] = shiftedP[i - 1]; } shiftedP[0] = new BigFraction[nSteps]; Arrays.fill(shiftedP[0], BigFraction.ZERO); FieldMatrix<BigFraction> bigMSupdate = pSolver.solve(new Array2DRowFieldMatrix<BigFraction>(shiftedP, false)); // convert coefficients to double update = MatrixUtils.bigFractionMatrixToRealMatrix(bigMSupdate); c1 = new double[nSteps]; for (int i = 0; i < nSteps; ++i) { c1[i] = bigC1[i].doubleValue(); } }
/** Initialize the high order scaled derivatives at step start. * @param h step size to use for scaling * @param t first steps times * @param y first steps states * @param yDot first steps derivatives * @return Nordieck vector at start of first step (h<sup>2</sup>/2 y''<sub>n</sub>, * h<sup>3</sup>/6 y'''<sub>n</sub> ... h<sup>k</sup>/k! y<sup>(k)</sup><sub>n</sub>) */ public Array2DRowFieldMatrix<T> initializeHighOrderDerivatives(final T h, final T[] t, final T[][] y, final T[][] yDot) { // using Taylor series with di = ti - t0, we get: // y(ti) - y(t0) - di y'(t0) = di^2 / h^2 s2 + ... + di^k / h^k sk + O(h^k) // y'(ti) - y'(t0) = 2 di / h^2 s2 + ... + k di^(k-1) / h^k sk + O(h^(k-1)) // we write these relations for i = 1 to i= 1+n/2 as a set of n + 2 linear // equations depending on the Nordsieck vector [s2 ... sk rk], so s2 to sk correspond // to the appropriately truncated Taylor expansion, and rk is the Taylor remainder. // The goal is to have s2 to sk as accurate as possible considering the fact the sum is // truncated and we don't want the error terms to be included in s2 ... sk, so we need // to solve also for the remainder final T[][] a = MathArrays.buildArray(field, c1.length + 1, c1.length + 1); final T[][] b = MathArrays.buildArray(field, c1.length + 1, y[0].length); final T[] y0 = y[0]; final T[] yDot0 = yDot[0]; for (int i = 1; i < y.length; ++i) { final T di = t[i].subtract(t[0]); final T ratio = di.divide(h); T dikM1Ohk = h.reciprocal(); // linear coefficients of equations // y(ti) - y(t0) - di y'(t0) and y'(ti) - y'(t0) final T[] aI = a[2 * i - 2]; final T[] aDotI = (2 * i - 1) < a.length ? a[2 * i - 1] : null; for (int j = 0; j < aI.length; ++j) { dikM1Ohk = dikM1Ohk.multiply(ratio); aI[j] = di.multiply(dikM1Ohk); if (aDotI != null) { aDotI[j] = dikM1Ohk.multiply(j + 2); } } // expected value of the previous equations final T[] yI = y[i]; final T[] yDotI = yDot[i]; final T[] bI = b[2 * i - 2]; final T[] bDotI = (2 * i - 1) < b.length ? b[2 * i - 1] : null; for (int j = 0; j < yI.length; ++j) { bI[j] = yI[j].subtract(y0[j]).subtract(di.multiply(yDot0[j])); if (bDotI != null) { bDotI[j] = yDotI[j].subtract(yDot0[j]); } } } // solve the linear system to get the best estimate of the Nordsieck vector [s2 ... sk], // with the additional terms s(k+1) and c grabbing the parts after the truncated Taylor expansion final FieldLUDecomposition<T> decomposition = new FieldLUDecomposition<T>(new Array2DRowFieldMatrix<T>(a, false)); final FieldMatrix<T> x = decomposition.getSolver().solve(new Array2DRowFieldMatrix<T>(b, false)); // extract just the Nordsieck vector [s2 ... sk] final Array2DRowFieldMatrix<T> truncatedX = new Array2DRowFieldMatrix<T>(field, x.getRowDimension() - 1, x.getColumnDimension()); for (int i = 0; i < truncatedX.getRowDimension(); ++i) { for (int j = 0; j < truncatedX.getColumnDimension(); ++j) { truncatedX.setEntry(i, j, x.getEntry(i, j)); } } return truncatedX; }