Home Reference Source # src/ops/uniformly_controlled_rotation.js

``````import math from 'mathjs'
import deepEqual from 'deep-eql'
import {BasicGate, ANGLE_PRECISION, ANGLE_TOLERANCE} from './basics'
import {NotMergeable} from '../meta/error'

/**
* @param {number[]} angles
* @return {number[]}
*/
function roundAngles(angles) {
const rounded_angles = []
angles.forEach((angle) => {
let newAngle = math.round(angle % (4 * math.pi), ANGLE_PRECISION)
if (newAngle > 4 * math.pi - ANGLE_TOLERANCE) {
newAngle = 0
}
if (Object.is(newAngle, -0)) {
newAngle = 0
}
rounded_angles.push(newAngle)
})
return rounded_angles
}

/**
* Uniformly controlled Ry gate as introduced in arXiv:quant-ph/0312218.

This is an n-qubit gate. There are n-1 control qubits and one target qubit.
This gate applies Ry(angles(k)) to the target qubit if the n-1 control
qubits are in the classical state k. As there are 2^(n-1) classical
states for the control qubits, this gate requires 2^(n-1) (potentially
different) angle parameters.

Example:
.. code-block:: python

controls = eng.allocate_qureg(2)
target = eng.allocate_qubit()
UniformlyControlledRy(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)

Note:
The first quantum register contains the control qubits. When converting
the classical state k of the control qubits to an integer, we define
controls to be the least significant (qu)bit. controls can also
be an empty list in which case the gate corresponds to an Ry.

Args:
angles(list[float]): Rotation angles. Ry(angles[k]) is applied
conditioned on the control qubits being in state
k.
* @class UniformlyControlledRy
*/
export class UniformlyControlledRy extends BasicGate {
/**
* @constructor
* @param {number[]} angles
*/
constructor(angles) {
super()
this.angles = roundAngles(angles)
}

getInverse() {
return new UniformlyControlledRy(this.angles.map(angle => -angle))
}

getMerged(other) {
if (other instanceof UniformlyControlledRy) {
const angles = other.angles.map((a1, idx) => a1 + this.angles[idx])
return new UniformlyControlledRy(angles)
} else {
throw new NotMergeable()
}
}

toString() {
const str = this.angles.map(a => a.toString()).join(', ')
return `UniformlyControlledRy([\${str}])`
}

equal(other) {
if (other instanceof UniformlyControlledRy) {
return deepEqual(this.angles, other.angles)
}
return false
}
}

/**
* Uniformly controlled Rz gate as introduced in arXiv:quant-ph/0312218.

This is an n-qubit gate. There are n-1 control qubits and one target qubit.
This gate applies Rz(angles(k)) to the target qubit if the n-1 control
qubits are in the classical state k. As there are 2^(n-1) classical
states for the control qubits, this gate requires 2^(n-1) (potentially
different) angle parameters.

Example:
.. code-block:: python

controls = eng.allocate_qureg(2)
target = eng.allocate_qubit()
UniformlyControlledRz(angles=[0.1, 0.2, 0.3, 0.4]) | (controls, target)

Note:
The first quantum register are the contains qubits. When converting
the classical state k of the control qubits to an integer, we define
controls to be the least significant (qu)bit. controls can also
be an empty list in which case the gate corresponds to an Rz.

Args:
angles(list[float]): Rotation angles. Rz(angles[k]) is applied
conditioned on the control qubits being in state
k.
@class UniformlyControlledRz
*/
export class UniformlyControlledRz extends BasicGate {
/**
* @constructor
* @param {number[]} angles
*/
constructor(angles) {
super()
this.angles = roundAngles(angles)
}

getInverse() {
return new UniformlyControlledRz(this.angles.map(angle => -angle))
}

getMerged(other) {
if (other instanceof UniformlyControlledRz) {
const angles = other.angles.map((a1, idx) => a1 + this.angles[idx])
return new UniformlyControlledRz(angles)
} else {
throw new NotMergeable()
}
}

toString() {
const str = this.angles.map(a => a.toString()).join(', ')
return `UniformlyControlledRz([\${str}])`
}

equal(other) {
if (other instanceof UniformlyControlledRz) {
return deepEqual(this.angles, other.angles)
}
return false
}
}
``````