-
Notifications
You must be signed in to change notification settings - Fork 420
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
feat: hint name options #666
Conversation
Do I understand correctly that the named hints are essentially unnamed hints but we allow to have some additional context within a hint? But right now the implementation doesn't seem to get the context? |
All this does is that it enables the user to give a hint a name (and ID) that is not (derived from) the name of the function used to define the hint. Its motivating use is in multi-commits where there are a number of to-be-replaced hints which is not known at compile time. |
This is great, we implemented a very similar approach here vocdoni@951aa9e In my opinion, all hints should be named hints. The use of the reflect package to construct the hintID has two issues:
|
Makes sense. Also @gbotrel is imo right now working on alternative representation for hints. I think there is some overlap, but also some contradictions. There is also another open PR #659 (just FYI, not sure if affects this PR). But if we start having named hints, then does it make sense to provide I actually really like named hints because it makes clearer the separation that from circuit definition point of view the result can be "anything". Right now because we provide the implementation then a lot of people assume that the hint output is some deterministic value. Actually, I'm thinking maybe when trying to improve hints, we should have a way to pass some state data between the hints? For example, we could have hints like: func statefulHint(ctx map[any]any, mod *big.Int, inputs []*big.Int, outputs []*big.Int) error {
// hint checks if there is anything in ctx. If not, then this is first invocation.
// after it has performed the computations, this hint stores its state in ctx
// now, in the second invocation of this hint, this function sees that there already is some context here and uses it to compute the result
} |
Very much agreed @p4u @ivokub. So how about this instead: NewHint(id solver.HintID, nbOutputs int, inputs ...Variable) ([]Variable, error)
I like this idea because it might make things like commitments and the GKR widget much simpler (though @gbotrel said for the latter Blueprints would be useful, I don't understand Blueprints well enough yet.) What are your particular use-cases @ivokub? I feel a bit hesitant doing something this radical because of added complexity (both in implementation and use) but if there are many good applications perhaps we can start thinking about it seriously. |
Nope, I don't have particular application. I think it could have helped to solve the blowup in the lookup table queries, but this can also be solved using Blueprints. On a very high level a blueprint is a low-level thingie which takes some inputs and gives some outputs. But it has to figure out its serialisation on its own (it gets and returns a list of uint32 what the solver does and it has to figure out what to do with the uint32 - get some wire values etc.). As such, blueprints are a lot more performance efficient, but I think not that intuitive for the developers. |
In that case it seems best to me to use blueprints for our internal use-cases and keep the hint changes minimal. What do you think? Also what do you think of simply replacing the |
Completely agree. Lets keep the changes minimal. But I would still prefer adding a new method For |
Yes I think we can get rid of the options 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, but NewNamedHint
confuses me a bit as a name.
constraint/core.go
Outdated
if nbOutput <= 0 { | ||
return nil, fmt.Errorf("hint function must return at least one output") | ||
} | ||
|
||
// TODO @Tabaie @gbotrel consider getting rid of hint names entirely |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
names are good to derive human readable error messages if hints are missing or duplicate, etc ?
@@ -46,7 +46,8 @@ type ConstraintSystem interface { | |||
|
|||
// AddSolverHint adds a hint to the solver such that the output variables will be computed | |||
// using a call to output := f(input...) at solve time. | |||
AddSolverHint(f solver.Hint, input []LinearExpression, nbOutput int) (internalVariables []int, err error) | |||
// Providing the function f is optional. | |||
AddSolverHint(f solver.Hint, id solver.HintID, input []LinearExpression, nbOutput int) (internalVariables []int, err error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Providing the function f is optional." --> describe a bit more what happens (ie if f == nil, then ... )
frontend/builder.go
Outdated
@@ -39,6 +39,7 @@ type Compiler interface { | |||
// | |||
// If nbOutputs is specified, it must be >= 1 and <= f.NbOutputs | |||
NewHint(f solver.Hint, nbOutputs int, inputs ...Variable) ([]Variable, error) | |||
NewNamedHint(id solver.HintID, nbOutputs int, inputs ...Variable) ([]Variable, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the name of the API confuses me a bit;
it reads NewNamedHint
but takes as parameter a HintID
Essentially it says "give me nbOutputs variable, and tell the solver to computes them with a hint that'll be provided at solve time with id == id" right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essentially it says "give me nbOutputs variable, and tell the solver to computes them with a hint that'll be provided at solve time with id == id" right?
Exactly.
it reads NewNamedHint but takes as parameter a HintID
You're right about that. Open to suggestions for a better name, couldn't think of one myself. Maybe NewDeferredHint
but then again that's a bit misleading since all hints are deferred except for in test.engine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
is more of an issue thanas of now a real PR!, in that the proposed API modifications are not final and worthy of debate, but for the multi-commit feature I needed something quick and dirty that works.This "PR" enables defining a hint with a user-chosen ID. This is useful in the context of multi-commits when the number of deferred hints is not known at compile time, so no number of placeholder functions can do the job.