Skip to content

Instantly share code, notes, and snippets.

@daxfohl
Created May 10, 2025 15:02

Revisions

  1. daxfohl created this gist May 10, 2025.
    122 changes: 122 additions & 0 deletions quantum2.kt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    // QReg interface and implementations

    interface QReg<T : QReg<T>> {
    fun mapIndices(mapper: (Int) -> Int): T
    fun indices(): List<Int>
    }

    data class Qubit(val index: Int) : QReg<Qubit> {
    override fun mapIndices(mapper: (Int) -> Int) = Qubit(mapper(index))
    override fun indices() = listOf(index)
    }

    data class QPair(val i1: Int, val i2: Int) : QReg<QPair> {
    override fun mapIndices(mapper: (Int) -> Int) = QPair(mapper(i1), mapper(i2))
    override fun indices() = listOf(i1, i2)
    }

    // Operation

    data class Operation<S>(
    val opName: String,
    val apply: (S) -> String
    )

    // Channels and state representations

    data class DM(val r: Float, val i: Float)
    data class SV(val value: Float)

    data class Channel(val r: Float, val i: Float)
    data class Unitary(val factor: Float)

    fun mockApplyChannel(channel: Channel, indices: List<Int>, dm: DM): String =
    "channel: $channel dm$dm indices$indices"

    fun mockApplyUnitary(unitary: Unitary, indices: List<Int>, sv: SV): String =
    "unitary: $unitary sv$sv indices$indices"

    fun unitaryToChannel(u: Unitary) = Channel(u.factor, u.factor)

    // Interfaces

    interface GateReader {
    fun name(): String
    }

    interface Gate<Q : QReg<Q>, S> : GateReader {
    fun on(qureg: Q): Operation<S>
    }

    interface ChannelGateReader : GateReader {
    fun getChannel(): Channel
    }

    interface ChannelGate<Q : QReg<Q>> : ChannelGateReader, Gate<Q, DM> {
    fun applyChannel(qureg: Q, dm: DM): String {
    return mockApplyChannel(getChannel(), qureg.indices(), dm)
    }

    override fun on(qureg: Q): Operation<DM> =
    Operation(name()) { dm -> applyChannel(qureg, dm) }
    }

    interface UnitaryGateReader : GateReader {
    fun getUnitary(): Unitary
    }

    interface UnitaryGate<Q : QReg<Q>> : UnitaryGateReader, Gate<Q, SV> {
    fun applyUnitary(qureg: Q, sv: SV): String {
    return mockApplyUnitary(getUnitary(), qureg.indices(), sv)
    }

    override fun on(qureg: Q): Operation<SV> =
    Operation(name()) { sv -> applyUnitary(qureg, sv) }
    }

    // Extension to convert UnitaryGate into ChannelGate
    fun <Q : QReg<Q>> UnitaryGate<Q>.asChannelGate(): ChannelGate<Q> =
    UnitaryChannelGate(this)

    // BitFlip gate

    data class BitFlip(val p: Float) : ChannelGate<Qubit> {
    override fun getChannel() = Channel(p, p)
    override fun name() = "BitFlip"
    }

    // XPowGate

    data class XPowGate(val exp: Float) : UnitaryGate<Qubit> {
    override fun getUnitary() = Unitary(exp)
    override fun name() = "XPowGate"
    }

    // UnitaryChannelGate: generalized over Q

    data class UnitaryChannelGate<Q : QReg<Q>>(
    val u: UnitaryGate<Q>
    ) : ChannelGate<Q> {
    override fun getChannel(): Channel = unitaryToChannel(u.getUnitary())
    override fun name(): String = u.name()
    }

    // Simulator

    fun <S> sim(state: S, ops: List<Operation<S>>): String =
    ops.joinToString("\n") { it.apply(state) }

    // Example usage

    fun main() {
    val dm = DM(0.3f, 0.5f)

    val ops = listOf(
    BitFlip(0.4f).on(Qubit(4)),
    BitFlip(0.4f).on(Qubit(4)),
    XPowGate(0.4f).asChannelGate().on(Qubit(4))
    )

    val result = sim(dm, ops)
    println(result)
    }