///|
/// A quantum action on an ordered local wire shape such as `Gate`, `Channel`, and `Program`.
///
/// An effect describes an operation independently of the physical wires
/// it is applied to. Its local wire indices are mapped onto the enclosing
/// operation's target wires when it is added to a program or circuit.
pub(open) trait Effect {
/// A label for display and error messages.
fn measurement_key(Self) -> String? = _
fn name(Self) -> String
/// Returns the dimensions of the local quantum wires acted upon by
/// this effect, in their logical order.
///
/// Each element specifies the Hilbert-space dimension of one wire.
/// For example, `[2, 2]` represents two qubits, while `[2, 3]`
/// represents one qubit and one qutrit.
///
/// The order is significant: `[2, 3]` and `[3, 2]` describe
/// different ordered wire shapes.
fn dimensions(Self) -> Array[UInt32]
/// The number of local wires, not the product of their dimensions.
fn arity(Self) -> Int32 = _
/// Try to provide an exact unitary gate equivalent to this effect.
fn try_unitary(Self) -> Gate? = _
/// Try to provide an equivalent completely positive, trace-preserving
/// quantum channel.
fn try_channel(Self) -> Channel? = _
/// Try to decompose this effect into an equivalent quantum program.
fn try_decompose(Self) -> Program? raise QuantumError = _
/// Try to provide the adjoint as an effect with the same ordered shape.
/// For a unitary, this is its inverse. Unbound symbols may stay symbolic.
/// General noisy channels need not have an adjoint that is a valid effect.
fn try_adjoint(Self) -> &Effect? raise QuantumError = _
/// Free parameter names, without duplicates, in lexical order.
/// Parameters let you build a circuit with values you will supply later, such as a rotation angle.
fn parameters(Self) -> Array[String] = _
}
///|
impl Effect with fn arity(self) -> Int32 {
self.dimensions().length()
}
///|
impl Effect with fn try_unitary(_self) -> Gate? {
None
}
///|
impl Effect with fn try_channel(_self) -> Channel? {
None
}
///|
impl Effect with fn try_decompose(_self) -> Program? raise QuantumError {
None
}
///|
impl Effect with fn try_adjoint(_self) -> &Effect? raise QuantumError {
None
}
///|
impl Effect with fn parameters(_self) -> Array[String] {
[]
}
///|
impl Effect with fn measurement_key(_self) -> String? {
None
}
/// ----- Implement Effect for Gate -----
///|
pub impl Effect for Gate with fn name(self) -> String {
self.label
}
///|
pub impl Effect for Gate with fn dimensions(self) -> Array[UInt32] {
self.shape.copy()
}
///|
pub impl Effect for Gate with fn try_unitary(self) -> Gate? {
Some(self)
}
/// ----- -----
///|
pub extend Gate with Effect::{
measurement_key,
try_unitary,
try_channel,
try_decompose,
try_adjoint,
parameters,
}