Circuit complexity #
The complexity of a function f on a support S, written C^S(f), is the least number of gates
in a circuit whose outputs agree with f on every input in S. The function may have several
values, one for each output of the circuit, and nothing is asked of the circuit outside S, so
C^S(f) depends only on the restriction of f to S. The complexity C(f) of f is its
complexity on all inputs, and the complexity of f relative to a function g, in
Cslib.Computability.Circuit.RelativeComplexity, is a complexity on the graph of g.
Over an arbitrary signature and interpretation some functions have no circuit at all. We represent
C^S(f) by ecomplexityOn I S f and C(f) by ecomplexity I f, taking values in ℕ∞ with
⊤ when no circuit exists. The prefix e stands for "extended". Over a complete basis, one over
which every function has a circuit, complexityOn I S f and complexity I f give the corresponding
natural-number values.
Support complexity obeys a small calculus from which the rules for complexity and relative
complexity follow. It grows with the support and ignores the function outside the support.
Wiring, which only selects, permutes, or duplicates inputs, costs nothing. The composite g ∘ f
costs at most the complexity of f on S plus that of g on the image of S, and computing two
functions side by side costs at most the sum of their complexities.
See [Jukna, Chapter 1][Jukna2012] for the Boolean case.
References #
- [Stasys Jukna, Boolean Function Complexity: Advances and Frontiers][Jukna2012]
Following [Jukna, Section 1.1][Jukna2012], a basis is complete when every single-valued function, on every number of inputs, is computed by some circuit over it. Circuits here have no constant inputs, so this includes the constants, which is why NAND alone is not complete in this sense. Functions with several values then have circuits too, built by running circuits for their values side by side.
- exists_computes_single {n : ℕ} (f : (Fin n → U) → U) : ∃ (c : Circuit σ n 1), c.Computes I (single f)
Every single-valued function has a circuit.
Instances
Over a complete basis every function, with any number of values, has a circuit.
The complexity C^S(f) of f on the support S: the least size of a circuit computing f
on S under I, or ⊤ if there is none.
Equations
- Cslib.Circuits.ecomplexityOn I S f = ⨅ (c : { c : Cslib.Circuits.Circuit σ n m // c.ComputesOn I S f }), ↑(↑c).size
Instances For
The complexity C(f) of f: its complexity on all inputs.
Equations
Instances For
Complexity on a support #
When some circuit computes f on S, the least size is attained by some
(potentially different) circuit.
Lower bounds on support complexity are exactly lower bounds on the size of every circuit computing the function on the support, including when no such circuit exists.
A larger support is harder to compute on.
Complexity on a support depends only on the values of the function on the support.
Selecting, permuting, or duplicating inputs costs nothing.
The composition rule: computing g ∘ f on S costs at most computing f on S and then
g on the values f takes there.
The pairing rule: computing f and g side by side on S costs at most the sum of their
complexities on S.
Reading the inputs through a wiring costs nothing beyond computing f on the rewired
support.
Complexity on all inputs #
When some circuit computes f, the least size is attained by some (potentially different)
circuit.
Lower bounds on complexity are exactly lower bounds on the size of every circuit computing the function, including when no such circuit exists.
Selecting, permuting, or duplicating inputs costs nothing.
Computing f alongside g is at least as hard as computing f.
Computing g alongside f is at least as hard as computing g.
Over a complete basis #
The complexity C^S(f) of f on the support S over a complete basis, as a natural
number.
Equations
- Cslib.Circuits.complexityOn I S f = WithTop.untop (Cslib.Circuits.ecomplexityOn I S f) ⋯
Instances For
The complexity C(f) of f over a complete basis, as a natural number.
Equations
Instances For
A circuit computing f on S bounds its support complexity.
Over a complete basis the least size on a support is attained.
Support complexity is at most k exactly when some circuit of size at most k computes
the function on the support.
Over a complete basis, lower bounds on support complexity are exactly lower bounds on the size of every circuit computing the function on the support.
A lower bound on the complexity is a lower bound on the size of every circuit.
Over a complete basis the least size is attained.
Over a complete basis, lower bounds on complexity are exactly lower bounds on the size of every circuit.
Complexity on a support depends only on the values of the function on the support.
Restricting the inputs to a support cannot increase complexity.
Selecting, permuting, or duplicating inputs costs nothing.
Computing f alongside g on S is at least as hard as computing f on S.
Computing g alongside f on S is at least as hard as computing g on S.
Selecting, permuting, or duplicating inputs costs nothing.
Computing a composite costs at most the sum of the complexities of its two functions.
Computing two functions side by side costs at most the sum of their complexities.
Computing f alongside g is at least as hard as computing f.
Computing g alongside f is at least as hard as computing g.
A synthesis bound on the input projections bounds the complexity.