Extending Dirac’s Bra–Ket Notation to a 3‑State Computation System

Theoretical Framework

In quantum mechanics, Dirac’s bra–ket notation is a powerful formalism for representing states and operations using vector-like symbols. A ket such as ∣ψ⟩ ∣ψ⟩ denotes a state vector (e.g. ∣0⟩ ∣0⟩ or ∣1⟩ ∣1⟩ for a qubit), and the corresponding bra ⟨ψ∣ ⟨ψ∣ denotes its dual (the conjugate transpose row vector). An inner product between states appears as a “bra-ket” ⟨ϕ∣ψ⟩ ⟨ϕ∣ψ⟩, producing a scalar amplitude. Operators (transformations) are inserted between a bra and a ket: for example, ⟨x∣O∣z⟩ ⟨x∣ O ^ ∣z⟩ represents the matrix element of operator O^ O ^ mapping state ∣z⟩ ∣z⟩ to state ∣x⟩ ∣x⟩. Bra–ket notation concisely captures how quantum states and processes (operators) relate, something we aim to mirror in a new three-part form.

Extending to a 3-state system: We introduce a notation ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ as an analogue of Dirac’s bracket, but with three components: an initial state or input x x, a process or transformation y y, and a resulting state or output z z. This triple can be read as “ y y transforms x x into z z.” It echoes the structure of a quantum amplitude ⟨output∣O∣input⟩ ⟨output∣ O ^ ∣input⟩, except here we treat the transformation y y as an explicit part of the tuple rather than an operator between bra and ket. In classical computing terms, it parallels the fundamental input–process–output model of computation. Just as a classical program takes an input and produces output, our notation ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ encapsulates a computational step with x x as input, y y as the operation, and z z as the output. This structure has a strong resemblance to the Hoare triple in programming logic {P} C {Q} {P}C{Q}, where P P is a precondition, C C a command, and Q Q the postcondition. In fact, ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ can be seen as a computational state transformer: when the pre-state satisfies condition x x, executing process y y yields post-state z z. Unlike Hoare logic (which is typically propositional, describing conditions), our notation treats x,y,z x,y,z as data or states themselves, making it a more concrete “executable” representation.

Inspiration from quantum 3-state systems: The “3-state qubit” concept corresponds to a qutrit, a quantum system with three basis states (often ∣0⟩ ∣0⟩, ∣1⟩ ∣1⟩, ∣2⟩ ∣2⟩). A qutrit can exist in a superposition α∣0⟩+β∣1⟩+γ∣2⟩ α∣0⟩+β∣1⟩+γ∣2⟩, with complex amplitudes α,β,γ α,β,γ obeying ∣α∣2+∣β∣2+∣γ∣2=1 ∣α∣ 2 +∣β∣ 2 +∣γ∣ 2 =1. Our notation ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ is not exactly a quantum state, but it is inspired by the idea of a ternary basis. Conceptually, one might think of x x, y y, z z as inhabiting three different “spaces” or roles (input space, process space, output space), analogous to a triple tensor product of spaces. This is a departure from standard bra–ket which has only two spaces (bra and ket), but it opens up new possibilities. In quantum terms, we could interpret ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ as a kind of transition amplitude from ∣x⟩ ∣x⟩ to ∣z⟩ ∣z⟩ via an intermediate operator/state y y. Standard Dirac notation would write something like ⟨z∣U∣x⟩ ⟨z∣U∣x⟩ for the amplitude of obtaining z z from x x under operation U U. Here we elevate U U (the process) to the middle of our bracket as y y for symmetry and generality, treating it on par with initial and final states.

Directional arrows ( → →, ← ←): We extend the notation with arrows to indicate the direction of computation or inference. A forward arrow ⟨x∣y→z⟩ ⟨x∣y→z⟩ denotes that applying process y y to input x x yields output z z. On the other hand, a backward arrow ⟨x←y∣z⟩ ⟨x←y∣z⟩ would indicate that we are using process y y in reverse (or solving for the input) given output z z. This is analogous to the concept of reversible computing, where every computation step is invertible. In a reversible system, if x→yz x y ​ z, then there exists an inverse process y−1 y −1 such that z→y−1x z y −1 ​ x. Using arrows in the bracket makes the direction explicit: one can think of → → as a “time-forward” evolution and ← ← as a “time-reversed” or inverse operation. For example, if y y is a function (or quantum gate) that maps 3 to 9 (say, squaring: y(n)=n2 y(n)=n 2 ), we write ⟨3∣Square→9⟩ ⟨3∣Square→9⟩. The inverse would be ⟨3←Square∣9⟩ ⟨3←Square∣9⟩, signifying that from output 9, we deduce the original input 3 by the inverse operation (square root). This mirrors the bra–ket duality: in Dirac notation the “adjoint” (Hermitian conjugate) of an operator corresponds to running the operation in reverse. Here, swapping the arrow from → → to ← ← and exchanging x x and z z conceptually gives the adjoint triple ⟨z∣y−1∣x⟩ ⟨z∣y −1 ∣x⟩. This property aligns with quantum operations being reversible (unitary) transformations.

Data structure view: Crucially, we treat ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ as a computable data structure or algebraic object, not just a notation for abstract math. Each triple encapsulates a piece of computation (like a record with fields for input, process, output). Because it’s a structured entity, we can imagine manipulating these triples with computer code – combining them, transforming them, and executing them. This idea draws on the concept of arrows in computer science (as defined by John Hughes), which generalize functions to describe computations with both inputs and outputs in a composable way. In Haskell’s arrow framework, for instance, one can compose two computations f and g using an operator like >>> if the output type of f matches the input type of g. Similarly, with our triples, if we have ⟨a∣y∣b⟩ ⟨a∣y∣b⟩ and ⟨b∣y′∣c⟩ ⟨b∣y ′ ∣c⟩ (the output of the first matches the input of the second), we can concatenate or compose them to get ⟨a∣y;y′∣c⟩ ⟨a∣y;y ′ ∣c⟩. This composition behaves like function composition or matrix multiplication of operators, a key property for building complex computations from simpler ones. We will demonstrate such composition with Ruby code shortly, treating the triple as a first-class object.

Bridging quantum and classical paradigms: The triple notation provides a framework to compare different computational paradigms in a unified way. In classical computing, we usually consider input and algorithm as given, and we deterministically produce output. In machine learning, one often has input and output examples and tries to infer the model (the process) that maps them. Interestingly, in some formulations of quantum computing, one might view certain problems “backwards” – for instance, Grover’s algorithm can be seen as taking a known output condition and finding an input that satisfies it, with the quantum algorithm (process) guiding the search. Our ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ can, in principle, represent all these scenarios by leaving one of the components unknown and solving for it. With an arrow marking the direction, we could denote a quantum algorithm’s inversion as ⟨?←Grover∣solution⟩ ⟨?←Grover∣solution⟩ meaning “given the desired output solution, find the input that produces it via Grover’s process,” illustrating how quantum computing sometimes “takes the output and model as given and produces the input probabilistically”. This flexibility suggests philosophical parallels to how knowledge is represented: the triple encapsulates a relation among cause (input), effect (output), and transformation (law) – much like how physical laws relate initial and final states. Dirac notation itself was designed to seamlessly describe superpositions and transformations in physics, and by extending it, we inch toward a language that might describe not only quantum states but also computational processes in an integrated formalism.

Ternary logic and beyond: Considering practical computing, using a three-state notation resonates with the idea of ternary (base-3) computation, which has been studied as an alternative to binary. Ternary logic is theorized to be more efficient in certain hardware contexts – it’s been mathematically shown that a three-level signal can be the optimal encoding in terms of minimal energy or information density. In fact, engineers have built ternary computers (like the Soviet Setun in 1958) that showed potential advantages in speed and cost. The interest in “beyond binary” is growing, as three-state devices (e.g. multi-level memory cells, memristors, quantum qutrits) become feasible. Our notation ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ could serve as a conceptual tool for ternary computing models, since it inherently calls out three components. For example, one might use it to represent a balanced ternary operation with x∈{−1,0,1} x∈{−1,0,1}, z∈{−1,0,1} z∈{−1,0,1}, and y y describing some ternary logic gate. The notation “allows thinking beyond black and white” (beyond Boolean), as one researcher quipped, analogous to how a third truth value in logic (e.g. “unknown” or “indeterminate”) adds nuance to reasoning. While our primary interpretation is not limited to any specific values of x,y,z x,y,z, it’s encouraging that the form aligns with emerging hardware and logic paradigms that inherently use three states.

In summary, the ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ notation generalizes Dirac’s bracket to explicitly include the transformation alongside initial and final states. It aligns with quantum notation (where an operator connects bra to ket) but elevates the operator to equal footing as a middle “state” or label. By incorporating directionality and treating the entire triple as a manipulable entity, we get a formalism that is both mathematically inspired and suitable as a pseudocode-like language construct. Next, we demonstrate how one might implement and experiment with this concept in Ruby, treating ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ as a data structure with which we can perform operations.


Ruby Code Implementation of the 3-State System

We can simulate the ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ notation in Ruby by creating a custom class to hold the three components and define operations on them. Ruby is a flexible, dynamic language, which allows us to override operators and create domain-specific representations easily. Below is a step-by-step implementation and demonstration:


Define a class for the triple state computation notation
class TriBraKet
  attr_accessor :input, :process_label, :output, :direction, :operation

  def initialize(input, process_label, output, direction=:forward, &operation)
    @input = input            # x: initial state or input
    @process_label = process_label  # y: label or name of the process
    @output = output          # z: resulting state or output
    @direction = direction    # :forward or :backward
    @operation = operation    # optional actual operation (Proc) for computation
  end

  # String representation for visualization in <x | process | z> form with arrow
  def to_s
    if @direction == :forward
      ParseError
    else  # :backward
      ParseError
    end
  end

  # Verify that applying the process to input yields output (if operation given)
  def valid?
    return true unless @operation    # if no operation block provided, skip
    if @direction == :forward
      @operation.call(@input) == @output
    else
      @operation.call(@output) == @input  # for backward, apply inverse on output
    end
  end

  # Compose this triple with another triple (if this.output == other.input)
  def compose(other)
    unless self.output == other.input && self.direction == :forward && other.direction == :forward
      raise
Can¬compose:states∨directionsincompatible
Can¬compose:states∨directionsincompatible
    end
    # Compose the operations sequentially, if present
    if self.operation && other.operation
      composed_op = proc { |x| other.operation.call(self.operation.call(x)) }
    else
      composed_op = nil
    end
    composed_label = 
    TriBraKet.new(self.input, composed_label, other.output, :forward, &composed_op)
  end
end


Example usage:
Create a triple for adding 3 (process "Add3": 2 -> 5)
triple1 = TriBraKet.new(2,
Add3
Add3, 5, :forward) { |x| x + 3 }
puts triple1.to_s  # visualize it
puts
Valid?
Valid? if triple1.valid?


Create a triple for multiplying by 2 (process "Mul2": 5 -> 10)
triple2 = TriBraKet.new(5,
Mul2
Mul2, 10, :forward) { |x| x * 2 }
puts triple2.to_s
puts
Valid?
Valid? if triple2.valid?


Compose triple1 and triple2 (since 5 from triple1 output matches triple2 input)
triple3 = triple1.compose(triple2)
puts triple3.to_s   # should represent 2 --Add3; Mul2--> 10
puts
Valid?
Valid? if triple3.valid?  # Check if composed operation from 2 gives 10


Example of a backward (inverse) triple: Square operation seen in reverse (3 <- Square | 9)
triple_back = TriBraKet.new(3,
Squ
Squ, 9, :backward) { |y| Math.sqrt(y) }
puts triple_back.to_s
puts
Valid?
Valid? if triple_back.valid?

Let’s break down what this code accomplishes:

  1. Class Definition (TriBraKet): We define a class with attributes for input (x), process_label (y), output (z), and direction. The initializer takes these along with an optional block representing the actual operation to perform. (For example, if y is “Add3”, the block could be { |x| x+3 }.) Storing a Proc in @operation lets us actually compute y(x) y(x) when needed. We default the direction to :forward but it can be set to :backward to indicate an inverse relationship.

  2. String Representation (to_s): For easy visualization, we override to_s to display the triple in the form ⟨x | y -> z⟩ or ⟨x <- y | z⟩, depending on the direction. We use the Unicode bra-ket symbols “⟨⟩” for a closer analogy to Dirac notation, and insert an arrow -> or <- next to the process. For instance, a forward triple might print as ⟨2 | Add3 -> 5⟩, indicating 2→Add35 2 Add3 ​

  3. A backward triple like ⟨3 <- Square | 9⟩ indicates 9 9 is the result of squaring 3 3, or equivalently 3 3 is obtained by applying the inverse of “Square” to 9

  4. This string format provides a visual pseudocode for the computation, which could be useful for logging or diagrams of data flow.

  5. Validation (valid? method): We include a helper that actually checks the math: it uses the stored @operation (if provided) to verify that applying y y to x x yields z z (forward) or that applying the inverse (modeled by the block when direction is backward) to z z gives x x. For example, for triple1 = ⟨2|Add3->5⟩, valid? will compute 2+3 and confirm it equals 5. This ensures internal consistency of the triple. If no actual operation block is given, valid? just returns true by default (treating it as a purely symbolic triple).

  6. Composition (compose method): Here we allow two triples to be composed sequentially, analogous to function composition or chaining of operations. The method checks that the current triple is forward and the next triple is forward (for simplicity, we only compose forward-directed computations), and that this triple’s output matches the next triple’s input. If so, it creates a new TriBraKet whose input is the first triple’s input, output is the second triple’s output, and the process label is a concatenation like Process1;    Process2 Process1;Process2. If both triples have actual operations, it also composes those functions so that the new triple’s @operation will execute first y then y'. For example, if we have ⟨2∣Add3∣5⟩ ⟨2∣Add3∣5⟩ and ⟨5∣Mul2∣10⟩ ⟨5∣Mul2∣10⟩, their composition is ⟨2∣Add3; Mul2∣10⟩ ⟨2∣Add3; Mul2∣10⟩. Internally, this new triple’s operation will do x + 3 then times 2. This mimics how one would compose two transformations y;y′ y;y ′ , reflecting the mathematical composition y′(y(x)) y ′ (y(x)). (This is directly analogous to composing arrows in Haskell with >>> when types align.) If the states don’t align, we raise an error – preventing invalid compositions where the “output” of one step doesn’t match the “input” of the next.

  7. Example objects and output: We create two forward triples, triple1 and triple2.

We then compose triple1.compose(triple2) to get triple3. This represents the combined process “Add3; Mul2” taking 2 all the way to 10. The to_s of triple3 would produce “⟨2 | Add3; Mul2 -> 10⟩”, clearly showing a pipeline: 2 →(+3)→ 5 →(×2)→ 10. The composed valid? now effectively checks (2+3)×2==10 (2+3)×2==10, which should pass. This demonstrates how multiple ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ structures can be linked to model a multi-step computation, just as successive quantum gates or function calls would be.

Finally, we show triple_back = ⟨3 \leftarrow \text{Square} | 9⟩ as an example of a backward-directed triple. We supply a block {|y| Math.sqrt(y)} which is essentially the inverse of squaring. Its to_s prints “⟨3 <- Square | 9⟩”, indicating that squaring 3 yields 9 (or taking sqrt of 9 returns 3). The valid? will do Math.sqrt(9) and check it equals 3 – again confirming the triple’s consistency but this time interpreting the block as y−1 y −1 on the output.

The Ruby simulation above treats the ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ notation as a concrete object with which we can compute and verify results. We also leveraged Ruby’s flexibility (for instance, we could overload + or * operators to combine triples in a more natural syntax if desired, and we can easily extend the class with more features). This kind of implementation illustrates that the notation is not just abstractly elegant, but also practical to work with in code. One could imagine building a small library where ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ objects can be manipulated, logged, or visualized as part of an algorithm’s pseudocode.


Extensions and Manipulations of $\langle x|y|z \rangle$ Notation

We have seen basic composition and inversion. To make ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ truly analogous to Dirac notation and useful for complex systems, we propose additional notations and manipulations:

In implementing these extensions, one must be careful to maintain logical consistency. The algebra of ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ should ideally form a mathematical structure (like a small category, where objects are states and morphisms are processes). Many of the above notations align with category theory ideas: we have identity morphisms, composition, possibly direct sums (superpositions) and products (parallel composition). By enforcing rules analogous to those in quantum mechanics (linearity, unitarity where applicable), we could ensure that the system remains well-behaved. For example, defining a distributive law for superposition: ⟨x∣(y1+y2)∣z⟩ ⟨x∣(y 1 ​ +y 2 ​ )∣z⟩ could be defined as shorthand for ⟨x∣y1∣z⟩+⟨x∣y2∣z⟩ ⟨x∣y 1 ​ ∣z⟩+⟨x∣y 2 ​ ∣z⟩, much as (A+B)∣ψ⟩=A∣ψ⟩+B∣ψ⟩ (A+B)∣ψ⟩=A∣ψ⟩+B∣ψ⟩ in linear algebra.

It’s worth noting that physicists and computer scientists have already explored using Dirac notation in program semantics. Quantum Hoare logic is a framework for verifying quantum programs, and it often uses a labeled Dirac notation to express assertions about program state (for instance, stating that a quantum register is in a certain state). In these logics, one might see judgments that combine classical conditions with bra-ket formalism for quantum parts. Our proposal for ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ could complement such efforts by providing a uniform way to talk about the program’s execution as a whole – bridging classical control structures (via the explicit process y y) with quantum state transformations (via the bra-ket style notation around them). It essentially embeds the program (algorithm y y) into the notation itself, rather than treating it as an external concept.

Philosophical Insights and Practical Applications

The ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ notation straddles the line between a mathematical formalism and a description language for computations. This dual nature invites several philosophical reflections:

  ⟨qubit_state | Apply(Hadamard) -> superposed_state⟩;
  ⟨superposed_state | Apply(Oracle) -> flipped_amplitudes⟩;
  ⟨flipped_amplitudes | Measure -> outcome⟩.

This isn’t far from how one talks through quantum algorithms in prose, but here it’s structured. It could serve as an intermediate representation that is human-readable yet precisely ties together states and operations. Practically, this could help in teaching quantum computing – students can write out the steps of an algorithm in bracket form to ensure they track the state changes explicitly, much like how one writes kets ∣ψinit⟩→U1∣ψ1⟩→U2∣ψ2⟩ etc.. The difference is our notation packages each step into a single object.

In conclusion, the proposed three-state computation notation ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ extends Dirac’s elegant bra–ket formalism to encapsulate the dynamic aspect of computations. We showed how this notation can be implemented and manipulated in a programming language (Ruby), proving that it’s not merely a theoretical curiosity but can serve as a computable pseudocode structure. By proposing additional analogues of Dirac notation’s features – composition, superposition, adjoint, identity – we make ⟨x∣y∣z⟩ ⟨x∣y∣z⟩ into a flexible toolkit, much like bra–ket is for quantum theory. The philosophical and practical implications are far-reaching: it could influence how we think about algorithms (merging the description of “what” and “how” into one bracketed expression), how we design future computing systems (especially ones that are inherently reversible or multi-state), and how we explain complex processes. In spirit, this approach aligns with the trend of borrowing concepts across disciplines: just as computer science has learned from category theory (arrows, monads) and physics has leveraged computer science for quantum algorithms, this triple notation is a transdisciplinary idea. It takes the clarity of quantum state notation and infuses it with the concreteness of computational steps, potentially leading to new ways to reason about and visualize computations as algebraic objects. The true test of its utility will be in applying it to real problems – whether in formal verification of programs, design of quantum algorithms, or even philosophical modeling of causation. The rich set of existing knowledge (from reversible computing theories to quantum Hoare logic) provides a foundation to build on, suggesting that this 3-state notation can be grounded in solid theory while opening pathways to innovative applications.