Result.java
/*-
* #%L
* Strange
* %%
* Copyright (C) 2020, 2021 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;
import java.util.HashMap;
import java.util.Map;
/**
* <p>Result class.</p>
*
* @author johan
* @version $Id: $Id
*/
public class Result {
private int nqubits;
private int nsteps;
private Qubit[] qubits;
private Complex[] probability;
private Complex[][] intermediateProps;
private Map<Integer, Qubit[]> intermediateQubits;
private int measuredProbability = -1;
/**
* <p>Constructor for Result.</p>
*
* @param nqubits a int
* @param steps a int
*/
public Result(int nqubits, int steps) {
assert(steps >= 0);
this.nqubits = nqubits;
this.nsteps = steps;
intermediateProps = new Complex[steps > 0 ? steps : 1][];
intermediateQubits = new HashMap<>();
}
/**
* <p>Constructor for Result.</p>
*
* @param q an array of {@link org.redfx.strange.Qubit} objects
* @param p an array of {@link org.redfx.strange.Complex} objects
*/
public Result(Qubit[] q, Complex[] p) {
this.qubits = q;
this.probability = p;
}
/**
* <p>Getter for the field <code>qubits</code>.</p>
*
* @return an array of {@link org.redfx.strange.Qubit} objects
*/
public Qubit[] getQubits() {
if (this.qubits == null) {
this.qubits = calculateQubits();
}
return this.qubits;
}
/**
* <p>Getter for the field <code>intermediateQubits</code>.</p>
*
* @return a {@link java.util.Map} object
*/
public Map<Integer, Qubit[]> getIntermediateQubits() {
return this.intermediateQubits;
}
private Qubit[] calculateQubits() {
Qubit[] answer = new Qubit[nqubits];
if (nqubits == 0) {
return answer;
}
int lastidx = nsteps == 0 ? 0 : nsteps-1;
while (intermediateProps[lastidx] == null) lastidx--;
double[] d = calculateQubitStatesFromVector(intermediateProps[lastidx]);
for (int i = 0; i < answer.length; i++) {
answer[i] = new Qubit();
answer[i].setProbability(d[i]);
}
return answer;
}
private Qubit[] calculateQubitsFromVector(Complex[] probs) {
Qubit[] answer = new Qubit[nqubits];
if (nqubits == 0) {
return answer;
}
double[] d = calculateQubitStatesFromVector(probs);
for (int i = 0; i < answer.length; i++) {
answer[i] = new Qubit();
answer[i].setProbability(d[i]);
}
return answer;
}
/**
* <p>Getter for the field <code>probability</code>.</p>
*
* @return an array of {@link org.redfx.strange.Complex} objects
*/
public Complex[] getProbability() {
return this.probability;
}
/**
* <p>setIntermediateProbability.</p>
*
* @param step a int
* @param p an array of {@link org.redfx.strange.Complex} objects
*/
public void setIntermediateProbability(int step, Complex[] p) {
this.intermediateProps[step] = p;
this.intermediateQubits.put(step, calculateQubitsFromVector(p));
// if ((step == nsteps -1) || (nsteps == 0)) { // in case we have no steps, this is the final result
this.probability = p;
// }
}
/**
* <p>getIntermediateProbability.</p>
*
* @param step a int
* @return an array of {@link org.redfx.strange.Complex} objects
*/
public Complex[] getIntermediateProbability(int step) {
int ret = step;
while ((ret > 0) && (intermediateProps[ret] == null)) ret--;
return intermediateProps[ret];
}
static 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;
}
/**
* Based on the probabilities of the system, this method will measure all qubits.
* When this method is called, the <code>measuredValue</code> value of every qubit
* contains a possible measurement value. The values are consistent for the entire system.
* (e.g. when an entangled pair is measured, its values are equal)
* However, different invocations of this method may result in different values.
*/
public void measureSystem() {
if (this.qubits == null) {
this.qubits = getQubits();
}
double random = Math.random();
int ressize = 1 << nqubits;
double[] probamp = new double[ressize];
double probtot = 0;
// we don't need all probabilities, but we might use this later
for (int i = 0; i < ressize; i++) {
probamp[i] = this.probability[i].abssqr();
}
int sel = 0;
probtot = probamp[0];
while (probtot < random) {
sel++;
probtot = probtot + probamp[sel];
}
this.measuredProbability = sel;
double outcome = probamp[sel];
for (int i = 0; i < nqubits; i++) {
qubits[i].setMeasuredValue(sel %2 == 1);
sel = sel/2;
}
}
/**
* Returns a measurement based on the probability vector
*
* @return an integer representation of the measurement
*/
public int getMeasuredProbability() {
return measuredProbability;
}
/**
* Print info about this result to stdout
*/
public void printInfo() {
System.out.println("Info about Quantum Result");
System.out.println("==========================");
System.out.println("Number of qubits = "+nqubits+", number of steps = "+nsteps);
for (int i = 0; i < probability.length;i++) {
System.out.println("Probability on "+i+":"+ probability[i].abssqr());
}
System.out.println("==========================");
}
}