-
Notifications
You must be signed in to change notification settings - Fork 72
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
Permutation instructions/links #1126
Conversation
I tried implementing memory with it: #1129 One issue that I think should be fixed in this PR is that it seems like the selectors can't actually be used. I expect this to be a common pattern:
This currently gives me |
I think they are missing from |
6e5adde
to
c3f5aba
Compare
9884947
to
299b37b
Compare
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.
Hmm, I think the approach of completely hiding the selectors from the user introduces some issues:
- I re-based my memory PR onto this branch and now I have this issue. Basically, I need access to the
used
flag in the constraints. - As mentioned in the comment below, I think the current way to keep selectors constant in the block fails if the latch is in the first row.
I'm not sure what the best abstraction is. My original proposal (just adding the selectors, maybe bit-constrain them, but no other magic) wouldn't have these issues and instead require the user to figure this out for their machine. I wonder if at this point that is the better approach until we know the patterns and figured out an abstraction that is flexible enough to cover all use-cases...
pipeline/tests/asm.rs
Outdated
#[should_panic = "Witness generation failed"] | ||
fn permutations_to_block_to_block() { | ||
// TODO: witgen issue | ||
let f = "asm/permutations_block_to_block.asm"; |
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.
If I understand this right, the issue here is not the block-to-block think (which would be good to test!) But that a machine of block size 1 does not get recognized as a block machine. If the first machine had a block size > 1 it should work! I think it would be good testing this, because it makes sure that the calls to the second machine are masked out in the dummy blocks of the first!
link 1 ~> bin.or A, B -> X; | ||
link 1 ~> bin.or C, D -> Y; | ||
link 1 ~> bin.or X, Y -> E; | ||
|
||
col fixed operation_id = [0]*; | ||
col fixed latch = [1]*; |
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.
link 1 ~> bin.or A, B -> X; | |
link 1 ~> bin.or C, D -> Y; | |
link 1 ~> bin.or X, Y -> E; | |
col fixed operation_id = [0]*; | |
col fixed latch = [1]*; | |
link latch ~> bin.or A, B -> X; | |
link latch ~> bin.or C, D -> Y; | |
link latch ~> bin.or X, Y -> E; | |
col fixed operation_id = [0]*; | |
// TODO: Currently, witgen fails if we set the latch to [1]*, because then the machine | |
// does not get detected as a block machine and connecting VMs via permutations is not supported | |
// yet. By setting the latch to [0, 1]*, the first row of every block is completely unconstrained. | |
col fixed latch = [0, 1]*; |
This seems to work!
The problem with the original example is not the block-to-block construction but that this machine does not have a latch (it gets optimized away). Feel free to keep the original file as a failing test, but I think it would be good to test the block-to-block case, because it tests that calls to Binary
get masked out in the dummy blocks of Binary4
!
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.
Alright then we're hitting other bugs ^^
It works though if we have a strict 1-to-1 mappings (Main has 1 link to Binary4, which has 1 link to Binary). LMK if I should give it a shot to come up with a simple-enough-but not dumb example!
airgen/src/lib.rs
Outdated
]); | ||
if let Some(latch) = &obj.latch { | ||
obj.pil.push(parse_pil_statement(&format!( | ||
"std::array::map({LINK_SELECTOR_NAME}, |s| std::utils::unchanged_until(s, {latch}));" |
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.
Ah, I think this would be a problem if the latch is in the first row instead of the last :/
I think in that case it should be:
std::utils::unchanged_until(s, {latch}'));
(note the '
!)
Can we detect this? I guess not easily because we haven't evaluated the fixed columns yet?
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.
I think Poseidon is a good test case for this. We could eventually change mos of our tests to use permutations instead of lookups.
I tried implementing this suggestion and testing with the Poseidon machine. I ran into more witgen issues which are fixed here: #1157
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.
I think we can't, were still producing pil at this point
airgen/src/lib.rs
Outdated
for (location, count) in incoming_permutations { | ||
let obj = objects.get_mut(&location).unwrap(); | ||
if count > 0 { | ||
// TODO: only block machines actually need a used flag to |
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.
Is this true? What if a VM calls another machine via a permutation?
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 used
flag is only used to filter out dummy blocks in the caller, and those (AFAIU) are not an issue in VMs, no?
But in any case, we don't know that here, so we add used
anyways.
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.
Ah, right, true!
For the issue of accessing the selectors, is accessing the used flag directly (i.e., sum of selectors) instead of the selector array enough?
What do you think? I kinda like the second option |
Not to fix the |
3293b4b
to
b64857b
Compare
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.
I just tested this by rebasing my memory PR (#1129) onto it and also trying to change the Poseidon machine so that it can be used via a lookup and permutation (by adding the call_selectors
statement).
I ran into witgen issues with the selector[0]
(reserved for lookups):
- If I have the
call_selectors
statement, lookups compile to a selector ofLATCH * selectors[0]
, in which case witgen doesn't detect the machine during witgen. - If the machine is connected only via permutation, we have an extra column
selectors[0]
which is never used. This also breaks machine detection for the memory machine.
Both of these could be fixed in witgen, but I'm not sure if there is need for this extra selector. It is not needed for the lookup argument, and just to pass a bit that is guaranteed to be 1 for any "real" call, we could also add an argument to the operation, as discussed in the chat.
pipeline/tests/asm.rs
Outdated
#[test] | ||
#[should_panic = "has outgoing permutations but doesn't declare call_selectors"] | ||
fn permutation_outgoing_needs_selector() { | ||
// TODO: witgen issue |
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.
// TODO: witgen issue |
pipeline/tests/asm.rs
Outdated
#[test] | ||
#[should_panic = "has incoming permutations but doesn't declare call_selectors"] | ||
fn permutation_incoming_needs_selector() { | ||
// TODO: witgen issue |
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.
// TODO: witgen issue |
instr or_into_C X, Y = bin.or X, Y -> C; | ||
|
||
// permutation to machine bin4 | ||
instr or4 X, Y, Z, W -> R = bin4.or4; |
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.
These are lookups, no?
call_selectors sel; | ||
|
||
// permutation links to Binary machine | ||
link 1 ~> bin.or A, B -> X; |
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.
link 1 ~> bin.or A, B -> X; | |
link array::sum(sel) ~> bin.or A, B -> X; |
No? Also, the sum of selectors needs to be constrained to be binary then I think.
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.
I've updated the example. I think the constraint force_bool(sum(sel))
could also be auto inserted by the compiler, but from our discussions I left it up to the user to add it to the asm
.
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.
Great! With this and some other recently merged PRs, the memory machine is now working (#1129)! 🎉
I also tried adding call_selectors sel;
to a bunch of machines in the standard library, so now we can use them both via a permutation and lookup. Probably, we should do that in a follow-up and also connect machines via permutations in the RISC-V machine!
As another follow-up, I think we need to update the book, right?
by instructions and links using `~` instead of `=`. Block machines must declare `call_selectors`.
09a1651
to
edaf536
Compare
Allow
asm
machines to be linked by permutation arguments.The syntax is the same as for lookups, but uses a
~
(tilde) instead of=
.This PR is written in a way that there's no change to existing asm/pil code and tests, and so witgen support can be implemented separately