Skip to content
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: cache lookup blueprint entries in solving phase #915

Merged
merged 2 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions constraint/bls12-377/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/bls12-381/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/bls24-315/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/bls24-317/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions constraint/blueprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ type BlueprintHint interface {
DecompressHint(h *HintMapping, instruction Instruction)
}

// BlueprintStateful indicates that the blueprint can be reset to its initial state.
type BlueprintStateful interface {
BlueprintSolvable

// Reset is called by the solver between invocation of Solve.
Reset()
}

// Compressible represent an object that knows how to encode itself as a []uint32.
type Compressible interface {
// Compress interprets the objects as a LinearExpression and encodes it as a []uint32.
Expand Down
49 changes: 39 additions & 10 deletions constraint/blueprint_logderivlookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package constraint

import (
"fmt"
"sync"
)

// TODO @gbotrel this shouldn't be there, but we need to figure out a clean way to serialize
Expand All @@ -16,28 +17,41 @@ type BlueprintLookupHint struct {
maxLevel Level
maxLevelPosition int
maxLevelOffset int

// cache the resolved entries by the solver
cachedEntries []Element
cachedOffset int
lock sync.Mutex
}

// ensures BlueprintLookupHint implements the BlueprintSolvable interface
var _ BlueprintSolvable = (*BlueprintLookupHint)(nil)
// ensures BlueprintLookupHint implements the BlueprintStateful interface
var _ BlueprintStateful = (*BlueprintLookupHint)(nil)

func (b *BlueprintLookupHint) Solve(s Solver, inst Instruction) error {
nbEntries := int(inst.Calldata[1])
entries := make([]Element, nbEntries)

// read the static entries from the blueprint
// TODO @gbotrel cache that.
offset, delta := 0, 0
for i := 0; i < nbEntries; i++ {
entries[i], delta = s.Read(b.EntriesCalldata[offset:])
offset += delta
// check if we already cached the entries
b.lock.Lock()
if len(b.cachedEntries) < nbEntries {
// we need to cache more entries
offset, delta := b.cachedOffset, 0
for i := len(b.cachedEntries); i < nbEntries; i++ {
b.cachedEntries = append(b.cachedEntries, Element{})
b.cachedEntries[i], delta = s.Read(b.EntriesCalldata[offset:])
offset += delta
}
b.cachedOffset = offset
}
b.lock.Unlock()

// we only append to the entries and never resize the slice; so we can access these indices safely
entries := b.cachedEntries[:nbEntries]

nbInputs := int(inst.Calldata[2])

// read the inputs from the instruction
inputs := make([]Element, nbInputs)
offset = 3
offset, delta := 3, 0
gbotrel marked this conversation as resolved.
Show resolved Hide resolved
for i := 0; i < nbInputs; i++ {
inputs[i], delta = s.Read(inst.Calldata[offset:])
offset += delta
Expand All @@ -57,6 +71,21 @@ func (b *BlueprintLookupHint) Solve(s Solver, inst Instruction) error {
return nil
}

func (b *BlueprintLookupHint) Reset() {
// first we need to compute the capacity; that is 1 element per linear expression in the entries.
// this must be accurate since solver is multi threaded and we don't want to resize the slice
// while the solver is running.
capacity := 0
for i := 0; i < len(b.EntriesCalldata); i++ {
n := int(b.EntriesCalldata[i]) // length of the linear expression
capacity++
i += 2 * n // skip the linear expression
}

b.cachedEntries = make([]Element, 0, capacity)
b.cachedOffset = 0
}

func (b *BlueprintLookupHint) CalldataSize() int {
// variable size
return -1
Expand Down
7 changes: 7 additions & 0 deletions constraint/bn254/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/bw6-633/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/bw6-761/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions constraint/tinyfield/system.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ func (cs *system) Solve(witness witness.Witness, opts ...csolver.Option) (any, e
return nil, err
}

// reset the stateful blueprints
for i := range cs.Blueprints {
if b, ok := cs.Blueprints[i].(constraint.BlueprintStateful); ok {
b.Reset()
}
}

// defer log printing once all solver.values are computed
// (or sooner, if a constraint is not satisfied)
defer solver.printLogs(cs.Logs)
Expand Down
8 changes: 8 additions & 0 deletions test/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ func IsSolved(circuit, witness frontend.Circuit, field *big.Int, opts ...TestEng
log := logger.Logger()
log.Debug().Msg("running circuit in test engine")
cptAdd, cptMul, cptSub, cptToBinary, cptFromBinary, cptAssertIsEqual = 0, 0, 0, 0, 0, 0

// first we reset the stateful blueprints
for i := range e.blueprints {
if b, ok := e.blueprints[i].(constraint.BlueprintStateful); ok {
b.Reset()
}
}

if err = c.Define(e); err != nil {
return fmt.Errorf("define: %w", err)
}
Expand Down