Skip to content

Use a single implementation for combine_table_entry #433

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 18, 2022

Conversation

mrmr1993
Copy link
Contributor

This PR generalises JointLookup so that it can handle SingleLookup<F>s, Fs, or Expr<ConstantExpr<F>>s as arguments, and relaxes the constraints on combine_table_entry.

This allows us to

  • store the 'dummy' lookup value as a JointLookup in the constraint system, rather than unpacking and re-packing it
    • not done here; this will be in a follow-up PR
  • unify the 3 different implementations of combine_table_entry into one
    • happily, the 'fold' implementation in combine_table_entry minimises the number of multiplications compared to the others, so this is also an efficiency gain
  • have a single point to change when we add table_ids

joint_combiner: F,
v: I,
) -> F {
v.rev().fold(F::zero(), |acc, x| joint_combiner * acc + x)
v.rev()
.fold(F::zero(), |acc, x| joint_combiner.clone() * acc + x.clone())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you add Copy instead of Clone you can remove the clone here (Field is Copy)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F is copy but Expr isn't (and we use JointCombiner rather than a field element there).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I see. My tolerance for generics is usually pretty low ^^ I'm wondering how we can make this clearer. Maybe by changing F with F_or_Expr or something. Food for thought

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then creating an actual trait F_or_Expr : Zero + One + ... and implement it on what we need

pub fn combine_table_entry<'a, F: Field, I: DoubleEndedIterator<Item = &'a F>>(
pub fn combine_table_entry<
'a,
F: 'a + Zero + One + Add + Mul + Clone,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering why F: Field + Zero here is not enough?

Also I'm wondering how I'm supposed to read F: 'a? And why it doesn't work without that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F may be a type that is defined within a function; if the scope of 'a is broader than the function, then the data outlives the type. Thus F: 'a.

joint_combiner: K,
eval: &G,
) -> K {
self.reduce(eval).evaluate(joint_combiner)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

honestly I find this function really hard to parse.

  • we have a JointLookup<SingleLookup<F>> for some F: Zero + One + Add + Mul + Clone
  • we want a K for some K: Zero + One + Add + Mul + Mul<F, Output = K> + Clone
  • in the mean time, we have some eval function that takes a LocalPosition and return a K

it's just too generic to really grasp what is really going on IMO. Is there a way to make this clearer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can just have code duplication for the different instantiations of these functions, this would make the code much clearer imo and we wouldn't need to pass a closure around (IIUC)

j.entry
.iter()
.enumerate()
.map(|(i, s)| E::constant(ConstantExpr::JointCombiner.pow(i as u64)) * single_lookup(s))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if I understand correctly this is replaced by the logic in combine_table_entry

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, yes

Copy link
Contributor

@mimoo mimoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved, but I find the generic implementation really hard to follow, I'm even wondering how I'll ever be able to change this code without keeping 10 different low-level details in my head.

@mrmr1993 mrmr1993 merged commit e1ef7ec into master Mar 18, 2022
@mrmr1993 mrmr1993 deleted the feature/joint-lookup-generalised branch March 18, 2022 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants