SimpleQuantumExecutionEnvironment.java
/*-
* #%L
* Strange
* %%
* Copyright (C) 2020 Johan Vos
* %%
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the Johan Vos nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.redfx.strange.local;
import org.redfx.strange.*;
import org.redfx.strange.gate.Identity;
import org.redfx.strange.gate.PermutationGate;
import org.redfx.strange.gate.ProbabilitiesGate;
import org.redfx.strange.gate.Swap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.logging.Logger;
/**
* <p>SimpleQuantumExecutionEnvironment class.</p>
*
* @author johan
* @version $Id: $Id
*/
public class SimpleQuantumExecutionEnvironment implements QuantumExecutionEnvironment {
static Logger LOG = Logger.getLogger(SimpleQuantumExecutionEnvironment.class.getName());
/**
* <p>Constructor for SimpleQuantumExecutionEnvironment.</p>
*/
public SimpleQuantumExecutionEnvironment() {
}
/** {@inheritDoc} */
@Override
public Result runProgram(Program p) {
LOG.info("runProgram ");
int nQubits = p.getNumberQubits();
Qubit[] qubit = new Qubit[nQubits];
for (int i = 0; i < nQubits; i++) {
qubit[i] = new Qubit();
}
int dim = 1 << nQubits;
double[] initalpha = p.getInitialAlphas();
Complex[] probs = new Complex[dim];
for (int i = 0; i < dim; i++) {
probs[i] = Complex.ONE;
for (int j = 0; j < nQubits; j++) {
int pw = nQubits - j -1 ;
int pt = 1 << pw;
int div = i/pt;
int md = div % 2;
if (md == 0) {
probs[i] = probs[i].mul(initalpha[j]);
} else {
probs[i] = probs[i].mul(Math.sqrt(1-initalpha[j]*initalpha[j]));
}
}
}
List<Step> steps = p.getSteps();
List<Step> simpleSteps = p.getDecomposedSteps();
if (simpleSteps == null) {
simpleSteps = new ArrayList<>();
for (Step step : steps) {
simpleSteps.addAll(Computations.decomposeStep(step, nQubits));
}
p.setDecomposedSteps(simpleSteps);
}
Result result = new Result(nQubits, steps.size());
int cnt = 0;
result.setIntermediateProbability(0, probs);
LOG.fine("START RUN, number of steps = " + simpleSteps.size());
for (Step step : simpleSteps) {
if (!step.getGates().isEmpty()) {
LOG.finer("RUN STEP " + step + ", cnt = " + cnt);
cnt++;
LOG.finest("before this step, probs = ");
// printProbs(probs);
probs = applyStep(step, probs, qubit);
LOG.info("after this step, probs = "+probs);
// printProbs(probs);
int idx = step.getComplexStep();
// System.err.println("complex? "+idx);
if (idx > -1) {
result.setIntermediateProbability(idx, probs);
}
}
}
LOG.info("DONE RUN, probability vector = " + probs);
printProbs(probs);
double[] qp = calculateQubitStatesFromVector(probs);
for (int i = 0; i < nQubits; i++) {
qubit[i].setProbability(qp[i]);
}
result.measureSystem();
p.setResult(result);
return result;
}
/** {@inheritDoc} */
@Override
public void runProgram(Program p, Consumer<Result> result) {
Thread t = new Thread(() -> result.accept(runProgram(p)));
t.start();
}
private void printProbs(Complex[] p) {
Complex.printArray(p);
}
private List<Step> decomposeSteps(List<Step> steps) {
return steps;
}
private Complex[] applyStep (Step step, Complex[] vector, Qubit[] qubits) {
LOG.finer("start applystep, vectorsize = "+vector.length+", ql = "+qubits.length);
long s0 = System.currentTimeMillis();
List<Gate> gates = step.getGates();
if (!gates.isEmpty() && gates.get(0) instanceof ProbabilitiesGate ) {
ProbabilitiesGate probGate = (ProbabilitiesGate)gates.get(0);
probGate.setProbabilites(vector);
return vector;
}
if (gates.size() == 1 && gates.get(0) instanceof PermutationGate) {
PermutationGate pg = (PermutationGate)gates.get(0);
return Computations.permutateVector (vector, pg.getIndex1(), pg.getIndex2());
}
Complex[] result = new Complex[vector.length];
boolean vdd = true;
result = Computations.calculateNewState(gates, vector, qubits.length);
long s1 = System.currentTimeMillis();
LOG.finer("done applystep took "+ (s1-s0));
return result;
}
private Complex[][] calculateStepMatrix(List<Gate> gates, int nQubits) {
return Computations.calculateStepMatrix(gates, nQubits, this);
}
// replaced by the similar function on Complex
/**
* <p>tensor.</p>
*
* @param a an array of {@link org.redfx.strange.Complex} objects
* @param b an array of {@link org.redfx.strange.Complex} objects
* @return an array of {@link org.redfx.strange.Complex} objects
*/
@Deprecated
public Complex[][] tensor(Complex[][] a, Complex[][] b) {
int d1 = a.length;
int d2 = b.length;
Complex[][] result = new Complex[d1 * d2][d1 * d2];
for (int rowa = 0; rowa < d1; rowa++) {
for (int cola = 0; cola < d1; cola++) {
for (int rowb = 0; rowb < d2; rowb++) {
for (int colb = 0; colb < d2; colb++) {
result[d2 * rowa + rowb][d2 * cola + colb] = a[rowa][cola].mul( b[rowb][colb]);
}
}
}
}
return result;
}
private double[] calculateQubitStatesFromVector(Complex[] vectorresult) {
int nq = (int) Math.round(Math.log(vectorresult.length) / Math.log(2));
double[] answer = new double[nq];
int ressize = 1 << nq;
for (int i = 0; i < nq; i++) {
int pw = i;//nq - i - 1;
int div = 1 << pw;
for (int j = 0; j < ressize; j++) {
int p1 = j / div;
if (p1 % 2 == 1) {
answer[i] = answer[i] + vectorresult[j].abssqr();
}
}
}
return answer;
}
/**
* <p>createPermutationMatrix.</p>
*
* @param first a int
* @param second a int
* @param n a int
* @return an array of {@link org.redfx.strange.Complex} objects
*/
public Complex[][] createPermutationMatrix(int first, int second, int n) {
Complex[][] swapMatrix = new Swap().getMatrix();
Complex[][] iMatrix = new Identity().getMatrix();
Complex[][] answer = iMatrix;
int i = 1;
if (first == 0) {
answer = swapMatrix;
i++;
}
while (i < n) {
if (i == first) {
i++;
answer = tensor(answer, swapMatrix);
} else {
answer = tensor(answer, iMatrix);
}
i++;
}
return answer;
}
}