Part A: 1/4
First compute the error :
The check misses exactly when . Row 0 gives and row 1 gives .
Of the 8 vectors in , two satisfy both: and . The miss
probability is . The two errors in row 0 can cancel each other, which an error
in a single entry cannot.
Part B: 1/10
Take a nonzero row of , and an index with . Fix every entry of except
. Then holds for at most one value of , so for at most 1 of its 10
values. The check misses with probability at most , and a single wrong entry reaches that
bound: with one 1 misses exactly when that column's .
The same argument for any finite set of values gives a miss probability of at most
. This is the Schwartz–Zippel lemma for a polynomial of degree 1: a nonzero
polynomial of degree vanishes at a random point of with probability at most .
Part C: one check with a wide range
So the range is what matters, not the number of checks. The solution takes one vector with
entries below :
def audit(n, times_A, times_B, times_C, rand):
r = [rand(2**64) for _ in range(n)]
return times_A(times_B(r)) == times_C(r)
That is three products and a miss probability of at most . Python's integers are exact,
so the entries' size costs nothing in correctness. Two checks with entries below also
pass.
What the grader catches:
- The 0/1 vector, twice. Each check misses a single wrong entry half the time, so two miss it
a quarter of the time, and over hundreds of audits some slip through.
- Entries 0 to 9, twice. A miss chance of per audit: over 300 audits, some miss.
- A fixed vector. All ones misses an error whose row sums to zero. misses
with the row . No fixed vector works, because the wrong may be
chosen after the vector is known.
- Arithmetic modulo a famous prime. Comparing modulo cannot see an error equal to
. A prime chosen at random at audit time would be fine.
- Multiplying out column by column is exact but needs products of each kind.
Going further
- Polynomial identity testing is the general form: decide whether a polynomial, given as a
circuit, is identically zero. Schwartz–Zippel makes it easy with randomness. No deterministic
polynomial-time algorithm is known, and finding one would prove circuit lower bounds
(Kabanets and Impagliazzo).
- Perfect matchings. A graph has one exactly when the determinant of its Tutte matrix, with
random values substituted, is nonzero (with high probability). This leads to parallel
matching algorithms (Mulmuley, Vazirani and Vazirani).
- Checking a product of polynomials : evaluate all three at one random point.
This is the simplest use of the same idea, and it sits behind fingerprinting
(Fingerprinting and String Matching).
References
- R. Freivalds. Probabilistic machines can use less running time. IFIP Congress, 1977.
- J. T. Schwartz. Fast probabilistic algorithms for verification of polynomial identities.
Journal of the ACM 27(4), 1980.
- R. Zippel. Probabilistic algorithms for sparse polynomials. EUROSAM, 1979.
- K. Mulmuley, U. V. Vazirani, V. V. Vazirani. Matching is as easy as matrix inversion.
Combinatorica 7(1), 1987.
- V. Kabanets, R. Impagliazzo. Derandomizing polynomial identity tests means proving circuit
lower bounds. Computational Complexity 13, 2004.