Step.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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
*
* A single Step in a quantum {@link Program}. In a step, a number
* of {@link Gate}s can be added, involving a number of {@link Qubit}s. However, in a single
* step a qubit can be involved in at most one Gate. It is illegal
* to declare 2 gates in a single step that operate on the same qubit.
*
* @author johan
* @version $Id: $Id
*/
public class Step {
/**
* The type of the step. Typically, a step contains instructions that alter
* the quantum circuit. Those are steps with type <code>NORMAL</code>.
* <br>
* Some steps do not alter the quantum circuit at all and can be ignored in
* computations. Those are steps with type <code>PSEUDO</code> and they
* are typically used for visualization.
*/
public enum Type {
NORMAL,
PSEUDO,
PROBABILITY
}
private final Type type;
private final ArrayList<Gate> gates = new ArrayList<>();
private int index;
private final String name;
private Program program;
private int complexStep = -1; // if a complex step needs to broken into
// simple steps, only one simple step can have this value to be the index of the complex step
private boolean informal = false;
/**
* Create a Step instance and populate it with zero or more {@link Gate}s.
* Note that it is possible to add gates later by invoking the
* {@link addGate} or {@link addGates} method.
*
* @param moreGates zero or more {@link org.redfx.strange.Gate} objects
*/
public Step(Gate... moreGates ) {
this("unknown", moreGates);
}
/**
* Create a Step with a specific name.
*
* @param name the name of this step
* @param moreGates zero or more {@link org.redfx.strange.Gate} objects
*/
public Step(String name, Gate... moreGates ) {
this.name = name;
addGates(moreGates);
this.type = Type.NORMAL;
}
/**
* Create a step with a specific (pseudo) type
*
* @param type a {@link org.redfx.strange.Step.Type} object
*/
public Step(Type type) {
this.type = type;
this.name = "pseudo";
}
/**
* return the type of this step.
*
* @return a {@link org.redfx.strange.Step.Type} object
*/
public Type getType() {
return this.type;
}
/**
* Return the name of this step. This is for descriptive information only, it has no impact on the
* computations
*
* @return the name of the step, if supplied by the user.
*/
public String getName() {
return this.name;
}
/**
* Add gate to the list of gates for this step
*
* @param gate gate to add
* @throws java.lang.IllegalArgumentException in case the supplied Gate operates on a qubit that is already
* been operated on in this step
*/
public void addGate(Gate gate) throws IllegalArgumentException {
verifyUnique(Objects.requireNonNull(gate));
gates.add(gate);
}
/**
* Adds the multiple Gates to the list of gates for this step
*
* @param moreGates more gates
* @throws java.lang.IllegalArgumentException in case the supplied Gate operates on a qubit that is already
* been operated on in this step
*/
public void addGates(Gate... moreGates) throws IllegalArgumentException {
for( Gate g: moreGates ){
addGate(g);
}
}
/**
* Return all gates for this step in an unmodifiable collection
*
* @return a List with {@link Gate}s that are added to this step, either
* via the constructor or the {@link addGate} or {@link addGates} methods.
*/
public List<Gate> getGates() {
return Collections.unmodifiableList(gates);
}
/**
* Remove a Gate from this step
*
* @param g the Gate that should be removed
*/
public void removeGate(Gate g) {
gates.remove(g);
}
/**
* Indicate that this step is part of a complex step.
*
* @param idx the index of the complex step that this step is part of in
* the original Program
*/
public void setComplexStep(int idx) {
this.complexStep = idx;
}
/**
* <p>Getter for the field <code>complexStep</code>.</p>
*
* @return a int
*/
public int getComplexStep() {
return this.complexStep;
}
/**
* <p>setInformalStep.</p>
*
* @param b a boolean
*/
public void setInformalStep(boolean b) {
this.informal = b;
}
/**
* <p>isInformal.</p>
*
* @return a boolean
*/
public boolean isInformal() {
return informal;
}
/**
* <p>Setter for the field <code>index</code>.</p>
*
* @param s a int
*/
public void setIndex(int s) {
this.index = s;
this.complexStep = s;
}
/**
* <p>Getter for the field <code>index</code>.</p>
*
* @return a int
*/
public int getIndex() {
return this.index;
}
/**
* <p>Setter for the field <code>program</code>.</p>
*
* @param p a {@link org.redfx.strange.Program} object
*/
public void setProgram(Program p) {
this.program = p;
}
/**
* <p>Getter for the field <code>program</code>.</p>
*
* @return a {@link org.redfx.strange.Program} object
*/
public Program getProgram() {
return this.program;
}
/**
* <p>setInverse.</p>
*
* @param val a boolean
*/
public void setInverse(boolean val) {
// TODO: https://github.com/redfx-quantum/strange/issues/93
for (Gate g: gates) {
if (g instanceof BlockGate) {
((BlockGate)g).inverse();
} else {
g.setInverse(val);
}
}
}
private void verifyUnique (Gate gate) {
for (Gate g: gates) {
long overlap = g.getAffectedQubitIndexes().stream().filter(gate.getAffectedQubitIndexes()::contains).count();
if (overlap > 0) throw new IllegalArgumentException("Adding gate that affects a qubit already involved in this step");
}
}
/** {@inheritDoc} */
@Override public String toString() {
if (this.getType() == Step.Type.PSEUDO) {
return "Pseudo-step";
} else {
return "Step with gates "+this.gates;
}
}
}