Documentation

Complexity.Computability.Circuit.Frontier.Compiler.Network

The graph and constraint network of a circuit #

Fix a circuit c with m outputs over any signature, an interpretation I of the signature in an alphabet U, and for each output o a set Acc o ⊆ U of accepting values. We build a constraint network (Compiler.network c I Acc) whose accepted inputs are exactly those on which every output o of the circuit lies in Acc o. A circuit deciding a set has one output; a circuit computing a function accepts every value at each of its outputs.

Only the reachable wires matter: the outputs and, recursively, the wires read by reachable gates (Reach). We call them signals (Signal). A signal is consumed by each argument slot of a reachable gate that reads it (Slot), and each output is also consumed by its own output vertex (Consumer). A circuit has unbounded fan-out, but a network of bounded degree cannot give a signal one edge per consumer. So each signal w with consumers t₀, t₁, ... is routed through a chain of junctions (Junction) j₀, j₁, ..., one per consumer:

  w --- j₀ --- j₁ --- j₂ --- ...
        |      |      |
        t₀     t₁     t₂

Each junction has one feed edge from its predecessor in the chain (the signal itself for j₀) and one deliver edge to its consumer. The constraints are:

Exactness (Compiler.satisfies_iff). The values of the circuit satisfy the network. Conversely, in a satisfying assignment the junction constraints force all edges of a signal to carry one value, and the gate constraints, read in program order, force that value to be the value of the signal in the circuit (Compiler.eq_trace). So the satisfying assignment, if any, is unique, and along any layout the read-once branching program of the network (Cslib.Circuits.Frontier.Network.branchingProgram) is unambiguous (Compiler.unambiguous_branchingProgram).

Outputs across a cut. If the runs of the circuit on two inputs x and y agree on the edge cut of a set of vertices P, the separator lemma splices them: on an input that reads like x at P and like y elsewhere, the outputs held in P are those of x and the others are those of y (Compiler.eval_splice).

Graph-theoretic properties (looplessness, degree bounds, connectivity) and cycle-rank / read-count inequalities are proved in Complexity/Computability/Circuit/Frontier/Compiler.lean.

Main definitions #

Main results #

References #

Signals, consumers, and junctions #

inductive Cslib.Circuits.Frontier.Compiler.Reach {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :
Wire n c.size → Prop

A wire of a circuit is reachable when it is an output or is read by a reachable gate.

Instances For
    @[reducible, inline]

    The signals of a circuit: its reachable wires.

    Instances For
      @[reducible, inline]
      abbrev Cslib.Circuits.Frontier.Compiler.Slot {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

      An argument slot of a reachable gate.

      Instances For
        @[reducible, inline]

        A consumer: an argument slot of a reachable gate, or an output.

        Instances For

          The signal read by a consumer.

          Instances For
            noncomputable def Cslib.Circuits.Frontier.Compiler.fanout {σ : Signature} {n m : ℕ} (c : Circuit σ n m) (w : Signal c) :

            The number of consumers of a signal.

            Instances For
              @[reducible, inline]

              A junction: a copy of a signal for one of its consumers. The junctions of a signal w are numbered 0, ..., fanout c w - 1.

              Instances For
                noncomputable def Cslib.Circuits.Frontier.Compiler.junctionEquiv {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

                Junctions correspond to consumers.

                Instances For
                  @[simp]

                  The consumer of a junction reads the signal of the junction.

                  @[simp]

                  The junction of a consumer belongs to the signal it reads.

                  theorem Cslib.Circuits.Frontier.Compiler.fanout_pos {σ : Signature} {n m : ℕ} {c : Circuit σ n m} (w : Signal c) :
                  0 < fanout c w

                  Every signal has a consumer.

                  The graph #

                  inductive Cslib.Circuits.Frontier.Compiler.Vertex {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

                  The vertices: one per signal, one per junction, and one per output.

                  Instances For
                    inductive Cslib.Circuits.Frontier.Compiler.Edge {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

                    The edges: two per junction.

                    Instances For

                      Vertices are signals, junctions, and outputs.

                      Instances For

                        Edges are two copies of the junctions.

                        Instances For

                          The vertex that consumes through a consumer: a gate vertex or an output vertex.

                          Instances For

                            The vertex feeding a junction: the signal itself for its first junction, and the previous junction of the chain otherwise.

                            Instances For

                              No junction feeds itself.

                              def Cslib.Circuits.Frontier.Compiler.src {σ : Signature} {n m : ℕ} {c : Circuit σ n m} :
                              Edge c → Vertex c

                              The source of an edge.

                              Instances For
                                noncomputable def Cslib.Circuits.Frontier.Compiler.tgt {σ : Signature} {n m : ℕ} {c : Circuit σ n m} :
                                Edge c → Vertex c

                                The target of an edge.

                                Instances For

                                  The signal carried by an edge.

                                  Instances For
                                    noncomputable def Cslib.Circuits.Frontier.Compiler.graph {σ : Signature} {n m : ℕ} (c : Circuit σ n m) :

                                    The graph of a circuit: the signals, junctions and outputs, joined by the feed and deliver edges of the junctions.

                                    Instances For
                                      @[simp]
                                      @[simp]
                                      noncomputable def Cslib.Circuits.Frontier.Compiler.deliverEdge {σ : Signature} {n m : ℕ} {c : Circuit σ n m} (t : Consumer c) :

                                      The edge delivering a signal to one of its consumers.

                                      Instances For
                                        @[reducible, inline]
                                        noncomputable abbrev Cslib.Circuits.Frontier.Compiler.argEdge {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {g : Fin c.size} (hg : Reach c (Wire.gate g)) (a : Fin (σ.Arity (c.program.lines g).op)) :

                                        The edge delivering argument a to the reachable gate g.

                                        Instances For
                                          @[reducible, inline]
                                          noncomputable abbrev Cslib.Circuits.Frontier.Compiler.outEdge {σ : Signature} {n m : ℕ} (c : Circuit σ n m) (o : Fin m) :

                                          The edge delivering an output to its output vertex.

                                          Instances For
                                            def Cslib.Circuits.Frontier.Compiler.head {σ : Signature} {n m : ℕ} {c : Circuit σ n m} (w : Signal c) :

                                            The first edge of a signal: the feed edge of its first junction.

                                            Instances For
                                              @[simp]
                                              theorem Cslib.Circuits.Frontier.Compiler.src_head {σ : Signature} {n m : ℕ} {c : Circuit σ n m} (w : Signal c) :
                                              @[simp]
                                              theorem Cslib.Circuits.Frontier.Compiler.signal_head {σ : Signature} {n m : ℕ} {c : Circuit σ n m} (w : Signal c) :
                                              (head w).signal = w
                                              theorem Cslib.Circuits.Frontier.Compiler.eq_head_of_src_eq_signal {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {e : Edge c} {w : Signal c} :
                                              src e = Vertex.signal w → e = head w

                                              An edge leaving the vertex of a signal is the first edge of that signal.

                                              An edge leaving a junction carries the signal of the junction.

                                              theorem Cslib.Circuits.Frontier.Compiler.exists_slot_of_tgt_eq_signal {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {e : Edge c} {w : Signal c} (h : tgt e = Vertex.signal w) :
                                              ∃ (a : Slot c), Wire.gate (↑a).fst = ↑w ∧ e = deliverEdge (Sum.inl a)

                                              An edge entering the vertex of a signal delivers one of the argument slots of its gate.

                                              theorem Cslib.Circuits.Frontier.Compiler.eq_outEdge_of_tgt_eq_output {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {e : Edge c} {o : Fin m} (h : tgt e = Vertex.output o) :
                                              e = outEdge c o

                                              An edge entering the vertex of an output delivers that output.

                                              The network #

                                              noncomputable def Cslib.Circuits.Frontier.Compiler.emit {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} (I : Interpretation σ U) :
                                              Signal c → (Fin n → U) → (Edge c → U) → U

                                              The value that the vertex of a signal puts on its outgoing edge: the input itself for an input wire, and the operation of the gate applied to its incoming edges for a gate wire.

                                              Instances For
                                                def Cslib.Circuits.Frontier.Compiler.Constraint {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} (I : Interpretation σ U) (Acc : Fin m → Set U) :
                                                Vertex c → (Fin n → U) → (Edge c → U) → Prop

                                                The constraint at each vertex: the vertex of a signal emits the value of the signal, a junction copies its incoming value onto its outgoing edges, and the vertex of an output requires its incoming value to be accepting.

                                                Instances For
                                                  noncomputable def Cslib.Circuits.Frontier.Compiler.site {σ : Signature} {n m : ℕ} (c : Circuit σ n m) (i : Fin n) :

                                                  Each reachable input is read at the vertex of its signal.

                                                  Instances For
                                                    theorem Cslib.Circuits.Frontier.Compiler.site_eq_some {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {i : Fin n} {v : Vertex c} (h : site c i = some v) :
                                                    ∃ (hi : Reach c (Wire.input i)), v = Vertex.signal ⟨Wire.input i, hi⟩

                                                    An input is read only at the vertex of its signal.

                                                    theorem Cslib.Circuits.Frontier.Compiler.site_of_reach {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {i : Fin n} (hi : Reach c (Wire.input i)) :

                                                    A reachable input is read at the vertex of its signal.

                                                    noncomputable def Cslib.Circuits.Frontier.Compiler.network {σ : Signature} {n m : ℕ} (c : Circuit σ n m) {U : Type u_1} (I : Interpretation σ U) (Acc : Fin m → Set U) :
                                                    Network U (Fin n) (Vertex c) (Edge c)

                                                    The constraint network of a circuit, accepting at the output o the values in Acc o.

                                                    Instances For
                                                      @[simp]
                                                      theorem Cslib.Circuits.Frontier.Compiler.network_toMultigraph {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} (I : Interpretation σ U) (Acc : Fin m → Set U) :
                                                      @[simp]
                                                      theorem Cslib.Circuits.Frontier.Compiler.network_site {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} (I : Interpretation σ U) (Acc : Fin m → Set U) :
                                                      (network c I Acc).site = site c

                                                      Exactness #

                                                      theorem Cslib.Circuits.Frontier.Compiler.satisfies_trace {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} (hx : ∀ (o : Fin m), c.eval I x o ∈ Acc o) :
                                                      (network c I Acc).Satisfies x fun (e : Edge c) => c.program.trace I x ↑e.signal

                                                      The values of the circuit satisfy the network: every edge carries the value of its signal.

                                                      theorem Cslib.Circuits.Frontier.Compiler.feed_eq_head {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α : Edge c → U} (hα : (network c I Acc).Satisfies x α) (w : Signal c) (k : ℕ) (hk : k < fanout c w) :
                                                      α (Edge.feed ⟨w, ⟨k, hk⟩⟩) = α (head w)

                                                      In a satisfying assignment, the feed edges along the chain of junctions of a signal carry the value of its first edge.

                                                      theorem Cslib.Circuits.Frontier.Compiler.eq_head {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α : Edge c → U} (hα : (network c I Acc).Satisfies x α) (e : Edge c) :
                                                      α e = α (head e.signal)

                                                      In a satisfying assignment, every edge carries the value of the first edge of its signal.

                                                      theorem Cslib.Circuits.Frontier.Compiler.head_eq_trace {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α : Edge c → U} (hα : (network c I Acc).Satisfies x α) (w : Wire n c.size) (hw : Reach c w) :
                                                      α (head ⟨w, hw⟩) = c.program.trace I x w

                                                      In a satisfying assignment, the first edge of every signal carries its value in the circuit.

                                                      theorem Cslib.Circuits.Frontier.Compiler.eq_trace {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α : Edge c → U} (hα : (network c I Acc).Satisfies x α) (e : Edge c) :
                                                      α e = c.program.trace I x ↑e.signal

                                                      Uniqueness. A satisfying assignment puts on every edge the value of its signal in the circuit.

                                                      theorem Cslib.Circuits.Frontier.Compiler.satisfies_iff {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α : Edge c → U} :
                                                      (network c I Acc).Satisfies x α ↔ (∀ (o : Fin m), c.eval I x o ∈ Acc o) ∧ α = fun (e : Edge c) => c.program.trace I x ↑e.signal

                                                      Exactness. An assignment satisfies the network exactly when every output of the circuit is accepted and the assignment puts on every edge the value of its signal in the circuit.

                                                      theorem Cslib.Circuits.Frontier.Compiler.accepted_network {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} :
                                                      (network c I Acc).accepted = {x : Fin n → U | ∀ (o : Fin m), c.eval I x o ∈ Acc o}

                                                      Exactness. The network accepts exactly the inputs on which every output o of the circuit lies in Acc o.

                                                      theorem Cslib.Circuits.Frontier.Compiler.satisfies_unique {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} {x : Fin n → U} {α β : Edge c → U} (hα : (network c I Acc).Satisfies x α) (hβ : (network c I Acc).Satisfies x β) :
                                                      α = β

                                                      Uniqueness. An input has at most one satisfying assignment.

                                                      theorem Cslib.Circuits.Frontier.Compiler.unambiguous_branchingProgram {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {Acc : Fin m → Set U} (π : Layout (Vertex c)) :

                                                      The branching program of the network along any layout is unambiguous.

                                                      Outputs across a cut #

                                                      theorem Cslib.Circuits.Frontier.Compiler.eval_splice {σ : Signature} {n m : ℕ} {c : Circuit σ n m} {U : Type u_1} {I : Interpretation σ U} {P : Set (Vertex c)} {x y z : Fin n → U} (hcut : ∀ e ∈ (graph c).edgeCut P, c.program.trace I x ↑e.signal = c.program.trace I y ↑e.signal) (hzx : Set.EqOn z x ((network c I fun (x : Fin m) => Set.univ).readIn P)) (hzy : Set.EqOn z y ((network c I fun (x : Fin m) => Set.univ).readIn P)ᶜ) (o : Fin m) :
                                                      (Vertex.output o ∈ P → c.eval I z o = c.eval I x o) ∧ (Vertex.output o ∉ P → c.eval I z o = c.eval I y o)

                                                      Outputs across a cut. In the network of a circuit computing a function, let the runs on two inputs x and y agree on the edge cut of a set of vertices P, and let z read like x at P and like y elsewhere. Then the outputs of z are those of x at the output vertices in P, and those of y at the others.