Closed cyphersnake closed 2 months ago
I did PR #245 with the first option, I also want to point out that within the third option, the overhead is also in lookup
module, because there is also recreated Evaluator
for each line.
I like the first option as well. It makes everything simpler. data.eval(poly)
and poly.eval(data)
are essentially same. We only need one of them in this case. Since we already have graph_evaluator, it is natural to remove the old Eval trait.
The current
trait Eval
design looks like this:We have:
What we are going to evaluate the data for. Earlier it was represented as
MultiPolynomial
, now it will be represented asExpression
(which we take fromGroupedPoly
). Let's call itPoly
.Where we are going to get the data for calculation. In #159, a separate trait
GetDataForEval
was created. Let's call itData
.There is also a type that implements the logic of calculation, such as
GraphEvaluator
. It stores intermediate data for calculation. Let's call itEvaluator
.Usage
Problem 1
For some reason,
trait Eval
is implemented forData
, although it is not implied that there can be a different type of calculation for different types ofData
, since the logic (both old and new) does not depend on the way the data is fetched, but on the algorithm.Thus trait does not fulfill the task of isolating the computation algorithm, but only complicates the structure of generics. Such a design will not allow us, for example, to replace the current algorithm on the fly with another `Evalutor' and compare the efficiency.
Problem 2
The current design, when
Evalutor
instance is local, within a single row computation (inside theeval
fn), we cannot overuse the cache (the computation tree insideGraphEvalutor
), so current versions of the PR code do NOT use trait at all to compute cross-term, because otherwise we have to callGraphEvaluator::new
on every line and this will cause overhead, given the large number of lines.Decision
Refactoring
trait
in this case should perform the task of isolating a particulareval
algorithm, so should be implemented forEvaluator
rather thanData
, but that would cause a huge number of generics throughout our codebase (I tried it, it came out verbose).Refactoring and adding
fn new
and a separate implementation offn eval_all_row
that will take over the creation ofEvaluator
and reusing it will make thetrait Eval
design meaningful, however, verbose.In that case we should add generics on the
PlonkStructure
&Argument
(and all related structs) itself or its methods with no obvious benefit at this stage, due to no plans yet to even implement another algorithm evalution of expression for now.However, the latter approach will allow us to change
Evaluator
implementations on the fly in the future and make measurements on one version of the code, which is much better than the problems we encountered in the #159 implementation, where we have to make comparisons on different commits.Alternative
I suggest we take a step back and abandon this isolation at this point, given the lack of plans to implement and support multiple
Evalutors
. This will cause us to useGraphEvalutor
directly in a few places (commit_cross_term + issat*), however, the number of such places is small and we can always revert to this isolation without much refactoring.Summarize
Options:
The latter option seems terrible to me, I'm in favor of the former.