Home Reference Source

src/ops/gates.js

/*
 * Copyright (c) 2018 Isaac Phoenix ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
Contains definitions of standard gates such as
* Hadamard (H)
* Pauli-X (X / NOT)
* Pauli-Z (Z)
* T and its inverse (T / Tdagger)
* Swap gate (Swap)
* Phase gate (Ph)
* Rotation-Z (Rz)
* Phase-shift (R)
* Measurement (Measure)

and meta gates, i.e.,
* Allocate / Deallocate qubits
* Flush gate (end of circuit)
*/
import math from 'mathjs'
import {
  SelfInverseGate, BasicPhaseGate, BasicRotationGate, BasicMathGate, BasicGate, FastForwardingGate, ClassicalInstructionGate
} from './basics'

import {getInverse} from './_cycle'

const mc = math.complex
const mm = math.matrix

/**
 * @class HGate
 */
export class HGate extends SelfInverseGate {
  toString() {
    return 'H'
  }

  get matrix() {
    return mm([
      [mc(Math.SQRT1_2, 0), mc(Math.SQRT1_2, 0)],
      [mc(Math.SQRT1_2, 0), mc(-Math.SQRT1_2, 0)]
    ])
  }
}

export const H = new HGate()

/**
 * @class XGate
 */
// Pauli-X gate class
export class XGate extends SelfInverseGate {
  toString() {
    return 'X'
  }

  get matrix() {
    return mm([
      [0, 1],
      [1, 0]
    ])
  }
}


// Shortcut (instance of) `XGate`
export const X = new XGate()
export const NOT = X

/**
 * @class YGate
 */
// Pauli-Y gate class
export class YGate extends SelfInverseGate {
  toString() {
    return 'Y'
  }

  get matrix() {
    return mm([
      [0, mc(0, -1)],
      [mc(0, 1), 0],
    ])
  }
}

// Shortcut (instance of) `YGate`
export const Y = new YGate()

/**
 * @class ZGate
 * Pauli-Z gate class
 */
export class ZGate extends SelfInverseGate {
  toString() {
    return 'Z'
  }

  get matrix() {
    return mm([
      [1, 0],
      [0, -1]
    ])
  }
}

// Shortcut (instance of) `ZGate`
export const Z = new ZGate()

/**
 * @class SGate
 */
// S gate class
export class SGate extends SelfInverseGate {
  toString() {
    return 'S'
  }

  get matrix() {
    return mm([
      [1, 0],
      [0, mc(0, 1)]
    ])
  }
}

// Shortcut (instance of) `SGate`
export const S = new SGate()

/**
 * @class TGate
 */
// T gate class
export class TGate extends BasicGate {
  get matrix() {
    return mm([
      [1, 0],
      [0, mc(Math.SQRT1_2, Math.SQRT1_2)]
    ])
  }

  toString() {
    return 'T'
  }
}

// Shortcut (instance of) `TGate`
export const T = new TGate()

/**
 * @class SqrtXGate
 */
// Square-root X gate class
export class SqrtXGate extends BasicGate {
  get matrix() {
    return mm([
      [mc(0.5, 0.5), mc(0.5, -0.5)],
      [mc(0.5, -0.5), mc(0.5, 0.5)]
    ])
  }

  toString() {
    return 'SqrtX'
  }

  texString() {
    return '$\\sqrt{X}$'
  }
}

// Shortcut (instance of) `SqrtXGate`
export const SqrtX = new SqrtXGate()

/**
 * @class SwapGate
 * @desc Swap gate class (swaps 2 qubits) also self inverse gate
 */
export class SwapGate extends BasicMathGate {
  constructor() {
    super((x, y) => [y, x])
    this.interchangeableQubitIndices = [[0, 1]]
  }

  toString() {
    return 'Swap'
  }

  get matrix() {
    return mm([
      [1, 0, 0, 0],
      [0, 0, 1, 0],
      [0, 1, 0, 0],
      [0, 0, 0, 1]
    ])
  }

  getInverse() {
    const inv = new SwapGate()
    inv.interchangeableQubitIndices = this.interchangeableQubitIndices.slice(0)
    return inv
  }
}

// Shortcut (instance of) `SwapGate`
export const Swap = new SwapGate()

/**
 * @class SqrtSwapGate
 * @desc Square-root Swap gate class
 */
export class SqrtSwapGate extends BasicGate {
  constructor() {
    super()
    this.interchangeableQubitIndices = [[0, 1]]
  }

  toString() {
    return 'SqrtSwap'
  }

  get matrix() {
    return mm([
      [1, 0, 0, 0],
      [0, mc(0.5, 0.5), mc(0.5, -0.5), 0],
      [0, mc(0.5, -0.5), mc(0.5, 0.5), 0],
      [0, 0, 0, 1]
    ])
  }
}

// Shortcut (instance of) `SqrtSwapGate`
export const SqrtSwap = new SqrtSwapGate()

/**
 * @class EntangleGate
 * @desc gate (Hadamard on first qubit, followed by CNOTs applied to all other qubits).
*/
export class EntangleGate extends BasicGate {
  toString() {
    return 'Entangle'
  }

  get matrix() {
    throw new Error('No Attribute')
  }
}


// Shortcut (instance of) `EntangleGate`
export const Entangle = new EntangleGate()

/**
 * @class Ph
 * @desc Phase gate (global phase)
 */
export class Ph extends BasicPhaseGate {
  get matrix() {
    return mm([
      [mc(Math.cos(this.angle), Math.sin(this.angle)), 0],
      [0, mc(Math.cos(this.angle), Math.sin(this.angle))]
    ])
  }
}

/**
 * @class Rx
 */
export class Rx extends BasicRotationGate {
  get matrix() {
    return mm([
      [Math.cos(0.5 * this.angle), mc(0, -1 * Math.sin(0.5 * this.angle))],
      [mc(0, -1 * Math.sin(0.5 * this.angle)), Math.cos(0.5 * this.angle)]
    ])
  }
}

/**
 * @class Ry
 */
export class Ry extends BasicRotationGate {
  get matrix() {
    return mm([
      [Math.cos(0.5 * this.angle), -Math.sin(0.5 * this.angle)],
      [Math.sin(0.5 * this.angle), Math.cos(0.5 * this.angle)]
    ])
  }
}

/**
 * @class Rz
 * @desc RotationZ gate class
 */
export class Rz extends BasicRotationGate {
  get matrix() {
    return mm([
      [mc(Math.cos(-0.5 * this.angle), Math.sin(-0.5 * this.angle)), 0],
      [0, mc(Math.cos(0.5 * this.angle), Math.sin(0.5 * this.angle))]
    ])
  }
}

/**
 * @class R
 * @desc Phase-shift gate (equivalent to Rz up to a global phase)
 */
export class R extends BasicPhaseGate {
  get matrix() {
    return mm([[1, 0], [0, mc(Math.cos(this.angle), Math.sin(this.angle))]])
  }
}

/**
 * @class FlushGate
 * @desc
Flush gate (denotes the end of the circuit).

Note:
    All compiler engines (cengines) which cache/buffer gates are obligated
to flush and send all gates to the next compiler engine (followed by
the flush command).

Note:
    This gate is sent when calling

 @example

eng.flush()

on the MainEngine `eng`.

 */
export class FlushGate extends FastForwardingGate {
  toString() {
    return ''
  }
}

/**
 * @class MeasureGate
 * @desc Measurement gate class (for single qubits).
 */
export class MeasureGate extends FastForwardingGate {
  toString() {
    return 'Measure'
  }

  /**
    Previously (ProjectQ <= v0.3.6) MeasureGate/Measure was allowed to be
    applied to any number of quantum registers. Now the MeasureGate/Measure
    is strictly a single qubit gate. In the coming releases the backward
    compatibility will be removed!

     */
  or(qubits) {
    let num_qubits = 0
    const qs = BasicGate.makeTupleOfQureg(qubits)
    qs.forEach((qureg) => {
      qureg.forEach((qubit) => {
        num_qubits += 1
        const cmd = this.generateCommand([qubit])
        cmd.apply()
      })
    })
    if (num_qubits > 1) {
      console.warn('Pending syntax change in future versions of '
      + 'ProjectQ: \n Measure will be a single qubit gate '
      + 'only. Use `All(Measure) | qureg` instead to '
        + 'measure multiple qubits.')
    }
  }
}


// Shortcut (instance of) `MeasureGate`
export const Measure = new MeasureGate()

export let Deallocate

/**
 * @class AllocateQubitGate
 */
export class AllocateQubitGate extends ClassicalInstructionGate {
  toString() {
    return 'Allocate'
  }

  getInverse() {
    return Deallocate
  }
}

// Shortcut (instance of) `AllocateQubitGate`
export const Allocate = new AllocateQubitGate()

/**
 * @class DeallocateQubitGate
 */
export class DeallocateQubitGate extends FastForwardingGate {
  toString() {
    return 'Deallocate'
  }

  getInverse() {
    return Allocate
  }
}

// Shortcut (instance of) `DeallocateQubitGate`
Deallocate = new DeallocateQubitGate()

/**
 * @class AllocateDirtyQubitGate
 */
export class AllocateDirtyQubitGate extends ClassicalInstructionGate {
  toString() {
    return 'AllocateDirty'
  }

  getInverse() {
    return Deallocate
  }
}

// Shortcut (instance of) AllocateDirtyQubitGate
export const AllocateDirty = new AllocateDirtyQubitGate()

export let Barrier

export class BarrierGate extends BasicGate {
  toString() {
    return 'Barrier'
  }

  getInverse() {
    return Barrier
  }
}

// Shortcut (instance of) BarrierGate
Barrier = new BarrierGate()

const obj = {}
let _sdag = null
let _tdag = null
Object.defineProperties(obj, {
  Sdag: {
    get() {
      if (!_sdag) {
        _sdag = getInverse(S)
      }
      return _sdag
    }
  },
  Sdagger: {
    get() {
      return obj.Sdag
    }
  },
  Tdag: {
    get() {
      if (!_tdag) {
        _tdag = getInverse(T)
      }
      return _tdag
    }
  },
  Tdagger: {
    get() {
      return obj.Tdag
    }
  }
})

/**
 * @ignore
 */
export default obj