implement array flattening, remove bimap
This commit is contained in:
parent
8ba7611aa0
commit
c4dec182d0
6 changed files with 113 additions and 163 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -94,11 +94,6 @@ dependencies = [
|
|||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bimap"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "0.8.0"
|
||||
|
@ -1452,7 +1447,6 @@ version = "0.3.8"
|
|||
dependencies = [
|
||||
"assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)",
|
||||
"bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1559,7 +1553,6 @@ dependencies = [
|
|||
"checksum backtrace 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "1a13fc43f04daf08ab4f71e3d27e1fc27fc437d3e95ac0063a796d92fb40f39b"
|
||||
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||
"checksum bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)" = "<none>"
|
||||
"checksum bimap 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6b282b982237078bfac61a948a2198f185aceea8b9a6e794b70b96fd31923d3d"
|
||||
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
|
||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
|
|
|
@ -24,7 +24,6 @@ serde_json = "1.0"
|
|||
serde_bytes = "0.10"
|
||||
bincode = "0.8.0"
|
||||
regex = "0.2"
|
||||
bimap = "0.1"
|
||||
bellman = { git = "https://github.com/matterinc/bellman", tag = "0.2.0" }
|
||||
pairing = { git = "https://github.com/matterinc/pairing", tag = "0.16.2" }
|
||||
ff = { git = 'https://github.com/matterinc/ff', features = ["derive"], tag = "0.5" }
|
||||
|
|
|
@ -11,7 +11,6 @@ use crate::typed_absy::*;
|
|||
use crate::types::conversions::cast;
|
||||
use crate::types::Signature;
|
||||
use crate::types::Type;
|
||||
use bimap::BiMap;
|
||||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
|
@ -21,7 +20,7 @@ pub struct Flattener<'ast> {
|
|||
/// Index of the next introduced variable while processing the program.
|
||||
next_var_idx: usize,
|
||||
///
|
||||
bijection: BiMap<Identifier<'ast>, FlatVariable>,
|
||||
layout: HashMap<Identifier<'ast>, Vec<FlatVariable>>,
|
||||
}
|
||||
impl<'ast> Flattener<'ast> {
|
||||
pub fn flatten<T: Field>(p: TypedProg<T>) -> FlatProg<T> {
|
||||
|
@ -37,7 +36,7 @@ impl<'ast> Flattener<'ast> {
|
|||
fn new() -> Flattener<'ast> {
|
||||
Flattener {
|
||||
next_var_idx: 0,
|
||||
bijection: BiMap::new(),
|
||||
layout: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,7 +126,7 @@ impl<'ast> Flattener<'ast> {
|
|||
// those will be booleans in the future
|
||||
match expression {
|
||||
BooleanExpression::Identifier(x) => {
|
||||
FlatExpression::Identifier(self.bijection.get_by_left(&x).unwrap().clone())
|
||||
FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()[0])
|
||||
}
|
||||
BooleanExpression::Lt(box lhs, box rhs) => {
|
||||
// Get the bitwidth to know the size of the binary decompsitions for this Field
|
||||
|
@ -457,7 +456,7 @@ impl<'ast> Flattener<'ast> {
|
|||
// set return statements right sidreturne as expression result
|
||||
FlatStatement::Return(..) => unreachable!(),
|
||||
FlatStatement::Definition(var, rhs) => {
|
||||
let new_var = self.issue_new_variable();
|
||||
let new_var = self.issue_new_variables(1)[0];
|
||||
replacement_map.insert(var, new_var);
|
||||
let new_rhs = rhs.apply_substitution(&replacement_map);
|
||||
FlatStatement::Definition(new_var, new_rhs)
|
||||
|
@ -472,7 +471,7 @@ impl<'ast> Flattener<'ast> {
|
|||
.outputs
|
||||
.into_iter()
|
||||
.map(|o| {
|
||||
let new_o = self.issue_new_variable();
|
||||
let new_o = self.issue_new_variables(1)[0];
|
||||
replacement_map.insert(o, new_o);
|
||||
new_o
|
||||
})
|
||||
|
@ -533,7 +532,7 @@ impl<'ast> Flattener<'ast> {
|
|||
match expr {
|
||||
FieldElementExpression::Number(x) => FlatExpression::Number(x), // force to be a field element
|
||||
FieldElementExpression::Identifier(x) => {
|
||||
FlatExpression::Identifier(self.bijection.get_by_left(&x).unwrap().clone())
|
||||
FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()[0])
|
||||
}
|
||||
FieldElementExpression::Add(box left, box right) => {
|
||||
let left_flattened =
|
||||
|
@ -724,11 +723,10 @@ impl<'ast> Flattener<'ast> {
|
|||
FieldElementExpression::Number(n) => match array {
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
assert!(n < T::from(size));
|
||||
unimplemented!()
|
||||
// FlatExpression::Identifier(
|
||||
// self.get_latest_var_substitution(&format!("{}_c{}", id, n))
|
||||
// .clone(),
|
||||
// )
|
||||
FlatExpression::Identifier(
|
||||
self.layout.get(&id).unwrap().clone()
|
||||
[n.to_dec_string().parse::<usize>().unwrap()],
|
||||
)
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, expressions) => {
|
||||
assert!(n < T::from(size));
|
||||
|
@ -804,12 +802,11 @@ impl<'ast> Flattener<'ast> {
|
|||
box FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
box match array.clone() {
|
||||
FieldElementArrayExpression::Identifier(_, id) => {
|
||||
unimplemented!()
|
||||
// FieldElementExpression::Identifier(format!(
|
||||
// "{}_c{}",
|
||||
// id, i
|
||||
// ))
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(size, id),
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, expressions) => {
|
||||
assert_eq!(size, expressions.len());
|
||||
|
@ -861,17 +858,13 @@ impl<'ast> Flattener<'ast> {
|
|||
expr: FieldElementArrayExpression<'ast, T>,
|
||||
) -> Vec<FlatExpression<T>> {
|
||||
match expr {
|
||||
FieldElementArrayExpression::Identifier(size, x) => {
|
||||
unimplemented!()
|
||||
// (0..size)
|
||||
// .map(|index| {
|
||||
// FlatExpression::Identifier(
|
||||
// self.get_latest_var_substitution(&format!("{}_c{}", x, index))
|
||||
// .clone(),
|
||||
// )
|
||||
// })
|
||||
// .collect()
|
||||
}
|
||||
FieldElementArrayExpression::Identifier(_, x) => self
|
||||
.layout
|
||||
.get(&x)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|v| FlatExpression::Identifier(v.clone()))
|
||||
.collect(),
|
||||
FieldElementArrayExpression::Value(size, values) => {
|
||||
assert_eq!(size, values.len());
|
||||
values
|
||||
|
@ -962,31 +955,32 @@ impl<'ast> Flattener<'ast> {
|
|||
Type::FieldElement | Type::Boolean => {
|
||||
match assignee {
|
||||
TypedAssignee::Identifier(ref v) => {
|
||||
let debug_name = v.clone().id;
|
||||
let var = self.use_variable(&debug_name);
|
||||
let var = self.use_variable(&v)[0];
|
||||
// handle return of function call
|
||||
statements_flattened
|
||||
.push(FlatStatement::Definition(var, rhs[0].clone()));
|
||||
}
|
||||
TypedAssignee::ArrayElement(ref array, ref index) => {
|
||||
TypedAssignee::ArrayElement(box array, box index) => {
|
||||
let expr = match expr {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!("not a field element as rhs of array element update, should have been caught at semantic")
|
||||
};
|
||||
match index {
|
||||
box FieldElementExpression::Number(n) => match array {
|
||||
box TypedAssignee::Identifier(id) => {
|
||||
unimplemented!()
|
||||
// let debug_name = format!("{}_c{}", id.id, n);
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// rhs[0].clone(),
|
||||
// ));
|
||||
FieldElementExpression::Number(n) => match array {
|
||||
TypedAssignee::Identifier(id) => {
|
||||
let var = self.issue_new_variables(1);
|
||||
let variables = self.layout.get_mut(&id.id).unwrap();
|
||||
variables
|
||||
[n.to_dec_string().parse::<usize>().unwrap()] =
|
||||
var[0];
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
var[0],
|
||||
rhs[0].clone(),
|
||||
));
|
||||
}
|
||||
_ => panic!("no multidimension array for now"),
|
||||
},
|
||||
box e => {
|
||||
e => {
|
||||
// we have array[e] with e an arbitrary expression
|
||||
// first we check that e is in 0..array.len(), so we check that sum(if e == i then 1 else 0) == 1
|
||||
// here depending on the size, we could use a proper range check based on bits
|
||||
|
@ -1027,48 +1021,52 @@ impl<'ast> Flattener<'ast> {
|
|||
|
||||
// now we redefine the whole array, updating only the piece that changed
|
||||
// stat(array[i] = if e == i then `expr` else `array[i]`)
|
||||
for i in 0..size {
|
||||
let rhs = FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
let vars = match array {
|
||||
TypedAssignee::Identifier(v) => self.use_variable(&v),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let statements = vars
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, v)| {
|
||||
let rhs = FieldElementExpression::IfElse(
|
||||
box BooleanExpression::Eq(
|
||||
box e.clone(),
|
||||
box FieldElementExpression::Number(
|
||||
T::from(i),
|
||||
),
|
||||
),
|
||||
box expr.clone(),
|
||||
box e.clone(),
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
box expr.clone(),
|
||||
box e.clone(),
|
||||
);
|
||||
);
|
||||
|
||||
let rhs_flattened = self.flatten_field_expression(
|
||||
functions_flattened,
|
||||
statements_flattened,
|
||||
rhs,
|
||||
);
|
||||
let rhs_flattened = self.flatten_field_expression(
|
||||
functions_flattened,
|
||||
statements_flattened,
|
||||
rhs,
|
||||
);
|
||||
|
||||
unimplemented!()
|
||||
FlatStatement::Definition(v, rhs_flattened)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// let var =
|
||||
// self.use_variable(&format!("{}_c{}", array, i));
|
||||
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// rhs_flattened,
|
||||
// ));
|
||||
}
|
||||
statements_flattened.extend(statements);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::FieldElementArray(..) => {
|
||||
for (index, r) in rhs.into_iter().enumerate() {
|
||||
let debug_name = match assignee {
|
||||
TypedAssignee::Identifier(ref v) => format!("{}_c{}", v.id, index),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
unimplemented!()
|
||||
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(var, r));
|
||||
}
|
||||
let vars = match assignee {
|
||||
TypedAssignee::Identifier(v) => self.use_variable(&v),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
statements_flattened.extend(
|
||||
vars.into_iter()
|
||||
.zip(rhs.into_iter())
|
||||
.map(|(v, r)| FlatStatement::Definition(v, r)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1162,7 +1160,7 @@ impl<'ast> Flattener<'ast> {
|
|||
let mut current = start;
|
||||
while current < end {
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
self.use_variable(&var.id),
|
||||
self.use_variable(&var)[0],
|
||||
FlatExpression::Number(current.clone()),
|
||||
));
|
||||
for s in statements.clone() {
|
||||
|
@ -1187,36 +1185,12 @@ impl<'ast> Flattener<'ast> {
|
|||
&exprs,
|
||||
);
|
||||
|
||||
let mut iterator = rhs_flattened.expressions.into_iter();
|
||||
let rhs = rhs_flattened.expressions.into_iter();
|
||||
|
||||
// take each new variable being assigned
|
||||
for v in vars {
|
||||
// determine how many field elements it carries
|
||||
match v.get_type() {
|
||||
Type::FieldElementArray(size) => {
|
||||
for index in 0..size {
|
||||
unimplemented!()
|
||||
// let debug_name = format!("{}_c{}", v.id, index);
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// iterator.next().unwrap(),
|
||||
// ));
|
||||
}
|
||||
}
|
||||
Type::Boolean | Type::FieldElement => {
|
||||
let debug_name = v.id;
|
||||
let var = self.use_variable(&debug_name);
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
var,
|
||||
iterator.next().unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
let vars = vars.into_iter().flat_map(|v| self.use_variable(&v));
|
||||
|
||||
// we should have exhausted the return values
|
||||
assert_eq!(iterator.next(), None);
|
||||
statements_flattened
|
||||
.extend(vars.zip(rhs).map(|(v, r)| FlatStatement::Definition(v, r)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1234,7 +1208,7 @@ impl<'ast> Flattener<'ast> {
|
|||
functions_flattened: &mut Vec<FlatFunction<T>>,
|
||||
funct: TypedFunction<'ast, T>,
|
||||
) -> FlatFunction<T> {
|
||||
self.bijection = BiMap::new();
|
||||
self.layout = HashMap::new();
|
||||
|
||||
self.next_var_idx = 0;
|
||||
|
||||
|
@ -1243,31 +1217,11 @@ impl<'ast> Flattener<'ast> {
|
|||
|
||||
// push parameters
|
||||
for arg in &funct.arguments {
|
||||
let arg_type = arg.id.get_type();
|
||||
|
||||
match arg_type {
|
||||
Type::FieldElement => {
|
||||
arguments_flattened.push(FlatParameter {
|
||||
id: self.use_variable(&arg.id.id),
|
||||
private: arg.private,
|
||||
});
|
||||
}
|
||||
Type::Boolean => {
|
||||
arguments_flattened.push(FlatParameter {
|
||||
id: self.use_variable(&arg.id.id),
|
||||
private: arg.private,
|
||||
});
|
||||
}
|
||||
Type::FieldElementArray(size) => {
|
||||
for i in 0..size {
|
||||
unimplemented!()
|
||||
// arguments_flattened.push(FlatParameter {
|
||||
// id: self.use_variable(&format!("{}_c{}", arg.id.id, i)),
|
||||
// private: arg.private,
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
let variables = self.use_variable(&arg.id);
|
||||
arguments_flattened.extend(variables.into_iter().map(|v| FlatParameter {
|
||||
id: v,
|
||||
private: arg.private,
|
||||
}));
|
||||
}
|
||||
|
||||
// flatten statements in functions and apply substitution
|
||||
|
@ -1311,32 +1265,39 @@ impl<'ast> Flattener<'ast> {
|
|||
/// # Arguments
|
||||
///
|
||||
/// * `name` - a String that holds the name of the variable
|
||||
fn use_variable(&mut self, name: &Identifier<'ast>) -> FlatVariable {
|
||||
// issue the variable we'll use
|
||||
let var = self.issue_new_variable();
|
||||
fn use_variable(&mut self, variable: &Variable<'ast>) -> Vec<FlatVariable> {
|
||||
let vars = match variable.get_type() {
|
||||
Type::FieldElement => self.issue_new_variables(1),
|
||||
Type::Boolean => self.issue_new_variables(1),
|
||||
Type::FieldElementArray(size) => self.issue_new_variables(size),
|
||||
};
|
||||
|
||||
self.bijection.insert(*name, var);
|
||||
var
|
||||
self.layout.insert(variable.id, vars.clone());
|
||||
vars
|
||||
}
|
||||
|
||||
fn issue_new_variable(&mut self) -> FlatVariable {
|
||||
let var = FlatVariable::new(self.next_var_idx);
|
||||
self.next_var_idx += 1;
|
||||
var
|
||||
fn issue_new_variables(&mut self, count: usize) -> Vec<FlatVariable> {
|
||||
(0..count)
|
||||
.map(|_| {
|
||||
let var = FlatVariable::new(self.next_var_idx);
|
||||
self.next_var_idx += 1;
|
||||
var
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn use_sym(&mut self) -> FlatVariable {
|
||||
unimplemented!()
|
||||
// let name = format!("sym_{}", self.next_var_idx);
|
||||
// let var = self.issue_new_variable();
|
||||
// self.bijection.insert(&name, var);
|
||||
// self.layout.insert(&name, var);
|
||||
// var
|
||||
}
|
||||
|
||||
fn get_latest_var_substitution(&mut self, name: &Identifier<'ast>) -> FlatVariable {
|
||||
// start with the variable name
|
||||
self.bijection.get_by_left(name).unwrap().clone()
|
||||
}
|
||||
// fn get_latest_var_substitution(&mut self, name: &Identifier<'ast>) -> FlatVariable {
|
||||
// // start with the variable name
|
||||
// self.layout.get(name).unwrap().clone()
|
||||
// }
|
||||
|
||||
fn get_function<'a, T: Field>(
|
||||
&self,
|
||||
|
|
|
@ -8,7 +8,6 @@ extern crate serde_json;
|
|||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate bellman;
|
||||
extern crate bimap;
|
||||
extern crate bincode;
|
||||
extern crate ff;
|
||||
extern crate lazy_static;
|
||||
|
|
|
@ -28,9 +28,7 @@ impl<'ast, T: Field> Analyse for TypedProg<'ast, T> {
|
|||
fn analyse(self) -> Self {
|
||||
let r = PowerChecker::check(self);
|
||||
// unroll
|
||||
println!("{}", r);
|
||||
let r = Unroller::unroll(r);
|
||||
println!("{}", r);
|
||||
//propagate a first time for constants to reach function calls
|
||||
let r = Propagator::propagate(r);
|
||||
// apply inlining strategy
|
||||
|
|
|
@ -4,16 +4,16 @@ use crate::flat_absy::*;
|
|||
use crate::helpers::{DirectiveStatement, Helper};
|
||||
use crate::types::signature::Signature;
|
||||
use crate::types::Type;
|
||||
use bimap::BiMap;
|
||||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
fn use_variable(
|
||||
bijection: &mut BiMap<String, FlatVariable>,
|
||||
layout: &mut HashMap<String, FlatVariable>,
|
||||
name: String,
|
||||
index: &mut usize,
|
||||
) -> FlatVariable {
|
||||
let var = FlatVariable::new(*index);
|
||||
bijection.insert(name, var);
|
||||
layout.insert(name, var);
|
||||
*index = *index + 1;
|
||||
var
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub fn split<T: Field>() -> FlatProg<T> {
|
|||
|
||||
let mut counter = 0;
|
||||
|
||||
let mut bijection = BiMap::new();
|
||||
let mut layout = HashMap::new();
|
||||
|
||||
let arguments = vec![FlatParameter {
|
||||
id: FlatVariable::new(0),
|
||||
|
@ -33,12 +33,12 @@ pub fn split<T: Field>() -> FlatProg<T> {
|
|||
// o0, ..., o253 = ToBits(i0)
|
||||
|
||||
let directive_inputs = vec![FlatExpression::Identifier(use_variable(
|
||||
&mut bijection,
|
||||
&mut layout,
|
||||
format!("i0"),
|
||||
&mut counter,
|
||||
))];
|
||||
let directive_outputs: Vec<FlatVariable> = (0..T::get_required_bits())
|
||||
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
|
||||
.map(|index| use_variable(&mut layout, format!("o{}", index), &mut counter))
|
||||
.collect();
|
||||
|
||||
let helper = Helper::bits();
|
||||
|
@ -113,7 +113,7 @@ pub fn split<T: Field>() -> FlatProg<T> {
|
|||
pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
|
||||
let mut counter = 0;
|
||||
|
||||
let mut bijection = BiMap::new();
|
||||
let mut layout = HashMap::new();
|
||||
|
||||
let arguments = (0..from.get_primitive_count())
|
||||
.enumerate()
|
||||
|
@ -124,10 +124,10 @@ pub fn cast<T: Field>(from: &Type, to: &Type) -> FlatFunction<T> {
|
|||
.collect();
|
||||
|
||||
let binding_inputs: Vec<_> = (0..from.get_primitive_count())
|
||||
.map(|index| use_variable(&mut bijection, format!("i{}", index), &mut counter))
|
||||
.map(|index| use_variable(&mut layout, format!("i{}", index), &mut counter))
|
||||
.collect();
|
||||
let binding_outputs: Vec<FlatVariable> = (0..to.get_primitive_count())
|
||||
.map(|index| use_variable(&mut bijection, format!("o{}", index), &mut counter))
|
||||
.map(|index| use_variable(&mut layout, format!("o{}", index), &mut counter))
|
||||
.collect();
|
||||
|
||||
let outputs = binding_outputs
|
||||
|
|
Loading…
Reference in a new issue