From 93ad6765867c0ca5204a3cd976fe931555fc8c1a Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 16 Oct 2024 22:50:32 +0200 Subject: [PATCH 01/22] working on improving tags --- compiler/src/circuit_design/build.rs | 2 +- compiler/src/hir/very_concrete_program.rs | 4 +- .../intermediate_representation/translate.rs | 32 +- constraint_generation/src/assignment_utils.rs | 29 +- .../environment_utils/bus_representation.rs | 351 ++-------- .../component_representation.rs | 371 +++++++---- .../src/environment_utils/environment.rs | 106 ++- .../src/environment_utils/slice_types.rs | 14 +- constraint_generation/src/execute.rs | 624 ++++++++++-------- .../src/execution_data/executed_bus.rs | 24 +- .../src/execution_data/executed_program.rs | 2 +- .../src/execution_data/executed_template.rs | 68 +- .../src/execution_data/mod.rs | 2 +- .../src/execution_data/type_definitions.rs | 17 +- 14 files changed, 888 insertions(+), 758 deletions(-) diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 6e1fe401b..4f7c57366 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -162,7 +162,7 @@ fn build_function_instances( component_to_parallel: HashMap::with_capacity(0), template_database: &c_info.template_database, string_table : string_table, - signals_to_tags: BTreeMap::new(), + signals_to_tags: HashMap::new(), buses: &c_info.buses }; let mut function_info = FunctionCodeInfo { diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 811aea53f..56808e8ae 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -196,7 +196,7 @@ pub struct TemplateInstance { pub number_of_outputs: usize, pub number_of_intermediates: usize, pub wires: Vec, - pub signals_to_tags: BTreeMap, + pub signals_to_tags: HashMap, BigInt>, pub components: Vec, pub number_of_components: usize, pub triggers: Vec, @@ -216,7 +216,7 @@ pub struct TemplateConfig { pub clusters: Vec, pub components: Vec, pub arguments: Vec, - pub signals_to_tags: BTreeMap, + pub signals_to_tags: HashMap, BigInt>, } impl TemplateInstance { pub fn new(config: TemplateConfig) -> TemplateInstance { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 0860a1659..c195c5a34 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -124,7 +124,7 @@ struct State { component_to_parallel: HashMap, component_to_instance: HashMap>, signal_to_type: HashMap, - signal_to_tags: BTreeMap, + signal_to_tags: HashMap, BigInt>, message_id: usize, signal_stack: usize, variable_stack: usize, @@ -142,7 +142,7 @@ impl State { cmp_id_offset: usize, field_tracker: FieldTracker, component_to_parallel: HashMap, - signal_to_tags: BTreeMap + signal_to_tags: HashMap, BigInt> ) -> State { State { field_tracker, @@ -857,26 +857,26 @@ fn check_tag_access(name_signal: &String, access: &Vec, state: &mut Stat use Access::*; let symbol_info = state.environment.get_variable(name_signal).unwrap().clone(); - let mut value_tag = None; - // TODO: case tags of buses -> future work - if !symbol_info.is_component && !symbol_info.is_bus{ + let mut complete_access = vec![name_signal.clone()]; + if !symbol_info.is_component{ for acc in access { match acc { - ArrayAccess(..) => {}, + ArrayAccess(..) => {return None}, ComponentAccess(name) => { - let tags_signal = state.signal_to_tags.get(name_signal).unwrap(); - let value = tags_signal.get(name).unwrap(); - - value_tag = if value.is_some() { - Some(value.clone().unwrap()) - } else { - unreachable!() - }; + complete_access.push(name.clone()); } } } + if state.signal_to_tags.contains_key(&complete_access){ + let value = state.signal_to_tags.get(&complete_access).unwrap(); + Some(value.clone()) + } else{ + None + } + } else{ + None } - value_tag + } fn translate_variable( @@ -1861,7 +1861,7 @@ pub struct CodeInfo<'a> { pub field_tracker: FieldTracker, pub component_to_parallel: HashMap, pub string_table: HashMap, - pub signals_to_tags: BTreeMap, + pub signals_to_tags: HashMap, BigInt>, pub buses: &'a Vec } diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index dd886ac47..e0f43f094 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -2,14 +2,26 @@ use super::environment_utils:: slice_types::{MemoryError, TypeAssignmentError, SignalSlice, SliceCapacity, TagInfo, TagState, TagDefinitions, - BusSlice + BusSlice, BusTagInfo }; - +use crate::execution_data::type_definitions::TagWire; use std::mem; - +use std::collections::HashMap; // Utils for assigning tags +pub fn compute_propagated_tags_bus(tag_data: &BusTagInfo) -> TagWire{ + let tags_propagated = compute_propagated_tags(&tag_data.tags, &tag_data.definitions); + let mut fields_propagated = HashMap::new(); + for (field_name, field_tags) in &tag_data.fields{ + fields_propagated.insert(field_name.clone(), compute_propagated_tags_bus(field_tags)); + } + TagWire{ + tags: tags_propagated, + fields: Some(fields_propagated), + } +} + pub fn compute_propagated_tags(tags_values: &TagInfo, tags_definitions: &TagDefinitions)-> TagInfo{ let mut tags_propagated = TagInfo::new(); for (tag, value) in tags_values{ @@ -106,6 +118,17 @@ pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut } +pub fn perform_tag_propagation_bus(tag_data: &mut BusTagInfo, assigned_tags: &TagWire, n_inserts: usize){ + perform_tag_propagation(&mut tag_data.tags, &mut tag_data.definitions, &assigned_tags.tags, tag_data.is_init); + tag_data.remaining_inserts -= n_inserts; + for (field_name, field_data) in &mut tag_data.fields{ + let aux = assigned_tags.fields.as_ref().unwrap(); + let field_assigned = aux.get(field_name).unwrap(); + let field_n_inserts = field_data.size * n_inserts; + perform_tag_propagation_bus(field_data, field_assigned, field_n_inserts); + } +} + pub fn perform_signal_assignment(signal_slice: &mut SignalSlice, array_access: &[SliceCapacity], new_route: &[SliceCapacity])-> Result<(), MemoryError>{ let memory_response_for_signal_previous_value = SignalSlice::access_values( diff --git a/constraint_generation/src/environment_utils/bus_representation.rs b/constraint_generation/src/environment_utils/bus_representation.rs index 502ecaa86..dd9d5b512 100644 --- a/constraint_generation/src/environment_utils/bus_representation.rs +++ b/constraint_generation/src/environment_utils/bus_representation.rs @@ -1,5 +1,5 @@ -use super::slice_types::{BusSlice, FieldTypes, FoldedArgument, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TagDefinitions, TagInfo, TagState, TypeAssignmentError}; +use super::slice_types::{BusSlice, FieldTypes, FoldedArgument, FoldedResult, MemoryError, SignalSlice, SliceCapacity, TypeAssignmentError}; use crate::execution_data::type_definitions::{NodePointer, AccessingInformationBus}; use crate::execution_data::ExecutedProgram; use std::collections::{BTreeMap,HashMap}; @@ -11,7 +11,6 @@ pub struct BusRepresentation { pub node_pointer: Option, pub meta: Option, fields: BTreeMap, - pub field_tags: BTreeMap, unassigned_fields: HashMap, has_assignment: bool, } @@ -21,7 +20,6 @@ impl Default for BusRepresentation { BusRepresentation { node_pointer: Option::None, fields: BTreeMap::new(), - field_tags: BTreeMap::new(), meta: Option::None, unassigned_fields: HashMap::new(), has_assignment: false @@ -33,7 +31,6 @@ impl Clone for BusRepresentation { BusRepresentation { node_pointer: self.node_pointer, fields: self.fields.clone(), - field_tags: self.field_tags.clone(), meta : self.meta.clone(), unassigned_fields: self.unassigned_fields.clone(), has_assignment: self.has_assignment @@ -91,23 +88,7 @@ impl BusRepresentation { let field_bus = FieldTypes::Bus(bus_slice); component.fields.insert(symbol.clone(), field_bus); } - - - // add the tags - if node.signal_to_tags.get(symbol).is_some(){ - let defined_tags = node.signal_to_tags.get(symbol).unwrap(); - let mut definitions = BTreeMap::new(); - let mut values = BTreeMap::new(); - for (tag, value) in defined_tags{ - let tag_state = TagState{defined:true, value_defined: value.is_some(), complete: true}; - definitions.insert(tag.clone(), tag_state); - values.insert(tag.clone(), value.clone()); - - } - component.field_tags.insert(symbol.clone(), (definitions, values)); - } else{ - component.field_tags.insert(symbol.clone(), (BTreeMap::new(), BTreeMap::new())); - } + if is_initialized{ component.unassigned_fields.remove(symbol); } @@ -124,61 +105,35 @@ impl BusRepresentation { &self, field_name: &str, remaining_access: &AccessingInformationBus - ) -> Result<(Option, FoldedResult), MemoryError>{ + ) -> Result{ let field = self.fields.get(field_name).unwrap(); - let (tags_defs, tags_info) = self.field_tags.get(field_name).unwrap(); if remaining_access.field_access.is_some(){ - // we are still considering an intermediate bus or a tag, check cases - let next_access = remaining_access.field_access.as_ref().unwrap(); - if tags_info.contains_key(next_access){ - // case tag, return its value - - // access only allowed when (1) it is value defined by user or (2) it is completely assigned - let state = tags_defs.get(next_access).unwrap(); - if state.value_defined || state.complete{ - let value_tag = tags_info.get(next_access).unwrap(); - match value_tag{ - Option::None =>{ - let error = MemoryError::TagValueNotInitializedAccess; - Result::Err(error) - }, - Some(v) =>{ - let folded_tag = FoldedResult::Tag(v.clone()); - Result::Ok((None, folded_tag)) - } - } - } else{ - let error = MemoryError::TagValueNotInitializedAccess; - Result::Err(error) - } - } else{ - // case bus, access to the next field - match field{ - FieldTypes::Bus(bus_slice)=>{ + // we are still considering an intermediate bus, check cases + match field{ + FieldTypes::Bus(bus_slice)=>{ - let memory_response = BusSlice::access_values_by_reference( - &bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(bus_slice) =>{ - assert!(bus_slice.len() == 1); - let resulting_bus = bus_slice[0]; - resulting_bus.get_field( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap() - ) - } - Result::Err(err)=>{ - return Err(err); - } + let memory_response = BusSlice::access_values_by_reference( + &bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice[0]; + resulting_bus.get_field( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap() + ) + } + Result::Err(err)=>{ + return Err(err); } } - FieldTypes::Signal(_) => unreachable!(), } + FieldTypes::Signal(_) => unreachable!(), } - + } else{ // in this case there is no need for recursion, final access @@ -186,15 +141,12 @@ impl BusRepresentation { FieldTypes::Signal(signal_slice) =>{ // Case it is just a signal or an array of signals, // in this case there is no need for recursion - - // compute which tags are propagated - let propagated_tags = compute_propagated_tags(tags_info, tags_defs); - + let accessed_slice_result = SignalSlice::access_values(&signal_slice, &remaining_access.array_access); match accessed_slice_result{ Ok(slice) =>{ let folded_slice = FoldedResult::Signal(slice); - Result::Ok((Some(propagated_tags), folded_slice)) + Result::Ok(folded_slice) }, Err(err) => Err(err) } @@ -202,15 +154,12 @@ impl BusRepresentation { FieldTypes::Bus(bus_slice) => { // Case it is just a bus or an array of buses, // in this case there is no need for recursion - - // compute which tags are propagated - let propagated_tags = compute_propagated_tags(tags_info, tags_defs); let accessed_slice_result = BusSlice::access_values(&bus_slice, &remaining_access.array_access); match accessed_slice_result{ Ok(slice) =>{ let folded_slice = FoldedResult::Bus(slice); - Result::Ok((Some(propagated_tags), folded_slice)) + Result::Ok( folded_slice) }, Err(err) => Err(err) } @@ -230,7 +179,6 @@ impl BusRepresentation { field_name: &str, remaining_access: &AccessingInformationBus, assigned_value: FoldedArgument, - tags: Option, is_input: bool, ) -> Result<(), MemoryError> { // TODO: move to auxiliar function to do not repeat effort @@ -245,169 +193,67 @@ impl BusRepresentation { let total_size = route.iter().fold(1, |acc, x| acc * x); total_size > 0 }, - FoldedArgument::Tag(_) => false }; if has_assignment{ self.has_assignment = true; } - // We later distinguish the case of tags // check if we need to access to another bus or if it is the final access let field: &mut FieldTypes = self.fields.get_mut(field_name).unwrap(); - let (status_tags, info_tags) = self.field_tags.get_mut(field_name).unwrap(); if remaining_access.field_access.is_some(){ - // case still intermediate access or a tag - let next_access = remaining_access.field_access.as_ref().unwrap(); - - // Distinguish between tag and intermediate access - if info_tags.contains_key(next_access){ - - // it is tag assignment -> check if valid - match field{ - FieldTypes::Signal(s) =>{ - let signal_is_init = SignalSlice::get_number_of_inserts(&s) > 0; - if signal_is_init{ - return Result::Err(MemoryError::AssignmentTagAfterInit) - } - } - FieldTypes::Bus(s) =>{ - for i in 0..BusSlice::get_number_of_cells(s){ - let accessed_bus = BusSlice::get_reference_to_single_value_by_index(&s, i)?; - if accessed_bus.has_assignment(){ - return Result::Err(MemoryError::AssignmentTagAfterInit) - } - } - } - } - // Get the assigned value - let value = match assigned_value{ - FoldedArgument::Tag(value) =>{ - value - }, - _ => unreachable!() - }; - - let possible_tag = info_tags.get_mut(next_access); - if let Some(val) = possible_tag { - if let Some(_) = val { - // already assigned value, return error - Result::Err(MemoryError::AssignmentTagTwice) - } else { // we add the info saying that the tag is defined - let tag_state = status_tags.get_mut(next_access).unwrap(); - tag_state.value_defined = true; - *val = Option::Some(value.clone()); - Result::Ok(()) - } - } else{ - unreachable!() - } - } else{ - // it is intermediate access - - match field{ - FieldTypes::Bus(bus_slice)=>{ - // case bus -> apply recursion - - // no tags assigned to the complete bus - // Check in case input if it is expecting tags, if so return error - if is_input{ - if !info_tags.is_empty(){ - let (possible_tag, _) = info_tags.iter().next().unwrap(); - return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), possible_tag.clone())); - } - } + // case still intermediate access + match field{ + FieldTypes::Bus(bus_slice)=>{ + // case bus -> apply recursion - let memory_response = BusSlice::access_values_by_mut_reference( - bus_slice, - &remaining_access.array_access - ); - match memory_response{ - Result::Ok(mut bus_slice) =>{ - assert!(bus_slice.len() == 1); - let resulting_bus = bus_slice.get_mut(0).unwrap(); - resulting_bus.assign_value_to_field( - remaining_access.field_access.as_ref().unwrap(), - &remaining_access.remaining_access.as_ref().unwrap(), - assigned_value, - tags, - is_input - )?; - - // Update from unassigned if it is completely assigned - if !resulting_bus.has_unassigned_fields(){ - match self.unassigned_fields.get_mut(field_name){ - Some(left) => { - *left -= 1; - if *left == 0 { - self.unassigned_fields.remove(field_name); - } + let memory_response = BusSlice::access_values_by_mut_reference( + bus_slice, + &remaining_access.array_access + ); + match memory_response{ + Result::Ok(mut bus_slice) =>{ + assert!(bus_slice.len() == 1); + let resulting_bus = bus_slice.get_mut(0).unwrap(); + resulting_bus.assign_value_to_field( + remaining_access.field_access.as_ref().unwrap(), + &remaining_access.remaining_access.as_ref().unwrap(), + assigned_value, + is_input + )?; + + // Update from unassigned if it is completely assigned + if !resulting_bus.has_unassigned_fields(){ + match self.unassigned_fields.get_mut(field_name){ + Some(left) => { + *left -= 1; + if *left == 0 { + self.unassigned_fields.remove(field_name); } - Option::None => {} } + Option::None => {} } - Result::Ok(()) - } - Result::Err(err)=>{ - return Err(err); } + Result::Ok(()) } - } - FieldTypes::Signal(_) => { - // no possible, already checked in check_types - unreachable!() - } - } - } - - } else{ - // case final assignment of signal or bus - let tags = tags.unwrap(); - - // first propagate the tags or check if conditions satisfied if input - let is_init = match field{ - FieldTypes::Signal(signal_slice) =>{ - SignalSlice::get_number_of_inserts(&signal_slice) > 0 - }, - FieldTypes::Bus(bus_slice) =>{ - let mut bus_is_init = false; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - Ok(bus) => { - bus_is_init |= bus.has_assignment(); - } - Err(_) => unreachable!() + Result::Err(err)=>{ + return Err(err); } } - bus_is_init } - }; - if !is_input{ - // case no input, just propagate - perform_tag_propagation(info_tags, status_tags, &tags, is_init); - } else{ - // in case input check if tags are satisfied - for (t, value) in info_tags{ - if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); - } else{ - if !is_init{ - // First assignment of input tag - *value = tags.get(t).unwrap().clone(); - } - else{ - // already given a value, check that it is the same - // if not return error - if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(field_name.to_string(), t.clone())); - } - } - } + FieldTypes::Signal(_) => { + // no possible, already checked in check_types + unreachable!() } } + + + + - // then assign the values to the signal or bus + } else{ + // assign the values to the signal or bus match field{ FieldTypes::Signal(signal_slice) =>{ let route = match assigned_value{ @@ -438,7 +284,6 @@ impl BusRepresentation { FoldedArgument::Bus(bus_slice) =>{ bus_slice.route() }, - _ => unreachable!() }; let mut dim_slice = 1; @@ -455,35 +300,6 @@ impl BusRepresentation { } Option::None => {} } - - // Update the value of the signal tags it is complete - - let is_completely_initialized = match field{ - FieldTypes::Signal(signal_slice) =>{ - SignalSlice::get_number_of_inserts(signal_slice) == - SignalSlice::get_number_of_cells(signal_slice) - }, - FieldTypes::Bus(bus_slice) =>{ - let mut bus_is_completely_init = true; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - match BusSlice::get_reference_to_single_value_by_index(bus_slice, i){ - Ok(bus) => { - bus_is_completely_init &= bus.has_assignment(); - } - Err(_) => unreachable!() - } - } - bus_is_completely_init - } - - }; - - if is_completely_initialized && !is_input{ - - for (_tag, state) in status_tags{ - state.complete = true; - } - } Ok(()) } @@ -503,31 +319,6 @@ impl BusRepresentation { self.has_assignment = true; for (field_name, value) in &mut self.fields{ - // get the tags that are propagated - let (tags_definition, tags_info) = self.field_tags.get_mut(field_name).unwrap(); - let (tags_assigned_definition, tags_assigned_info) = assigned_bus.field_tags.get(field_name).unwrap(); - let tags_propagated = compute_propagated_tags(tags_assigned_info, tags_assigned_definition); - - let is_init = false; - - // perform the tag assignment - if !is_input{ - // case no input, just propagate - perform_tag_propagation(tags_info, tags_definition, &tags_propagated, is_init); - } else{ - - // in case input check if tags are satisfied - for (t, value) in tags_info{ - if !tags_propagated.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(field_name.to_string(), t.clone())); - } else{ - // Not needed check, always not init, if not error - // First assignment of input tag - *value = tags_propagated.get(t).unwrap().clone(); - } - } - } - // perform the assignment match value{ FieldTypes::Bus(ref mut bus_slice) =>{ @@ -574,11 +365,7 @@ impl BusRepresentation { // Update the value of unnasigned fields self.unassigned_fields.remove(field_name); - - // Update the value of the complete tags - for (_tag, state) in tags_definition{ - state.complete = true; - } + } Ok(()) @@ -628,10 +415,4 @@ impl BusRepresentation { result } - - - pub fn has_assignment(&self)-> bool{ - self.has_assignment - } - } diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 7da0dd663..8b686d6c6 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -2,9 +2,9 @@ use super::slice_types::{FoldedResult, FoldedArgument, BusSlice, MemoryError, Si use crate::execution_data::type_definitions::AccessingInformationBus; use crate::{environment_utils::slice_types::BusRepresentation, execution_data::type_definitions::NodePointer}; use crate::execution_data::ExecutedProgram; -use std::collections::{BTreeMap,HashMap, HashSet}; +use std::collections::{HashMap, HashSet}; use crate::ast::Meta; - +use crate::execution_data::type_definitions::{TagNames,TagWire}; use crate::assignment_utils::*; pub struct ComponentRepresentation { @@ -12,16 +12,16 @@ pub struct ComponentRepresentation { pub is_parallel: bool, pub meta: Option, unassigned_inputs: HashMap, - unassigned_tags: HashSet, + unassigned_tags: HashSet>, to_assign_inputs: Vec<(String, Vec, Vec)>, to_assign_input_buses: Vec<(String, Vec, BusSlice)>, - to_assign_input_bus_fields: Vec<(String, AccessingInformationBus, FoldedResult, TagInfo)>, + to_assign_input_bus_fields: Vec<(String, AccessingInformationBus, FoldedResult)>, inputs: HashMap, input_buses: HashMap, - pub inputs_tags: BTreeMap, + pub inputs_tags: HashMap, outputs: HashMap, output_buses: HashMap, - pub outputs_tags: BTreeMap, + pub outputs_tags: HashMap, pub is_initialized: bool, } @@ -34,9 +34,9 @@ impl Default for ComponentRepresentation { unassigned_tags: HashSet::new(), to_assign_inputs: Vec::new(), inputs: HashMap::new(), - inputs_tags: BTreeMap::new(), + inputs_tags: HashMap::new(), outputs: HashMap::new(), - outputs_tags: BTreeMap::new(), + outputs_tags: HashMap::new(), is_initialized: false, meta: Option::None, to_assign_input_buses: Vec::new(), @@ -85,25 +85,49 @@ impl ComponentRepresentation { let node = possible_node.unwrap(); let mut unassigned_tags = HashSet::new(); - let mut inputs_tags = BTreeMap::new(); - let mut outputs_tags = BTreeMap::new(); - for (symbol, tags) in node.inputs() { - if !tags.is_empty() { - unassigned_tags.insert(symbol.clone()); - } + let mut inputs_tags = HashMap::new(); + let mut outputs_tags = HashMap::new(); + pub fn collect_info_tag(tags: &TagNames, complete_name: &mut Vec, unassigned_tags: &mut HashSet>, is_input:bool)-> TagWire{ let mut new_tags = TagInfo::new(); - for t in tags{ + if !tags.tag_names.is_empty() && is_input{ + unassigned_tags.insert(complete_name.clone()); + } + for t in &tags.tag_names{ new_tags.insert(t.clone(), Option::None); } - inputs_tags.insert(symbol.clone(), new_tags); + let new_tag_fields = if tags.fields.is_some(){ + let mut info = HashMap::new(); + for (name, tags) in tags.fields.as_ref().unwrap(){ + complete_name.push(name.clone()); + info.insert( + name.clone(), + collect_info_tag(tags, complete_name, unassigned_tags, is_input) + ); + complete_name.pop(); + } + Some(info) + } else{ + None + }; + TagWire{ + tags: new_tags, + fields: new_tag_fields, + } + } + for (symbol, tags) in node.inputs() { + let mut complete_name = vec![symbol.clone()]; + if !tags.tag_names.is_empty() { + unassigned_tags.insert(complete_name.clone()); + } + let tag_info = collect_info_tag(tags, &mut complete_name, &mut unassigned_tags, true); + inputs_tags.insert(symbol.clone(), tag_info); + } for (symbol, tags) in node.outputs() { - let mut new_tags = TagInfo::new(); - for t in tags{ - new_tags.insert(t.clone(), Option::None); - } - outputs_tags.insert(symbol.clone(), new_tags); + let mut complete_name = vec![symbol.clone()]; + let tag_info = collect_info_tag(tags, &mut complete_name, &mut unassigned_tags, false); + outputs_tags.insert(symbol.clone(), tag_info); } *component = ComponentRepresentation { @@ -167,19 +191,19 @@ impl ComponentRepresentation { } - fn insert_tags_output(node: &crate::execution_data::ExecutedTemplate, symbol: &String, component: &mut ComponentRepresentation) { - let tags_output = node.signal_to_tags.get(symbol); - let component_tags_output = component.outputs_tags.get_mut(symbol); - if tags_output.is_some() && component_tags_output.is_some(){ - let result_tags_output = tags_output.unwrap(); - let result_component_tags_output = component_tags_output.unwrap(); - for (tag, value) in result_tags_output{ - // only update the output tag in case it contains the tag in the definition - if result_component_tags_output.contains_key(tag){ - result_component_tags_output.insert(tag.clone(), value.clone()); + fn insert_tags_output(node: &crate::execution_data::ExecutedTemplate, component: &mut ComponentRepresentation) { + + for (tag_name, value) in &node.signal_to_tags{ + if component.outputs_tags.contains_key(&tag_name[0]){ + // in this case we have to store the value + let info_output_tags = component.outputs_tags.get_mut(&tag_name[0]).unwrap(); + for i in 1..tag_name.len()-1{ + info_output_tags.fields.as_mut().unwrap().get_mut(&tag_name[i]).unwrap(); } + info_output_tags.tags.insert(tag_name.last().unwrap().clone(), Some(value.clone())); } } + } for info_wire in node.outputs() { @@ -200,8 +224,10 @@ impl ComponentRepresentation { component.output_buses.insert(symbol.clone(), bus_slice); } - insert_tags_output(node, symbol, component); } + // To insert the info of the output tags + insert_tags_output(node, component); + component.node_pointer = Option::Some(node_pointer); @@ -219,7 +245,13 @@ impl ComponentRepresentation { } let to_assign = std::mem::replace(&mut component.to_assign_input_bus_fields, vec![]); - for (signal_name, access, field_value, tags_input) in to_assign{ + for (signal_name, access, field_value) in &to_assign{ + let mut tags_input = &component.inputs_tags[signal_name].clone(); + let mut aux_access = access; + while aux_access.field_access.is_some(){ + tags_input = tags_input.fields.as_ref().unwrap().get(aux_access.field_access.as_ref().unwrap()).unwrap(); + aux_access = aux_access.remaining_access.as_ref().unwrap(); + } component.assign_value_to_bus_field_init(&signal_name, &access, &field_value, tags_input)?; } @@ -241,28 +273,31 @@ impl ComponentRepresentation { if !self.is_initialized { // we return the name of an input with tags that has not been assigned let ex_signal = self.unassigned_tags.iter().next().unwrap().clone(); - return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal))); + return Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::MissingInputTags(ex_signal[0].clone()))); // TODO: improve, show complete trace } Result::Ok(()) } - pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<(Option, FoldedResult), MemoryError>{ + pub fn get_io_value(&self, field_name: &str, remaining_access: &AccessingInformationBus) ->Result<(TagWire, FoldedResult), MemoryError>{ if let Result::Err(value) = self.check_initialized_inputs(field_name) { return Err(value); } if self.inputs.contains_key(field_name) || self.outputs.contains_key(field_name){ // in this case we are accessing a signal + + // We get the info of the tags let (tag_info, signal_slice) = if self.inputs.contains_key(field_name) { (self.inputs_tags.get(field_name).unwrap(), self.inputs.get(field_name).unwrap()) } else { (self.outputs_tags.get(field_name).unwrap(), self.outputs.get(field_name).unwrap()) }; - + + /* NOT VALID: to access a tag of a subcomponent if remaining_access.field_access.is_some(){ // in case it is a tag access assert!(remaining_access.array_access.len() == 0); - let value_tag = tag_info.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); + let value_tag = tag_info.tags.get(remaining_access.field_access.as_ref().unwrap()).unwrap(); match value_tag{ Option::None =>{ let error = MemoryError::TagValueNotInitializedAccess; @@ -273,37 +308,35 @@ impl ComponentRepresentation { Result::Ok((None, folded_tag)) } } - } else{ + } else{*/ // case signals // We access to the selected signal if it is an array let accessed_slice_result = SignalSlice::access_values(signal_slice, &remaining_access.array_access); match accessed_slice_result{ Ok(slice) =>{ let folded_slice = FoldedResult::Signal(slice); - Result::Ok((Some(tag_info.clone()), folded_slice)) + Result::Ok((tag_info.clone(), folded_slice)) }, Err(err) => Err(err) } - } + //} } else{ // in this case we are accessing a bus - let (tag_info, bus_slice) = if self.input_buses.contains_key(field_name) { + let (mut tag_info, bus_slice) = if self.input_buses.contains_key(field_name) { (self.inputs_tags.get(field_name).unwrap(), self.input_buses.get(field_name).unwrap()) } else { (self.outputs_tags.get(field_name).unwrap(), self.output_buses.get(field_name).unwrap()) }; - if remaining_access.field_access.is_some(){ - // In this case we need to access to values of the bus or one of its tags - let next_array_access = &remaining_access.array_access; + let result = if remaining_access.field_access.is_some(){ + // In this case we need to access to values of the bus let next_field_access = remaining_access.field_access.as_ref().unwrap(); let next_remaining_access = remaining_access.remaining_access.as_ref().unwrap(); - // we distingish between tags or buses - if tag_info.contains_key(remaining_access.field_access.as_ref().unwrap()){ + /* NOT VALID-> case tags: if tag_info.tags.contains_key(remaining_access.field_access.as_ref().unwrap()){ // in this case we are returning a tag assert!(next_array_access.len() == 0); - let value_tag = tag_info.get(next_field_access).unwrap(); + let value_tag = tag_info.tags.get(next_field_access).unwrap(); match value_tag{ Option::None =>{ let error = MemoryError::TagValueNotInitializedAccess; @@ -314,8 +347,8 @@ impl ComponentRepresentation { Result::Ok((None, folded_tag)) } } - } else{ - // in this case we are returning a field of the bus + } else{ */ + // we are returning a field of the bus let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); let accessed_bus = match accessed_slice_result{ @@ -324,21 +357,23 @@ impl ComponentRepresentation { }, Err(err) => return Err(err) }; - accessed_bus.get_field(next_field_access, next_remaining_access) - } + accessed_bus.get_field(next_field_access, next_remaining_access)? + //} } else{ // In this case we are accessing the complete bus - let accessed_slice_result = BusSlice::access_values(bus_slice, &remaining_access.array_access); - - match accessed_slice_result{ - Ok(slice) =>{ - let folded_slice = FoldedResult::Bus(slice); - Result::Ok((Some(tag_info.clone()), folded_slice)) - }, - Err(err) => Err(err) - } + let slice = BusSlice::access_values(bus_slice, &remaining_access.array_access)?; + FoldedResult::Bus(slice) + }; + + // Finally, get the tags + let mut to_access = remaining_access; + while to_access.field_access != None { + let acc = to_access.field_access.as_ref().unwrap(); + tag_info = tag_info.fields.as_ref().unwrap().get(acc).unwrap(); + to_access = remaining_access.remaining_access.as_ref().unwrap(); } + Ok((tag_info.clone(), result)) } } @@ -350,7 +385,7 @@ impl ComponentRepresentation { signal_name: &str, access: &[SliceCapacity], slice_route: &[SliceCapacity], - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !component.is_initialized{ ComponentRepresentation::assign_value_to_signal_no_init( @@ -376,11 +411,11 @@ impl ComponentRepresentation { signal_name: &str, access: &[SliceCapacity], slice_route: &[SliceCapacity], - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { // check that the tags are correct and update values - ComponentRepresentation::handle_tag_assignment_no_init(component, signal_name, tags)?; + ComponentRepresentation::handle_tag_assignment_no_init(component, &vec![signal_name.to_string()], tags)?; component.to_assign_inputs.push((signal_name.to_string(), access.to_vec(), slice_route.to_vec())); Result::Ok(()) @@ -391,7 +426,7 @@ impl ComponentRepresentation { signal_name: &str, access: &[SliceCapacity], slice_route: &[SliceCapacity], - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !self.is_preinitialized() { @@ -403,7 +438,7 @@ impl ComponentRepresentation { } // Check that the assignment satisfies the tags requisites - ComponentRepresentation::handle_tag_assignment_init(self, signal_name, tags)?; + ComponentRepresentation::handle_tag_assignment_init(self, &vec![signal_name.to_string()], tags)?; // Perform the assignment @@ -424,7 +459,7 @@ impl ComponentRepresentation { bus_name: &str, access: &[SliceCapacity], bus_slice: BusSlice, - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !component.is_initialized{ ComponentRepresentation::assign_value_to_bus_no_init( @@ -450,11 +485,11 @@ impl ComponentRepresentation { bus_name: &str, access: &[SliceCapacity], bus_slice: BusSlice, - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { // check that the tags are correct and update values - ComponentRepresentation::handle_tag_assignment_no_init(component, bus_name, tags)?; + ComponentRepresentation::handle_tag_assignment_no_init(component, &vec![bus_name.to_string()], tags)?; component.to_assign_input_buses.push((bus_name.to_string(), access.to_vec(), bus_slice)); Result::Ok(()) @@ -465,7 +500,7 @@ impl ComponentRepresentation { bus_name: &str, access: &[SliceCapacity], bus_slice: &BusSlice, - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !self.is_preinitialized() { @@ -477,7 +512,7 @@ impl ComponentRepresentation { } // Check that the assignment satisfies the tags requisites - ComponentRepresentation::handle_tag_assignment_init(self, bus_name, tags)?; + ComponentRepresentation::handle_tag_assignment_init(self, &vec![bus_name.to_string()], tags)?; // Perform the assignment let inputs_response = self.input_buses.get_mut(bus_name).unwrap(); @@ -499,7 +534,7 @@ impl ComponentRepresentation { bus_name: &str, access: &AccessingInformationBus, field_value: FoldedResult, - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !component.is_initialized{ ComponentRepresentation::assign_value_to_bus_field_no_init( @@ -515,7 +550,7 @@ impl ComponentRepresentation { bus_name, access, &field_value, - tags.clone() + tags ) } } @@ -525,21 +560,37 @@ impl ComponentRepresentation { bus_name: &str, access: &AccessingInformationBus, field_value: FoldedResult, - tags: &TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { - // check that the tags are correct and update values, in this case none inputs - // are assigned to the complete bus + fn build_name(complete_bus_name: &mut Vec, access: &AccessingInformationBus){ + match &access.field_access{ + Option::None =>{}, + Option::Some(name) =>{ + complete_bus_name.push(name.clone()); + } + } + match &access.remaining_access{ + Option::None =>{}, + Option::Some(remaining) =>{ + build_name(complete_bus_name, &remaining) + } + } + } + let mut complete_name = vec![bus_name.to_string()]; + build_name(&mut complete_name, access); + + // check that the tags are correct and update values ComponentRepresentation::handle_tag_assignment_no_init( component, - bus_name, - &TagInfo::new())?; + &complete_name, + &tags + )?; component.to_assign_input_bus_fields.push(( bus_name.to_string(), access.clone(), field_value, - tags.clone() ) ); @@ -551,7 +602,7 @@ impl ComponentRepresentation { bus_name: &str, access: &AccessingInformationBus, field_value: &FoldedResult, - tags: TagInfo, + tags: &TagWire, ) -> Result<(), MemoryError> { if !self.is_preinitialized() { @@ -562,6 +613,10 @@ impl ComponentRepresentation { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } + // Check that the assignment satisfies the tags requisites + let mut complete_bus_name = vec![bus_name.to_string()]; + build_name(&mut complete_bus_name, access); + ComponentRepresentation::handle_tag_assignment_init(self, &complete_bus_name, &tags)?; // Get the assigned input bus let inputs_slice = self.input_buses.get_mut(bus_name).unwrap(); @@ -587,22 +642,17 @@ impl ComponentRepresentation { FoldedResult::Bus (bs)=>{ FoldedArgument::Bus(&bs) }, - FoldedResult::Tag(_) =>{ - unreachable!() - } }; single_bus.assign_value_to_field( access.field_access.as_ref().unwrap(), access.remaining_access.as_ref().unwrap(), folded_arg, - Some(tags), - true, // it is an input so check tags instead of propagate + true, )?; // In case it is completely assigned update unassigned - if !single_bus.has_unassigned_fields(){ ComponentRepresentation::update_unassigned_inputs(self, bus_name, &[1]); } @@ -633,55 +683,127 @@ impl ComponentRepresentation { */ - fn handle_tag_assignment_no_init(component: &mut ComponentRepresentation, signal_name: &str, tags: &TagInfo) -> Result<(), MemoryError> { + fn handle_tag_assignment_no_init( + component: &mut ComponentRepresentation, + signal_name: &Vec, + tags: &TagWire + ) -> Result<(), MemoryError> { if !component.is_preinitialized() { return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::NoInitializedComponent)); } - if !component.inputs_tags.contains_key(signal_name){ + if !component.inputs_tags.contains_key(&signal_name[0]){ return Result::Err(MemoryError::AssignmentError(TypeAssignmentError::AssignmentOutput)); } - let tags_input = component.inputs_tags.get_mut(signal_name).unwrap(); - let is_first_assignment_signal = component.unassigned_tags.contains(signal_name); - component.unassigned_tags.remove(signal_name); + // perform all the intermediate accesses to the field + let mut accessed_info = &mut component.inputs_tags; + for i in 0..signal_name.len()-1{ + accessed_info = accessed_info.get_mut(&signal_name[i]).unwrap().fields.as_mut().unwrap(); + } + let input_tags = accessed_info.get_mut(&signal_name[signal_name.len()-1]).unwrap(); // We copy tags in any case, complete or incomplete assignment - // The values of the tags must be the same than the ones stored before - - for (t, value) in tags_input{ - if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); - } else{ - if is_first_assignment_signal{ - *value = tags.get(t).unwrap().clone(); - } - else{ - // already given a value, check that it is the same - if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); + // Th.e values of the tags must be the same than the ones stored before + + fn check_tags( + input_tags: &mut TagWire, + unassigned_tags: &mut HashSet>, + tags_info: &TagWire, + signal_name: &mut Vec + )-> Result<(), MemoryError> { + + // remove the signal name of unassigned inputs + let is_first_assignment_signal = unassigned_tags.contains(signal_name); + unassigned_tags.remove(signal_name); + + for (t, value) in &mut input_tags.tags{ + if !tags_info.tags.contains_key(t){ + // TODO: change error message to consider Vec + return Result::Err(MemoryError::AssignmentMissingTags(signal_name[0].to_string(), t.clone())); + } else{ + if is_first_assignment_signal{ + *value = tags_info.tags.get(t).unwrap().clone(); + } + else{ + // already given a value, check that it is the same + if value != tags_info.tags.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name[0].to_string(), t.clone())); + } } } } + if input_tags.fields.is_some(){ + let input_fields = input_tags.fields.as_mut().unwrap(); + let tags_fields = tags_info.fields.as_ref().unwrap(); + for (field_name, input_field) in input_fields{ + let tags = tags_fields.get(field_name).unwrap(); + signal_name.push(field_name.clone()); + check_tags( + input_field, + unassigned_tags, + tags, + signal_name + )?; + signal_name.pop(); + } + } + Result::Ok(()) } - Result::Ok(()) + + + check_tags( + input_tags, + &mut component.unassigned_tags, + tags, + &mut signal_name.clone() + ) + + } - fn handle_tag_assignment_init(component: &ComponentRepresentation, signal_name: &str, tags: &TagInfo)-> Result<(), MemoryError>{ - let tags_input = component.inputs_tags.get(signal_name).unwrap(); - for (t, value) in tags_input{ - if !tags.contains_key(t){ - return Result::Err(MemoryError::AssignmentMissingTags(signal_name.to_string(), t.clone())); - } else{ - // We are in the case wher.e the component is initialized, so we - // assume that all tags already have their value and check if it is - // the same as the one we are receiving - if value != tags.get(t).unwrap(){ - return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name.to_string(), t.clone())); + fn handle_tag_assignment_init( + component: &ComponentRepresentation, + signal_name: &Vec, + tags: &TagWire + )-> Result<(), MemoryError>{ + // perform all the intermediate accesses to the field + let mut accessed_info = &component.inputs_tags; + for i in 0..signal_name.len()-1{ + accessed_info = accessed_info.get(&signal_name[i]).unwrap().fields.as_ref().unwrap(); + } + let input_tags = accessed_info.get(&signal_name[signal_name.len()-1]).unwrap(); + + fn check_tags(input_tags: &TagWire, tags: &TagWire, signal_name: &mut Vec)-> Result<(), MemoryError>{ + for (t, value) in &input_tags.tags{ + if !tags.tags.contains_key(t){ + return Result::Err(MemoryError::AssignmentMissingTags(signal_name[0].to_string(), t.clone())); + } else{ + // We are in the case where the component is initialized, so we + // assume that all tags already have their value and check if it is + // the same as the one we are receiving + if value != tags.tags.get(t).unwrap(){ + return Result::Err(MemoryError::AssignmentTagInputTwice(signal_name[0].to_string(), t.clone())); + } + } + } + if input_tags.fields.is_some(){ + let tags_field = tags.fields.as_ref().unwrap(); + for (field_name, input_field) in input_tags.fields.as_ref().unwrap(){ + signal_name.push(field_name.clone()); + check_tags( + input_field, + tags_field.get(field_name).as_ref().unwrap(), + signal_name + )?; + signal_name.pop(); } + } + Ok(()) } - Ok(()) + let mut aux_name = signal_name.clone(); + check_tags(input_tags, tags, &mut aux_name) } // Auxiliar function to update the unassigned inputs @@ -703,3 +825,20 @@ impl ComponentRepresentation { } } + +// Auxiliar function to build the name of a bus field +fn build_name(complete_bus_name: &mut Vec, access: &AccessingInformationBus){ + match &access.field_access{ + Option::None =>{}, + Option::Some(name) =>{ + complete_bus_name.push(name.clone()); + } + } + match &access.remaining_access{ + Option::None =>{}, + Option::Some(remaining) =>{ + build_name(complete_bus_name, &remaining) + } + } +} + diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index f1be900e7..4a96c6a0d 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -8,14 +8,19 @@ use super::slice_types::{ TagInfo, TagDefinitions, TagState, - BusSlice + BusSlice, + BusTagInfo }; use super::{ArithmeticExpression, CircomEnvironment, CircomEnvironmentError}; use program_structure::memory_slice::MemoryError; +use crate::execution_data::type_definitions::TagWire; use crate::ast::Meta; +use std::collections::BTreeMap; +use crate::environment_utils::slice_types::BigInt; + pub type ExecutionEnvironmentError = CircomEnvironmentError; -pub type ExecutionEnvironment = CircomEnvironment; +pub type ExecutionEnvironment = CircomEnvironment; pub fn environment_shortcut_add_component( environment: &mut ExecutionEnvironment, @@ -70,16 +75,37 @@ pub fn environment_shortcut_add_bus_input( environment: &mut ExecutionEnvironment, input_name: &str, dimensions: &[SliceCapacity], - tags: &TagInfo, + tags: &TagWire, ) { + fn generate_tags_data(tags: &TagWire)-> BusTagInfo{ + let mut tags_defined = TagDefinitions::new(); + + for (t, value) in &tags.tags{ + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: true}); + } + let mut fields = BTreeMap::new(); + if tags.fields.is_some(){ + for (field_name, info_field) in tags.fields.as_ref().unwrap(){ + let field_tag_info = generate_tags_data(info_field); + fields.insert(field_name.clone(), field_tag_info); + } + } + + BusTagInfo{ + definitions: tags_defined, + tags: tags.tags.clone(), + remaining_inserts: 0, + size: 0, // in this case we never use it + is_init: true, + fields + } + } + // In this case we need to set all the signals of the bus to known -> in the default method let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); - let mut tags_defined = TagDefinitions::new(); - for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: true}); - } + - environment.add_input_bus(input_name, (tags.clone(), tags_defined, slice)); + environment.add_input_bus(input_name, (generate_tags_data(tags), slice)); } pub fn environment_shortcut_add_bus_output( environment: &mut ExecutionEnvironment, @@ -92,7 +118,16 @@ pub fn environment_shortcut_add_bus_output( for (t, value) in tags{ tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); } - environment.add_output_bus(output_name, (tags.clone(), tags_defined, slice)); + let size = dimensions.iter().fold(1, |aux, val| aux * val); + let tag_info= BusTagInfo{ + definitions: tags_defined, + tags: tags.clone(), + remaining_inserts: size, + size, + is_init: false, + fields: BTreeMap::new(), + }; + environment.add_output_bus(output_name, (tag_info, slice)); } pub fn environment_shortcut_add_bus_intermediate( environment: &mut ExecutionEnvironment, @@ -105,7 +140,17 @@ pub fn environment_shortcut_add_bus_intermediate( for (t, value) in tags{ tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); } - environment.add_intermediate_bus(intermediate_name, (tags.clone(), tags_defined, slice)); + let size = dimensions.iter().fold(1, |aux, val| aux * val); + + let tag_info= BusTagInfo{ + definitions: tags_defined, + tags: tags.clone(), + remaining_inserts: size, + size, + is_init: false, + fields: BTreeMap::new(), + }; + environment.add_intermediate_bus(intermediate_name, (tag_info, slice)); } pub fn environment_shortcut_add_variable( environment: &mut ExecutionEnvironment, @@ -127,4 +172,45 @@ pub fn environment_check_all_components_assigned(environment: &ExecutionEnvironm } } Result::Ok(()) +} + + +pub fn environment_get_value_tags_signal(environment: &ExecutionEnvironment, name: &String) -> Vec<(Vec, BigInt)>{ + let mut to_add = Vec::new(); + let (tags, definitions, _) = environment.get_signal(name).unwrap(); + for (tag, value) in tags{ + if value.is_some(){ + let state = definitions.get(tag).unwrap(); + if state.defined && (state.value_defined || state.complete){ + to_add.push((vec![name.clone(), tag.clone()], value.clone().unwrap())); + } + } + } + to_add +} + +pub fn environment_get_value_tags_bus(environment: &ExecutionEnvironment, name: &String) -> Vec<(Vec, BigInt)>{ + fn get_value_tags_data(tag_data: &BusTagInfo, name: &Vec)-> Vec<(Vec, BigInt)>{ + let mut to_add = Vec::new(); + for (tag, value) in &tag_data.tags{ + if value.is_some(){ + let state = tag_data.definitions.get(tag).unwrap(); + if state.defined && (state.value_defined || state.complete){ + let mut aux = name.clone(); + aux.push(tag.clone()); + to_add.push((aux, value.clone().unwrap())); + } + } + } + for (field, field_data) in &tag_data.fields{ + let mut aux = name.clone(); + aux.push(field.clone()); + let mut new_tags = get_value_tags_data(field_data, &aux); + to_add.append(&mut new_tags); + } + to_add + } + let (tag_data, _) = environment.get_bus(name).unwrap(); + + get_value_tags_data(tag_data, &vec![name.clone()]) } \ No newline at end of file diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index e5426fe99..7cf6c02cc 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -14,6 +14,18 @@ pub struct TagState{ } pub type TagInfo = BTreeMap>; pub type TagDefinitions = BTreeMap; // the tags defined for each signal and if the info about their state + +#[derive(Debug, Clone)] +pub struct BusTagInfo{ + pub tags: TagInfo, + pub definitions: TagDefinitions, + pub remaining_inserts: usize, // indicates the number of remaining inserts to be complete + pub size: usize, // the size of the array generating the bus + pub is_init: bool, // to check if the bus has been initialized or not (no valid tag declarations if init) + pub fields: BTreeMap, +} + + pub type AExpressionSlice = MemorySlice>; // The boolean is true if the signal contains a value pub type SignalSlice = MemorySlice; @@ -35,7 +47,6 @@ pub enum FoldedResult { // For each possible returning value, we store the info // Depending on the case we store a different slice Signal(SignalSlice), Bus(BusSlice), - Tag(BigInt) } @@ -43,5 +54,4 @@ pub enum FoldedArgument<'a> { // For each possible argument, we store the info d // Depending on the case we store a different slice Signal(&'a Vec), Bus(&'a BusSlice), - Tag(&'a BigInt) } \ No newline at end of file diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index f48f26a47..863166ee9 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -5,7 +5,9 @@ use super::environment_utils::{ environment_shortcut_add_bus_input, environment_shortcut_add_bus_intermediate, environment_shortcut_add_bus_output, environment_shortcut_add_variable, ExecutionEnvironment, ExecutionEnvironmentError, - environment_check_all_components_assigned + environment_check_all_components_assigned, + environment_get_value_tags_bus, environment_get_value_tags_signal + }, slice_types::{ AExpressionSlice, ArithmeticExpression as ArithmeticExpressionGen, ComponentRepresentation, @@ -14,15 +16,15 @@ use super::environment_utils::{ FoldedResult, FoldedArgument }, }; - +use program_structure::wire_data::WireType; use crate::assignment_utils::*; - +use crate::environment_utils::slice_types::BusTagInfo; use program_structure::constants::UsefulConstants; - +use program_structure::bus_data::BusData; use super::execution_data::analysis::Analysis; use super::execution_data::{ExecutedBus, ExecutedProgram, ExecutedTemplate, PreExecutedTemplate, NodePointer}; -use super::execution_data::type_definitions::{AccessingInformationBus, AccessingInformation}; +use super::execution_data::type_definitions::{AccessingInformationBus, AccessingInformation, TagNames, TagWire}; use super::{ ast::*, ArithmeticError, FileID, ProgramArchive, Report, ReportCode, ReportCollection @@ -74,7 +76,7 @@ struct FoldedValue { pub node_pointer: Option, pub bus_node_pointer: Option, pub is_parallel: Option, - pub tags: Option, + pub tags: Option, } impl FoldedValue { pub fn valid_arithmetic_slice(f_value: &FoldedValue) -> bool { @@ -152,7 +154,7 @@ pub fn constraint_execution( execute_template_call_complete( id, arg_values, - BTreeMap::new(), + HashMap::new(), program_archive, &mut runtime_information, flags, @@ -1131,7 +1133,7 @@ fn execute_call( fn execute_template_call_complete( id: &String, arg_values: Vec, - tags: BTreeMap, + tags: HashMap, program_archive: &ProgramArchive, runtime: &mut RuntimeInformation, flags: FlagsExecution, @@ -1238,7 +1240,7 @@ fn execute_signal_declaration( match signal_type { Input => { if let Some(tags_input) = node.tag_instances().get(signal_name){ - environment_shortcut_add_input(environment, signal_name, dimensions, &tags_input); + environment_shortcut_add_input(environment, signal_name, dimensions, &tags_input.tags); } else{ environment_shortcut_add_input(environment, signal_name, dimensions, &tags); } @@ -1272,16 +1274,13 @@ fn execute_declaration_bus( } if is_bus{ - actual_node.add_bus(signal_name, dimensions); + actual_node.add_bus(signal_name, dimensions, list_tags.clone()); environment_shortcut_add_bus_intermediate(environment, signal_name, dimensions, &tags); } else{ - actual_node.add_signal(signal_name, dimensions); + actual_node.add_signal(signal_name, dimensions, list_tags.clone()); environment_shortcut_add_intermediate(environment, signal_name, dimensions, &tags); } - for t in list_tags{ - actual_node.add_tag_signal(signal_name, t, None); - } } fn execute_bus_declaration( @@ -1297,13 +1296,18 @@ fn execute_bus_declaration( for t in list_tags{ tags.insert(t.clone(), None); } + if let Option::Some(node) = actual_node { match signal_type { Input => { if let Some(tags_input) = node.tag_instances().get(bus_name){ - environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tags_input); + environment_shortcut_add_bus_input(environment, bus_name, dimensions, tags_input); } else{ - environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tags); + let tag_wire = TagWire{ + tags, + fields: None + }; + environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tag_wire); } node.add_input(bus_name, dimensions, true); } @@ -1377,12 +1381,12 @@ fn perform_assign( let mut r_tags = if r_folded.tags.is_some(){ r_folded.tags.as_ref().unwrap().clone() } else{ - TagInfo::new() + TagWire::default() }; let mut r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); if runtime.block_type == BlockType::Unknown { r_slice = AExpressionSlice::new_with_route(r_slice.route(), &AExpr::NonQuadratic); - r_tags = TagInfo::new(); + r_tags = TagWire::default(); } if accessing_information.undefined { let new_value = @@ -1412,7 +1416,7 @@ fn perform_assign( )?; // in case it is a complete assignment assign the tags, if not set the tags to empty if AExpressionSlice::get_number_of_cells(symbol_content) == AExpressionSlice::get_number_of_cells(&r_slice){ - *symbol_tags = r_tags; + *symbol_tags = r_tags.tags; } else { *symbol_tags = TagInfo::new(); } @@ -1457,55 +1461,40 @@ fn perform_assign( meta, &mut runtime.runtime_errors, &runtime.call_trace, + )?; + } + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); + let value_aux = AExpressionSlice::unwrap_to_single(arithmetic_slice); + let value = if let ArithmeticExpressionGen::Number { value } = value_aux { + value + } else { + treat_result_with_execution_error( + Result::Err(ExecutionError::NonValidTagAssignment), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, )? - } - else if let Some(a_slice) = r_folded.arithmetic_slice { - - let value = AExpressionSlice::unwrap_to_single(a_slice); - match value { - ArithmeticExpressionGen::Number { value } => { - let possible_tag = reference_to_tags.get(&tag.clone()); - if let Some(val) = possible_tag { - if let Some(_) = val { - treat_result_with_memory_error( - Result::Err(MemoryError::AssignmentTagTwice), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? - } else { // we add the info saying that the tag is defined - reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); - let tag_state = reference_to_tags_defined.get_mut(&tag).unwrap(); - tag_state.value_defined = true; - match actual_node{ - ExecutedStructure::Template(node) =>{ - node.add_tag_signal(symbol, &tag, Some(value)); - }, - ExecutedStructure::Bus(node) =>{ - node.add_tag_signal(symbol, &tag, Some(value)); - }, - ExecutedStructure::None => { - unreachable!(); - } - } - - } - } else {unreachable!()} - }, - - _ =>{ - treat_result_with_execution_error( - Result::Err(ExecutionError::NonValidTagAssignment), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - }, } - } - else { - unreachable!() - } + }; + let possible_tag = reference_to_tags.get(&tag.clone()); + if let Some(val) = possible_tag { + if let Some(_) = val { + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagTwice), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } else { // we add the info saying that the tag is defined + reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); + let tag_state = reference_to_tags_defined.get_mut(&tag).unwrap(); + tag_state.value_defined = true; + } + } else { + unreachable!() + } + Option::None + }else { // it is just a signal debug_assert!(accessing_information.signal_access.is_none()); @@ -1534,12 +1523,12 @@ fn perform_assign( let new_tags = if r_folded.tags.is_some() && op == AssignOp::AssignConstraintSignal{ r_folded.tags.clone().unwrap() } else{ - TagInfo::new() + TagWire::default() }; let signal_is_init = SignalSlice::get_number_of_inserts(reference_to_signal_content) > 0; - perform_tag_propagation(reference_to_tags, reference_to_tags_defined, &new_tags, signal_is_init); + perform_tag_propagation(reference_to_tags, reference_to_tags_defined, &new_tags.tags, signal_is_init); // Perform the signal assignment @@ -1564,22 +1553,9 @@ fn perform_assign( if signal_is_completely_initialized { - for (tag, value) in reference_to_tags{ + for (tag, _value) in reference_to_tags{ let tag_state = reference_to_tags_defined.get_mut(tag).unwrap(); tag_state.complete = true; - match actual_node{ - ExecutedStructure::Template(node) =>{ - if !tag_state.value_defined{ - node.add_tag_signal(symbol, &tag, value.clone()); - } - }, - ExecutedStructure::Bus(_) =>{ - unreachable!(); - }, - ExecutedStructure::None => { - unreachable!(); - } - } } } @@ -1736,7 +1712,7 @@ fn perform_assign( let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { - TagInfo::new() + TagWire::default() }; let memory_response = if remaining_access.field_access.is_none(){ @@ -1778,10 +1754,12 @@ fn perform_assign( // it is a bus input let bus_accessed = accessing_information.field_access.as_ref().unwrap(); let (name_bus, assigned_bus_slice) = r_folded.bus_slice.unwrap(); + + let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { - TagInfo::new() + TagWire::default() }; // Generate an arithmetic slice for the buses left and right @@ -1959,7 +1937,7 @@ fn perform_assign( let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); - let (tags_info, tags_definition, bus_slice) = treat_result_with_environment_error( + let (tags_info, bus_slice) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, @@ -1984,7 +1962,7 @@ fn perform_assign( debug_assert!(accessing_information.array_access.len() == 0); debug_assert!(accessing_information.field_access.is_none()); - + for i in 0..BusSlice::get_number_of_cells(&bus_slice){ let mut value_left = treat_result_with_memory_error( BusSlice::get_mut_reference_to_single_value_by_index(bus_slice, i), @@ -2008,6 +1986,54 @@ fn perform_assign( } let bus_info = runtime.exec_program.get_bus_node(bus_pointer).unwrap(); + + // Get and update the inside tags of the bus + // -> similar to collect_info_tags + fn collect_info_tags(data_bus: &ExecutedBus, exec_program: &ExecutedProgram, n_inserts: usize)->BTreeMap{ + use crate::environment_utils::slice_types::TagState; + let mut fields = BTreeMap::new(); + + for wire_data in &data_bus.fields{ + let mut tags = BTreeMap::new(); + let mut definitions = BTreeMap::new(); + let mut inside_fields = BTreeMap::new(); + let tag_names = data_bus.tag_names.get(&wire_data.name).unwrap(); + let size = wire_data.length.iter().fold(1, |aux, val| aux * val); + let n_inserts_field = size * n_inserts; + for tag in tag_names{ + tags.insert(tag.clone(), Option::None); + definitions.insert(tag.clone(), TagState{ + defined: true, + value_defined: false, + complete: false, + }); + } + // in this case it is a bus, add its fields + if wire_data.is_bus{ + let bus_pointer = data_bus.bus_connexions.get(&wire_data.name).unwrap().inspect.goes_to; + let data_inside_bus = exec_program.get_bus_node(bus_pointer).unwrap(); + inside_fields = collect_info_tags(data_inside_bus, exec_program, n_inserts_field); + } + fields.insert( + wire_data.name.clone(), + BusTagInfo{ + tags, + definitions, + fields: inside_fields, + remaining_inserts: n_inserts_field, + size, + is_init: false, + } + ); + } + fields + } + // only if it is not an input_bus + if !is_input_bus { + let bus_inside_tags = collect_info_tags(bus_info, &runtime.exec_program, BusSlice::get_number_of_cells(&bus_slice)); + tags_info.fields = bus_inside_tags; + } + let size = bus_info.size; match actual_node{ ExecutedStructure::Template(node) =>{ @@ -2053,14 +2079,13 @@ fn perform_assign( let tags = if r_folded.tags.is_some() { r_folded.tags.unwrap() } else { - TagInfo::new() + TagWire::default() }; let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), FoldedArgument::Signal(&arithmetic_slice.route().to_vec()), - Some(tags), false ); treat_result_with_memory_error_void( @@ -2069,6 +2094,16 @@ fn perform_assign( &mut runtime.runtime_errors, &runtime.call_trace, )?; + + // Perform the tag propagation + // access to the field that is assigned and then propagate the tags + let mut to_access = accessing_information; + let mut tag_data = tags_info; + while to_access.remaining_access.is_some(){ + tag_data = tag_data.fields.get_mut(to_access.field_access.as_ref().unwrap()).unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); + } + perform_tag_propagation_bus(tag_data, &tags, MemorySlice::get_number_of_cells(&arithmetic_slice)); // Get left arithmetic slice let mut l_signal_names = Vec::new(); @@ -2082,109 +2117,73 @@ fn perform_assign( } else if meta.get_type_knowledge().is_tag(){ // in case we are assigning a tag of the complete bus - // or one of its fields - assert!(accessing_information.array_access.len() == 0); - assert!(accessing_information.field_access.is_some()); - if accessing_information.remaining_access.as_ref().unwrap().field_access.is_none(){ - // case tag of the complete bus - let tag = accessing_information.field_access.as_ref().unwrap(); - let environment_response = ExecutionEnvironment::get_mut_bus_res(&mut runtime.environment, symbol); - let (reference_to_tags, reference_to_tags_defined, bus_content) = treat_result_with_environment_error( - environment_response, + // check not valid in input buses + if is_input_bus { + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagInput), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } + // check not valid in unknown environment + if runtime.block_type == BlockType::Unknown{ + // Case not valid constraint Known/Unknown + let err = Result::Err(ExecutionError::TagAssignmentInUnknown); + treat_result_with_execution_error( + err, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; + } - for i in 0..BusSlice::get_number_of_cells(bus_content){ - let accessed_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(bus_content, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - if accessed_bus.has_assignment(){ - treat_result_with_memory_error( - Result::Err(MemoryError::AssignmentTagAfterInit), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? - } - } - - if let Some(a_slice) = r_folded.arithmetic_slice { - let value = AExpressionSlice::unwrap_to_single(a_slice); - match value { - ArithmeticExpressionGen::Number { value } => { - let possible_tag = reference_to_tags.get(&tag.clone()); - if let Some(val) = possible_tag { - if let Some(_) = val { - treat_result_with_memory_error( - Result::Err(MemoryError::AssignmentTagTwice), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )? - } else { // we add the info saying that the tag is defined - reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); - let tag_state = reference_to_tags_defined.get_mut(tag).unwrap(); - tag_state.value_defined = true; - match actual_node{ - ExecutedStructure::Template(node) =>{ - node.add_tag_signal(symbol, &tag, Some(value)); - }, - ExecutedStructure::Bus(node) =>{ - node.add_tag_signal(symbol, &tag, Some(value)); - }, - ExecutedStructure::None => { - unreachable!(); - } - } - } - } else {unreachable!()} - }, - _ => unreachable!(), - } - } - else { - unreachable!() - } - } else{ - // in case it is a tag of one its fields - let mut value_left = treat_result_with_memory_error( - BusSlice::access_values_by_mut_reference(bus_slice, &accessing_information.array_access), + assert!(accessing_information.field_access.is_some()); + let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); + let value_aux = AExpressionSlice::unwrap_to_single(arithmetic_slice); + let value = if let ArithmeticExpressionGen::Number { value } = value_aux { + value + } else { + treat_result_with_execution_error( + Result::Err(ExecutionError::NonValidTagAssignment), meta, &mut runtime.runtime_errors, &runtime.call_trace, - )?; - - assert!(value_left.len() == 1); - let single_bus = value_left.get_mut(0).unwrap(); - - - assert!(accessing_information.field_access.is_some()); - let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); - let value_aux = AExpressionSlice::unwrap_to_single(arithmetic_slice); - let value = if let ArithmeticExpressionGen::Number { value } = value_aux { - value - } else { - unreachable!(); - }; - let memory_response = single_bus.assign_value_to_field( - accessing_information.field_access.as_ref().unwrap(), - accessing_information.remaining_access.as_ref().unwrap(), - FoldedArgument::Tag(&value), - None, - false - ); - treat_result_with_memory_error_void( - memory_response, + )? + }; + + let mut ref_to_tags_info = tags_info; + let mut to_access = accessing_information; + while to_access.remaining_access.is_some(){ + ref_to_tags_info = ref_to_tags_info.fields.get_mut(to_access.field_access.as_ref().unwrap()).unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); + } + + if ref_to_tags_info.is_init{ + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagAfterInit), meta, &mut runtime.runtime_errors, &runtime.call_trace, - )?; + )? } + + let tag_name = to_access.field_access.as_ref().unwrap(); + let possible_tag = ref_to_tags_info.tags.get_mut(tag_name); + if let Some(val) = possible_tag { + if let Some(_) = val { + treat_result_with_memory_error( + Result::Err(MemoryError::AssignmentTagTwice), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )? + } else { // we add the info saying that the tag is defined + ref_to_tags_info.tags.insert(tag_name.clone(), Option::Some(value.clone())); + let tag_state = ref_to_tags_info.definitions.get_mut(tag_name).unwrap(); + tag_state.value_defined = true; + } + } None } else{ unreachable!(); @@ -2194,25 +2193,17 @@ fn perform_assign( // case assigning a bus (complete or field) if accessing_information.field_access.is_none(){ - // We assign the tags - if r_folded.tags.is_some(){ - - let mut bus_is_init = false; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - let accessed_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(bus_slice, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - bus_is_init |= accessed_bus.has_assignment(); - } - - // Perform the tag assignment - let new_tags = r_folded.tags.unwrap(); - perform_tag_propagation(tags_info, tags_definition, &new_tags, bus_is_init); - + // Perform the tag propagation + // access to the field that is assigned and then propagate the tags + let new_tags = r_folded.tags.unwrap(); + + let mut to_access = accessing_information; + let mut tag_data = tags_info; + while to_access.remaining_access.is_some(){ + tag_data = tag_data.fields.get_mut(to_access.field_access.as_ref().unwrap()).unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); } + perform_tag_propagation_bus(tag_data, &new_tags, MemorySlice::get_number_of_cells(&bus_slice)); // We assign the original buses let bus_assignment_response = perform_bus_assignment(bus_slice, &accessing_information.array_access, assigned_bus_slice, false); @@ -2275,37 +2266,6 @@ fn perform_assign( ae_signals_right.push(AExpr::Signal { symbol: signal_name }); } - // Update the final tags - let mut bus_is_completely_init = true; - for i in 0..BusSlice::get_number_of_cells(bus_slice){ - let accessed_bus = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(bus_slice, i), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - bus_is_completely_init &= accessed_bus.has_assignment(); - } - if bus_is_completely_init{ - for (tag, value) in tags_info{ - let tag_state = tags_definition.get_mut(tag).unwrap(); - tag_state.complete = true; - match actual_node{ - ExecutedStructure::Template(node) =>{ - if !tag_state.value_defined{ - node.add_tag_signal(symbol, &tag, value.clone()); - } - }, - ExecutedStructure::Bus(_) =>{ - unreachable!(); - }, - ExecutedStructure::None => { - unreachable!(); - } - } - } - } - // Update the left slice let l_slice = AExpressionSlice::new_array([ae_signals_left.len()].to_vec(), ae_signals_left); let r_slice = AExpressionSlice::new_array([ae_signals_right.len()].to_vec(), ae_signals_right); @@ -2326,17 +2286,23 @@ fn perform_assign( assert!(accessing_information.field_access.is_some()); let (name_bus, bus_slice) = r_folded.bus_slice.as_ref().unwrap(); - let tags = if r_folded.tags.is_some() { - r_folded.tags.unwrap() - } else { - TagInfo::new() - }; + + // Perform the tag propagation + // access to the field that is assigned and then propagate the tags + let new_tags = r_folded.tags.unwrap(); + + let mut to_access = accessing_information; + let mut tag_data = tags_info; + while to_access.remaining_access.is_some(){ + tag_data = tag_data.fields.get_mut(to_access.field_access.as_ref().unwrap()).unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); + } + perform_tag_propagation_bus(tag_data, &new_tags, BusSlice::get_number_of_cells(&bus_slice)); let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), FoldedArgument::Bus(bus_slice), - Some(tags), false ); treat_result_with_memory_error_void( @@ -2625,7 +2591,11 @@ fn execute_variable( &mut runtime.runtime_errors, &runtime.call_trace, )?; - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), tags: Option::Some(var_tag.clone()), ..FoldedValue::default() }) + let tags = TagWire{ + tags: var_tag.clone(), + fields: None + }; + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), tags: Option::Some(tags), ..FoldedValue::default() }) } fn execute_signal( @@ -2711,10 +2681,13 @@ fn execute_signal( // check which tags are propagated let tags_propagated = compute_propagated_tags(tags, tags_definitions); - + let tags = TagWire{ + tags: tags_propagated, + fields: None + }; Result::Ok(FoldedValue { arithmetic_slice: Option::Some(arith_slice), - tags: Option::Some(tags_propagated), + tags: Option::Some(tags), ..FoldedValue::default() }) } @@ -2756,13 +2729,19 @@ fn execute_bus( flags: FlagsExecution ) -> Result { let access_information = treat_accessing_bus(meta, access, program_archive, runtime, flags)?; + + let is_tag = match meta.get_type_knowledge().get_reduces_to(){ + TypeReduction::Tag => true, + _ => false + }; + if access_information.undefined { let arithmetic_slice = Option::Some(AExpressionSlice::new(&AExpr::NonQuadratic)); return Result::Ok(FoldedValue { arithmetic_slice, ..FoldedValue::default() }); } let environment_response = ExecutionEnvironment::get_bus_res(&runtime.environment, symbol); - let (tags, tags_definitions, bus_slice) = treat_result_with_environment_error( + let (tag_data, bus_slice) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, @@ -2783,8 +2762,8 @@ fn execute_bus( let symbol = create_symbol_bus(symbol, &access_information); // Compute which tags are propagated - let tags_propagated = compute_propagated_tags(tags, tags_definitions); - + let tags_propagated = compute_propagated_tags_bus(&tag_data); + // Check that all the buses are completely assigned for i in 0..BusSlice::get_number_of_cells(&bus_slice){ @@ -2804,16 +2783,27 @@ fn execute_bus( )?; } } + Result::Ok(FoldedValue{bus_slice: Some((symbol.to_string(), bus_slice)), tags: Some(tags_propagated), ..FoldedValue::default()}) - } else if tags.contains_key(access_information.field_access.as_ref().unwrap()){ - // case tags - let acc = access_information.field_access.unwrap(); - let value_tag = tags.get(&acc).unwrap(); - let state = tags_definitions.get(&acc).unwrap(); + } else if is_tag{ + // in this case we access to the value of a tag (of the complete bus or a field) + let mut to_do_access = &access_information; + let mut ref_tag_data = tag_data; + // we perform all the field accesses + while to_do_access.remaining_access.is_some(){ + let field = to_do_access.field_access.as_ref().unwrap(); + ref_tag_data = ref_tag_data.fields.get(field).unwrap(); + to_do_access = to_do_access.remaining_access.as_ref().unwrap(); + } + // the last access is the tag access + let tag_access = to_do_access.field_access.as_ref().unwrap(); + let value_tag = tag_data.tags.get(tag_access).unwrap(); + let is_complete = tag_data.remaining_inserts == 0; + let state = tag_data.definitions.get(tag_access).unwrap(); if let Some(value_tag) = value_tag { // tag has value // access only allowed when (1) it is value defined by user or (2) it is completely assigned - if state.value_defined || state.complete{ + if state.value_defined || is_complete{ let a_value = AExpr::Number { value: value_tag.clone() }; let ae_slice = AExpressionSlice::new(&a_value); Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) @@ -2825,8 +2815,7 @@ fn execute_bus( &mut runtime.runtime_errors, &runtime.call_trace, )? - } - + } } else { let error = MemoryError::TagValueNotInitializedAccess; @@ -2837,9 +2826,8 @@ fn execute_bus( &runtime.call_trace, )? } - } else{ - // access to the field or tag of a field + // access to a field let resulting_bus = safe_unwrap_to_single(bus_slice, line!()); let symbol = create_symbol_bus(symbol, &access_information); @@ -2849,21 +2837,34 @@ fn execute_bus( let remaining_access = access_information.remaining_access.as_ref().unwrap(); - let (tags, result) = treat_result_with_memory_error( + let result= treat_result_with_memory_error( resulting_bus.get_field(field_name, remaining_access), meta, &mut runtime.runtime_errors, - &runtime.call_trace, + &runtime.call_trace, )?; + // get the tags from the environment + let mut to_do_access = &access_information; + let mut ref_tag_data = tag_data; + // we perform all the field accesses + while to_do_access.field_access.is_some(){ + let field = to_do_access.field_access.as_ref().unwrap(); + ref_tag_data = ref_tag_data.fields.get(field).unwrap(); + to_do_access = to_do_access.remaining_access.as_ref().unwrap(); + } + // Compute which tags are propagated + let tags_propagated = compute_propagated_tags_bus(&tag_data); + // match the result and generate the output match result{ FoldedResult::Signal(signals) =>{ // Generate signal slice and check that all assigned + let result = signal_to_arith(symbol, signals) .map(|s| FoldedValue { arithmetic_slice: Option::Some(s), - tags: Option::Some(tags.unwrap()), + tags: Option::Some(tags_propagated), ..FoldedValue::default() }); treat_result_with_memory_error( @@ -2895,18 +2896,11 @@ fn execute_bus( } Ok(FoldedValue { bus_slice: Option::Some((symbol, buses)), - tags: Option::Some(tags.unwrap()), + tags: Option::Some(tags_propagated), ..FoldedValue::default() }) }, - FoldedResult::Tag(value) =>{ - // return the tag value - let a_value = AExpr::Number { value }; - let ae_slice = AExpressionSlice::new(&a_value); - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - - } } } @@ -2965,7 +2959,7 @@ fn execute_component( let result = signal_to_arith(symbol, signals) .map(|s| FoldedValue { arithmetic_slice: Option::Some(s), - tags: Option::Some(tags.unwrap()), + tags: Option::Some(tags), ..FoldedValue::default() }); treat_result_with_memory_error( @@ -2997,16 +2991,10 @@ fn execute_component( } Ok(FoldedValue { bus_slice: Option::Some((symbol, buses)), - tags: Option::Some(tags.unwrap()), + tags: Option::Some(tags), ..FoldedValue::default() }) - }, - FoldedResult::Tag(value) =>{ - let a_value = AExpr::Number { value }; - let ae_slice = AExpressionSlice::new(&a_value); - Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - } } @@ -3080,7 +3068,7 @@ fn execute_function_call( fn execute_template_call( id: &str, parameter_values: Vec, - tag_values: BTreeMap, + tag_values: HashMap, program_archive: &ProgramArchive, runtime: &mut RuntimeInformation, flags: FlagsExecution @@ -3101,7 +3089,8 @@ fn execute_template_call( args_to_values.insert(name.clone(), value.clone()); } for (_input, input_tags) in &tag_values{ - for (_tag, value) in input_tags { + // TODO: does not got inside bus + for (_tag, value) in &input_tags.tags { if value.is_none(){ instantiation_name.push_str("null,"); } @@ -3156,8 +3145,24 @@ fn execute_template_call( }, Ok(_) => {}, } + let mut new_node = node_wrap.unwrap(); + + + // we add the tags to the executed template + // TODO: improve and remove clone + let outputs = new_node.outputs.clone(); + for output in outputs{ + let to_add = if output.is_bus{ + environment_get_value_tags_bus(&runtime.environment, &output.name) + } else{ + environment_get_value_tags_signal(&runtime.environment, &output.name) + }; + for (name, value) in to_add{ + new_node.add_tag_signal(name, value); + } + } + - let new_node = node_wrap.unwrap(); let analysis = std::mem::replace(&mut runtime.analysis, analysis); let node_pointer = runtime.exec_program.add_node_to_scheme(new_node, analysis); node_pointer @@ -3171,6 +3176,35 @@ fn preexecute_template_call( program_archive: &ProgramArchive, runtime: &mut RuntimeInformation, ) -> Result { + + pub fn collect_tag_info( + bus_data: &BusData, + program_archive: &ProgramArchive, + )-> HashMap{ + let mut bus_fields_tags = HashMap::new(); + for (field_name, field_info) in bus_data.get_fields(){ + let tags = field_info.get_tags(); + + let fields = match field_info.get_type() { + WireType::Signal => { + None + }, + WireType::Bus(bus_name) =>{ + let bus_data = program_archive.get_bus_data(&bus_name); + let info = collect_tag_info(bus_data, program_archive); + Some(info) + } + }; + let tag_name = TagNames{ + tag_names: tags.clone(), + fields + }; + bus_fields_tags.insert(field_name.clone(), tag_name); + } + bus_fields_tags + + } + debug_assert!(runtime.block_type == BlockType::Known); let inputs = program_archive.get_template_data(id).get_inputs(); let outputs = program_archive.get_template_data(id).get_outputs(); @@ -3180,11 +3214,45 @@ fn preexecute_template_call( for (name, info_input) in inputs { - inputs_to_tags.insert(name.clone(), info_input.get_tags().clone()); + let tags = info_input.get_tags().clone(); + + let fields = match info_input.get_type() { + WireType::Signal => { + None + }, + WireType::Bus(bus_name) =>{ + let bus_data = program_archive.get_bus_data(&bus_name); + Some(collect_tag_info(bus_data, program_archive)) + } + }; + inputs_to_tags.insert( + name.clone(), + TagNames{ + tag_names: tags, + fields + } + ); } for (name, info_output) in outputs { - outputs_to_tags.insert(name.clone(), info_output.get_tags().clone()); + let tags = info_output.get_tags().clone(); + + let fields = match info_output.get_type() { + WireType::Signal => { + None + }, + WireType::Bus(bus_name) =>{ + let bus_data = program_archive.get_bus_data(&bus_name); + Some(collect_tag_info(bus_data, program_archive)) + } + }; + outputs_to_tags.insert( + name.clone(), + TagNames{ + tag_names: tags, + fields + } + ); } let node_wrap = Option::Some(PreExecutedTemplate::new( @@ -3245,7 +3313,6 @@ fn execute_bus_call( flags, )?; - let analysis = std::mem::replace(&mut runtime.analysis, analysis); let node_pointer = runtime.exec_program.add_bus_node_to_scheme(node, analysis); node_pointer @@ -3393,8 +3460,8 @@ fn cast_index(ae_index: &AExpr) -> Option { return Option::None; } match AExpr::get_usize(ae_index) { - Some(index) => { Option::Some(index) }, - None => { Option::None }, + Option::Some(index) => { Option::Some(index) }, + Option::None => { Option::None }, } } @@ -3973,3 +4040,6 @@ fn add_report_to_runtime( report.add_note(trace); runtime_errors.push(report); } + + + diff --git a/constraint_generation/src/execution_data/executed_bus.rs b/constraint_generation/src/execution_data/executed_bus.rs index ac1a12523..b474d6b28 100644 --- a/constraint_generation/src/execution_data/executed_bus.rs +++ b/constraint_generation/src/execution_data/executed_bus.rs @@ -1,8 +1,6 @@ use super::type_definitions::*; -use num_bigint::BigInt; use std::collections::{HashMap, BTreeMap}; -use crate::execution_data::TagInfo; use compiler::hir::very_concrete_program::*; @@ -20,10 +18,10 @@ pub struct ExecutedBus { pub report_name: String, pub fields: WireCollector, pub parameter_instances: ParameterContext, - pub signal_to_tags: TagContext, pub bus_connexions: HashMap, pub size: usize, pub bus_id: Option, + pub tag_names: HashMap>, } impl ExecutedBus { @@ -37,10 +35,10 @@ impl ExecutedBus { bus_name: name, parameter_instances: instance, fields: Vec::new(), - signal_to_tags: TagContext::new(), bus_connexions: HashMap::new(), size: 0, bus_id: None, + tag_names: HashMap::new(), } } @@ -68,7 +66,7 @@ impl ExecutedBus { self.bus_connexions.insert(component_name, cnn); } - pub fn add_signal(&mut self, signal_name: &str, dimensions: &[usize]) { + pub fn add_signal(&mut self, signal_name: &str, dimensions: &[usize], tags: Vec) { let info_signal = WireData{ name: signal_name.to_string(), length: dimensions.to_vec(), @@ -79,27 +77,19 @@ impl ExecutedBus { for v in dimensions{ total_size *= v; } + self.tag_names.insert(signal_name.to_string(), tags); self.size += total_size; } - pub fn add_bus(&mut self, bus_name: &str, dimensions: &[usize]) { + pub fn add_bus(&mut self, bus_name: &str, dimensions: &[usize], tags: Vec) { let info_bus = WireData{ name: bus_name.to_string(), length: dimensions.to_vec(), is_bus: true }; self.fields.push(info_bus); - } + self.tag_names.insert(bus_name.to_string(), tags); - pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ - let tags_signal = self.signal_to_tags.get_mut(signal_name); - if tags_signal.is_none(){ - let mut new_tags_signal = TagInfo::new(); - new_tags_signal.insert(tag_name.to_string(), value); - self.signal_to_tags.insert(signal_name.to_string(), new_tags_signal); - } else { - tags_signal.unwrap().insert(tag_name.to_string(), value); - } } pub fn bus_name(&self) -> &String { @@ -179,6 +169,4 @@ impl ExecutedBus { } } - - } \ No newline at end of file diff --git a/constraint_generation/src/execution_data/executed_program.rs b/constraint_generation/src/execution_data/executed_program.rs index f9ed7059a..1852338d5 100644 --- a/constraint_generation/src/execution_data/executed_program.rs +++ b/constraint_generation/src/execution_data/executed_program.rs @@ -34,7 +34,7 @@ impl ExecutedProgram { } } - pub fn identify_node(&self, name: &str, context: &ParameterContext, tag_context: &TagContext) -> Option { + pub fn identify_node(&self, name: &str, context: &ParameterContext, tag_context: &HashMap) -> Option { if !self.template_to_nodes.contains_key(name) { return Option::None; } diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index d4e6651b0..4809613bd 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -8,7 +8,6 @@ use num_bigint::BigInt; use program_structure::ast::{SignalType, Statement}; use std::collections::{HashMap, HashSet}; use crate::execution_data::AExpressionSlice; -use crate::execution_data::TagInfo; struct Connexion { @@ -24,16 +23,16 @@ struct Connexion { pub struct PreExecutedTemplate { pub template_name: String, pub parameter_instances: Vec, - pub inputs: HashMap>, - pub outputs: HashMap>, + pub inputs: HashMap, + pub outputs: HashMap, } impl PreExecutedTemplate { pub fn new( name: String, instance: Vec, - inputs: HashMap>, - outputs: HashMap>, + inputs: HashMap, + outputs: HashMap, ) -> PreExecutedTemplate { PreExecutedTemplate { template_name: name, @@ -51,11 +50,11 @@ impl PreExecutedTemplate { &self.parameter_instances } - pub fn inputs(&self) -> &HashMap> { + pub fn inputs(&self) -> &HashMap{ &self.inputs } - pub fn outputs(&self) -> &HashMap> { + pub fn outputs(&self) -> &HashMap { &self.outputs } } @@ -75,8 +74,10 @@ pub struct ExecutedTemplate { pub number_of_components: usize, pub public_inputs: HashSet, pub parameter_instances: ParameterContext, - pub tag_instances: TagContext, - pub signal_to_tags: TagContext, + pub tag_instances: HashMap, + pub signal_to_tags: HashMap, BigInt>, + // only store the info of the tags with value + // name of tag -> value pub is_parallel: bool, pub has_parallel_sub_cmp: bool, pub is_custom_gate: bool, @@ -91,12 +92,14 @@ impl ExecutedTemplate { name: String, report_name: String, instance: ParameterContext, - tag_instances: TagContext, + tag_instances: HashMap, code: Statement, is_parallel: bool, is_custom_gate: bool ) -> ExecutedTemplate { let public_inputs: HashSet<_> = public.iter().cloned().collect(); + + ExecutedTemplate { report_name, public_inputs, @@ -106,7 +109,7 @@ impl ExecutedTemplate { code: code.clone(), template_name: name, parameter_instances: instance, - signal_to_tags: tag_instances.clone(), + signal_to_tags: HashMap::new(), tag_instances, inputs: WireCollector::new(), outputs: WireCollector::new(), @@ -121,7 +124,7 @@ impl ExecutedTemplate { } } - pub fn is_equal(&self, name: &str, context: &ParameterContext, tag_context: &TagContext) -> bool { + pub fn is_equal(&self, name: &str, context: &ParameterContext, tag_context: &HashMap) -> bool { self.template_name == name && self.parameter_instances == *context && self.tag_instances == *tag_context @@ -139,7 +142,12 @@ impl ExecutedTemplate { self.bus_connexions.insert(bus_name, cnn); } - pub fn add_input(&mut self, input_name: &str, dimensions: &[usize], is_bus: bool) { + pub fn add_input( + &mut self, + input_name: &str, + dimensions: &[usize], + is_bus: bool + ) { let wire_info = WireData{ name: input_name.to_string(), length: dimensions.to_vec(), @@ -149,7 +157,12 @@ impl ExecutedTemplate { self.ordered_signals.push(wire_info); } - pub fn add_output(&mut self, output_name: &str, dimensions: &[usize], is_bus: bool) { + pub fn add_output( + &mut self, + output_name: &str, + dimensions: &[usize], + is_bus: bool + ) { let wire_info = WireData{ name: output_name.to_string(), length: dimensions.to_vec(), @@ -159,7 +172,12 @@ impl ExecutedTemplate { self.ordered_signals.push(wire_info); } - pub fn add_intermediate(&mut self, intermediate_name: &str, dimensions: &[usize], is_bus: bool) { + pub fn add_intermediate( + &mut self, + intermediate_name: &str, + dimensions: &[usize], + is_bus: bool + ) { let wire_info = WireData{ name: intermediate_name.to_string(), length: dimensions.to_vec(), @@ -169,15 +187,15 @@ impl ExecutedTemplate { self.ordered_signals.push(wire_info); } - pub fn add_tag_signal(&mut self, signal_name: &str, tag_name: &str, value: Option){ - let tags_signal = self.signal_to_tags.get_mut(signal_name); - if tags_signal.is_none(){ - let mut new_tags_signal = TagInfo::new(); - new_tags_signal.insert(tag_name.to_string(), value); - self.signal_to_tags.insert(signal_name.to_string(), new_tags_signal); - } else { - tags_signal.unwrap().insert(tag_name.to_string(), value); - } + // Used to update the values of the signals + // We call to this function to store the signals with values + // when we finish the execution of a template + pub fn add_tag_signal( + &mut self, + signal_name: Vec, + value: BigInt + ){ + self.signal_to_tags.insert(signal_name, value); } pub fn add_component(&mut self, component_name: &str, dimensions: &[usize]) { @@ -201,7 +219,7 @@ impl ExecutedTemplate { &self.parameter_instances } - pub fn tag_instances(&self) -> &TagContext { + pub fn tag_instances(&self) -> &HashMap { &self.tag_instances } diff --git a/constraint_generation/src/execution_data/mod.rs b/constraint_generation/src/execution_data/mod.rs index b471a0035..bd7fa81a9 100644 --- a/constraint_generation/src/execution_data/mod.rs +++ b/constraint_generation/src/execution_data/mod.rs @@ -1,4 +1,4 @@ -use super::environment_utils::slice_types::{AExpressionSlice, TagInfo}; +use super::environment_utils::slice_types::AExpressionSlice; use circom_algebra::algebra::Constraint; pub use executed_program::ExecutedProgram; pub use executed_template::{PreExecutedTemplate, ExecutedTemplate}; diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index 5086ea02d..afdaee42b 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -2,13 +2,28 @@ use super::AExpressionSlice; use super::Constraint as ConstraintGen; use std::collections::BTreeMap; use num_bigint_dig::BigInt; +use std::collections::HashSet; +use std::collections::HashMap; pub type NodePointer = usize; pub type Constraint = ConstraintGen; pub type ParameterContext = BTreeMap; -pub type TagContext = BTreeMap; pub type TagInfo = BTreeMap>; + +#[derive(Clone)] +pub struct TagNames{ + pub tag_names: HashSet, + pub fields: Option>, +} + +#[derive(Clone, PartialEq, Default)] +pub struct TagWire{ + pub tags: TagInfo, + pub fields: Option>, +} + + // From name to dimensions and if it is bus or not #[derive(Clone)] pub struct WireData{ From 144475781af9e2b017f8c5c062058cf86495d59b Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 17 Oct 2024 18:28:19 +0200 Subject: [PATCH 02/22] solving minor issues tag propagation --- constraint_generation/src/execute.rs | 16 ++++++++++------ .../src/execution_data/type_definitions.rs | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 863166ee9..0ef9c68be 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2154,9 +2154,11 @@ fn perform_assign( let mut ref_to_tags_info = tags_info; let mut to_access = accessing_information; - while to_access.remaining_access.is_some(){ + let mut next_access = accessing_information.remaining_access.as_ref().unwrap(); + while next_access.remaining_access.is_some(){ // it is not the tag access ref_to_tags_info = ref_to_tags_info.fields.get_mut(to_access.field_access.as_ref().unwrap()).unwrap(); to_access = to_access.remaining_access.as_ref().unwrap(); + next_access = next_access.remaining_access.as_ref().unwrap(); } if ref_to_tags_info.is_init{ @@ -2790,17 +2792,19 @@ fn execute_bus( // in this case we access to the value of a tag (of the complete bus or a field) let mut to_do_access = &access_information; let mut ref_tag_data = tag_data; - // we perform all the field accesses - while to_do_access.remaining_access.is_some(){ + let mut next_access = access_information.remaining_access.as_ref().unwrap(); + // we perform all the field accesses, we stop in the previous one to the tag + while next_access.remaining_access.is_some(){ let field = to_do_access.field_access.as_ref().unwrap(); ref_tag_data = ref_tag_data.fields.get(field).unwrap(); to_do_access = to_do_access.remaining_access.as_ref().unwrap(); + next_access = next_access.remaining_access.as_ref().unwrap(); } // the last access is the tag access let tag_access = to_do_access.field_access.as_ref().unwrap(); - let value_tag = tag_data.tags.get(tag_access).unwrap(); - let is_complete = tag_data.remaining_inserts == 0; - let state = tag_data.definitions.get(tag_access).unwrap(); + let value_tag = ref_tag_data.tags.get(tag_access).unwrap(); + let is_complete = ref_tag_data.remaining_inserts == 0; + let state = ref_tag_data.definitions.get(tag_access).unwrap(); if let Some(value_tag) = value_tag { // tag has value // access only allowed when (1) it is value defined by user or (2) it is completely assigned if state.value_defined || is_complete{ diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index afdaee42b..8c90e20f7 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -55,7 +55,7 @@ pub struct BusData { pub remaining_access: Option, // may not appear } */ -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct AccessingInformationBus { pub undefined: bool, pub array_access: Vec, From a6c0d26d8c3c216530d9afe82b1863a892448719 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Thu, 17 Oct 2024 18:51:19 +0200 Subject: [PATCH 03/22] solving minors --- constraint_generation/src/assignment_utils.rs | 1 + .../src/environment_utils/environment.rs | 2 +- .../src/environment_utils/slice_types.rs | 9 ++++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index e0f43f094..8ba178bd1 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -121,6 +121,7 @@ pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut pub fn perform_tag_propagation_bus(tag_data: &mut BusTagInfo, assigned_tags: &TagWire, n_inserts: usize){ perform_tag_propagation(&mut tag_data.tags, &mut tag_data.definitions, &assigned_tags.tags, tag_data.is_init); tag_data.remaining_inserts -= n_inserts; + tag_data.is_init = true; for (field_name, field_data) in &mut tag_data.fields{ let aux = assigned_tags.fields.as_ref().unwrap(); let field_assigned = aux.get(field_name).unwrap(); diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index 4a96c6a0d..593c175f4 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -195,7 +195,7 @@ pub fn environment_get_value_tags_bus(environment: &ExecutionEnvironment, name: for (tag, value) in &tag_data.tags{ if value.is_some(){ let state = tag_data.definitions.get(tag).unwrap(); - if state.defined && (state.value_defined || state.complete){ + if state.defined && (state.value_defined || tag_data.remaining_inserts == 0){ let mut aux = name.clone(); aux.push(tag.clone()); to_add.push((aux, value.clone().unwrap())); diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index 7cf6c02cc..ed1693c24 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -15,7 +15,14 @@ pub struct TagState{ pub type TagInfo = BTreeMap>; pub type TagDefinitions = BTreeMap; // the tags defined for each signal and if the info about their state -#[derive(Debug, Clone)] +pub struct SignalTagInfo{ + pub tags: TagInfo, + pub definitions: TagDefinitions, + pub remaining_inserts: usize, + pub is_init: bool, +} + +#[derive(Clone)] pub struct BusTagInfo{ pub tags: TagInfo, pub definitions: TagDefinitions, From 29dc92928911926096868da2ea5b46a74e31e075 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 18 Oct 2024 00:34:15 +0200 Subject: [PATCH 04/22] minor -> moving complete from definitions to field in SignalTagInfo --- constraint_generation/src/assignment_utils.rs | 16 ++++-- .../src/environment_utils/environment.rs | 54 +++++++++++++------ .../src/environment_utils/slice_types.rs | 2 +- constraint_generation/src/execute.rs | 52 ++++++------------ 4 files changed, 68 insertions(+), 56 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index 8ba178bd1..ede82f0bb 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -11,7 +11,11 @@ use std::collections::HashMap; // Utils for assigning tags pub fn compute_propagated_tags_bus(tag_data: &BusTagInfo) -> TagWire{ - let tags_propagated = compute_propagated_tags(&tag_data.tags, &tag_data.definitions); + let tags_propagated = compute_propagated_tags( + &tag_data.tags, + &tag_data.definitions, + tag_data.remaining_inserts + ); let mut fields_propagated = HashMap::new(); for (field_name, field_tags) in &tag_data.fields{ fields_propagated.insert(field_name.clone(), compute_propagated_tags_bus(field_tags)); @@ -22,11 +26,15 @@ pub fn compute_propagated_tags_bus(tag_data: &BusTagInfo) -> TagWire{ } } -pub fn compute_propagated_tags(tags_values: &TagInfo, tags_definitions: &TagDefinitions)-> TagInfo{ +pub fn compute_propagated_tags( + tags_values: &TagInfo, + tags_definitions: &TagDefinitions, + remaining_inserts: usize +)-> TagInfo{ let mut tags_propagated = TagInfo::new(); for (tag, value) in tags_values{ let state = tags_definitions.get(tag).unwrap(); - if state.value_defined || state.complete{ + if state.value_defined || remaining_inserts == 0{ tags_propagated.insert(tag.clone(), value.clone()); } else if state.defined{ tags_propagated.insert(tag.clone(), None); @@ -110,7 +118,7 @@ pub fn perform_tag_propagation(tags_values: &mut TagInfo, tags_definitions: &mut for (tag, value) in assigned_tags{ if !tags_values.contains_key(tag){ // in case it is a new tag (not defined by user) tags_values.insert(tag.clone(), value.clone()); - let state = TagState{defined: false, value_defined: false, complete: false}; + let state = TagState{defined: false, value_defined: false}; tags_definitions.insert(tag.clone(), state); } } diff --git a/constraint_generation/src/environment_utils/environment.rs b/constraint_generation/src/environment_utils/environment.rs index 593c175f4..8625cb3f4 100644 --- a/constraint_generation/src/environment_utils/environment.rs +++ b/constraint_generation/src/environment_utils/environment.rs @@ -9,7 +9,8 @@ use super::slice_types::{ TagDefinitions, TagState, BusSlice, - BusTagInfo + BusTagInfo, + SignalTagInfo }; use super::{ArithmeticExpression, CircomEnvironment, CircomEnvironmentError}; use program_structure::memory_slice::MemoryError; @@ -20,7 +21,7 @@ use crate::environment_utils::slice_types::BigInt; pub type ExecutionEnvironmentError = CircomEnvironmentError; -pub type ExecutionEnvironment = CircomEnvironment; +pub type ExecutionEnvironment = CircomEnvironment; pub fn environment_shortcut_add_component( environment: &mut ExecutionEnvironment, @@ -40,10 +41,17 @@ pub fn environment_shortcut_add_input( let slice = SignalSlice::new_with_route(dimensions, &true); let mut tags_defined = TagDefinitions::new(); for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: true}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } - - environment.add_input(input_name, (tags.clone(), tags_defined, slice)); + let tag_info = SignalTagInfo{ + tags: tags.clone(), + definitions: tags_defined, + remaining_inserts: 0, + is_init: true + }; + + + environment.add_input(input_name, (tag_info, slice)); } pub fn environment_shortcut_add_output( environment: &mut ExecutionEnvironment, @@ -54,9 +62,16 @@ pub fn environment_shortcut_add_output( let slice = SignalSlice::new_with_route(dimensions, &false); let mut tags_defined = TagDefinitions::new(); for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } - environment.add_output(output_name, (tags.clone(), tags_defined, slice)); + let size = dimensions.iter().fold(1, |acc, dim| acc * dim); + let tag_info = SignalTagInfo{ + tags: tags.clone(), + definitions: tags_defined, + remaining_inserts: size, + is_init: false + }; + environment.add_output(output_name, (tag_info, slice)); } pub fn environment_shortcut_add_intermediate( environment: &mut ExecutionEnvironment, @@ -67,9 +82,16 @@ pub fn environment_shortcut_add_intermediate( let slice = SignalSlice::new_with_route(dimensions, &false); let mut tags_defined = TagDefinitions::new(); for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } - environment.add_intermediate(intermediate_name, (tags.clone(), tags_defined, slice)); + let size = dimensions.iter().fold(1, |acc, dim| acc * dim); + let tag_info = SignalTagInfo{ + tags: tags.clone(), + definitions: tags_defined, + remaining_inserts: size, + is_init: false + }; + environment.add_intermediate(intermediate_name, (tag_info, slice)); } pub fn environment_shortcut_add_bus_input( environment: &mut ExecutionEnvironment, @@ -81,7 +103,7 @@ pub fn environment_shortcut_add_bus_input( let mut tags_defined = TagDefinitions::new(); for (t, value) in &tags.tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: true}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } let mut fields = BTreeMap::new(); if tags.fields.is_some(){ @@ -116,7 +138,7 @@ pub fn environment_shortcut_add_bus_output( let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); let mut tags_defined = TagDefinitions::new(); for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } let size = dimensions.iter().fold(1, |aux, val| aux * val); let tag_info= BusTagInfo{ @@ -138,7 +160,7 @@ pub fn environment_shortcut_add_bus_intermediate( let slice = BusSlice::new_with_route(dimensions, &BusRepresentation::default()); let mut tags_defined = TagDefinitions::new(); for (t, value) in tags{ - tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some(), complete: false}); + tags_defined.insert(t.clone(), TagState{defined:true, value_defined: value.is_some()}); } let size = dimensions.iter().fold(1, |aux, val| aux * val); @@ -177,11 +199,11 @@ pub fn environment_check_all_components_assigned(environment: &ExecutionEnvironm pub fn environment_get_value_tags_signal(environment: &ExecutionEnvironment, name: &String) -> Vec<(Vec, BigInt)>{ let mut to_add = Vec::new(); - let (tags, definitions, _) = environment.get_signal(name).unwrap(); - for (tag, value) in tags{ + let (tag_data, _) = environment.get_signal(name).unwrap(); + for (tag, value) in &tag_data.tags{ if value.is_some(){ - let state = definitions.get(tag).unwrap(); - if state.defined && (state.value_defined || state.complete){ + let state = tag_data.definitions.get(tag).unwrap(); + if state.defined && (state.value_defined || tag_data.remaining_inserts == 0){ to_add.push((vec![name.clone(), tag.clone()], value.clone().unwrap())); } } diff --git a/constraint_generation/src/environment_utils/slice_types.rs b/constraint_generation/src/environment_utils/slice_types.rs index ed1693c24..9d6d44e3a 100644 --- a/constraint_generation/src/environment_utils/slice_types.rs +++ b/constraint_generation/src/environment_utils/slice_types.rs @@ -10,11 +10,11 @@ use std::collections::BTreeMap; pub struct TagState{ pub defined: bool, // if it appears in the definition of the signal pub value_defined: bool, // if the value is given by the user - pub complete: bool, // if the signal is completely initialized } pub type TagInfo = BTreeMap>; pub type TagDefinitions = BTreeMap; // the tags defined for each signal and if the info about their state +#[derive(Clone)] pub struct SignalTagInfo{ pub tags: TagInfo, pub definitions: TagDefinitions, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 0ef9c68be..cd89103ac 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1448,7 +1448,7 @@ fn perform_assign( let tag = accessing_information.signal_access.clone().unwrap(); let environment_response = ExecutionEnvironment::get_mut_signal_res(&mut runtime.environment, symbol); - let (reference_to_tags, reference_to_tags_defined, reference_to_signal_content) = treat_result_with_environment_error( + let (reference_to_tags, reference_to_signal_content) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, @@ -1475,7 +1475,7 @@ fn perform_assign( &runtime.call_trace, )? }; - let possible_tag = reference_to_tags.get(&tag.clone()); + let possible_tag = reference_to_tags.tags.get(&tag.clone()); if let Some(val) = possible_tag { if let Some(_) = val { treat_result_with_memory_error( @@ -1485,8 +1485,8 @@ fn perform_assign( &runtime.call_trace, )? } else { // we add the info saying that the tag is defined - reference_to_tags.insert(tag.clone(), Option::Some(value.clone())); - let tag_state = reference_to_tags_defined.get_mut(&tag).unwrap(); + reference_to_tags.tags.insert(tag.clone(), Option::Some(value.clone())); + let tag_state = reference_to_tags.definitions.get_mut(&tag).unwrap(); tag_state.value_defined = true; } } else { @@ -1511,7 +1511,7 @@ fn perform_assign( } let environment_response = ExecutionEnvironment::get_mut_signal_res(&mut runtime.environment, symbol); - let (reference_to_tags, reference_to_tags_defined, reference_to_signal_content) = treat_result_with_environment_error( + let (reference_to_tags, reference_to_signal_content) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, @@ -1525,15 +1525,14 @@ fn perform_assign( } else{ TagWire::default() }; + + // Perform the tag propagation + let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); - let signal_is_init = SignalSlice::get_number_of_inserts(reference_to_signal_content) > 0; - - perform_tag_propagation(reference_to_tags, reference_to_tags_defined, &new_tags.tags, signal_is_init); + reference_to_tags.remaining_inserts -= MemorySlice::get_number_of_inserts(&r_slice); + perform_tag_propagation(&mut reference_to_tags.tags, &mut reference_to_tags.definitions, &new_tags.tags, reference_to_tags.is_init); - // Perform the signal assignment - let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); - let signal_assignment_response = perform_signal_assignment(reference_to_signal_content, &accessing_information.before_signal, &r_slice.route()); treat_result_with_memory_error_void( @@ -1543,22 +1542,6 @@ fn perform_assign( &runtime.call_trace, )?; - - // Update complete tags if completely init - let signal_is_completely_initialized = - SignalSlice::get_number_of_inserts(reference_to_signal_content) == - SignalSlice::get_number_of_cells(reference_to_signal_content); - - - - if signal_is_completely_initialized { - - for (tag, _value) in reference_to_tags{ - let tag_state = reference_to_tags_defined.get_mut(tag).unwrap(); - tag_state.complete = true; - } - } - // Get left arithmetic slice let mut l_signal_names = Vec::new(); unfold_signals(full_symbol, 0, r_slice.route(), &mut l_signal_names); @@ -2005,7 +1988,6 @@ fn perform_assign( definitions.insert(tag.clone(), TagState{ defined: true, value_defined: false, - complete: false, }); } // in this case it is a bus, add its fields @@ -2304,7 +2286,7 @@ fn perform_assign( let memory_response = single_bus.assign_value_to_field( accessing_information.field_access.as_ref().unwrap(), accessing_information.remaining_access.as_ref().unwrap(), - FoldedArgument::Bus(bus_slice), + FoldedArgument::Bus(&bus_slice), false ); treat_result_with_memory_error_void( @@ -2624,19 +2606,19 @@ fn execute_signal( } else { unreachable!(); }; - let (tags,tags_definitions, signal_slice) = treat_result_with_environment_error( + let (tag_data, signal_slice) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; if let Some(acc) = access_information.signal_access { - if tags.contains_key(&acc) { - let value_tag = tags.get(&acc).unwrap(); - let state = tags_definitions.get(&acc).unwrap(); + if tag_data.tags.contains_key(&acc) { + let value_tag = tag_data.tags.get(&acc).unwrap(); + let state = tag_data.definitions.get(&acc).unwrap(); if let Some(value_tag) = value_tag { // tag has value // access only allowed when (1) it is value defined by user or (2) it is completely assigned - if state.value_defined || state.complete{ + if state.value_defined || tag_data.remaining_inserts == 0{ let a_value = AExpr::Number { value: value_tag.clone() }; let ae_slice = AExpressionSlice::new(&a_value); Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) @@ -2682,7 +2664,7 @@ fn execute_signal( )?; // check which tags are propagated - let tags_propagated = compute_propagated_tags(tags, tags_definitions); + let tags_propagated = compute_propagated_tags(&tag_data.tags, &tag_data.definitions, tag_data.remaining_inserts); let tags = TagWire{ tags: tags_propagated, fields: None From 51d047034edd3bc8d606ce81f8c24f63d07b471e Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 18 Oct 2024 12:31:42 +0200 Subject: [PATCH 05/22] minors --- constraint_generation/src/execute.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index cd89103ac..de96638fa 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1448,14 +1448,14 @@ fn perform_assign( let tag = accessing_information.signal_access.clone().unwrap(); let environment_response = ExecutionEnvironment::get_mut_signal_res(&mut runtime.environment, symbol); - let (reference_to_tags, reference_to_signal_content) = treat_result_with_environment_error( + let (reference_to_tags, _) = treat_result_with_environment_error( environment_response, meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; - if SignalSlice::get_number_of_inserts(&reference_to_signal_content) > 0{ + if reference_to_tags.is_init{ treat_result_with_memory_error( Result::Err(MemoryError::AssignmentTagAfterInit), meta, @@ -1529,7 +1529,8 @@ fn perform_assign( // Perform the tag propagation let r_slice = safe_unwrap_to_arithmetic_slice(r_folded, line!()); - reference_to_tags.remaining_inserts -= MemorySlice::get_number_of_inserts(&r_slice); + reference_to_tags.remaining_inserts -= MemorySlice::get_number_of_cells(&r_slice); + reference_to_tags.is_init = true; perform_tag_propagation(&mut reference_to_tags.tags, &mut reference_to_tags.definitions, &new_tags.tags, reference_to_tags.is_init); // Perform the signal assignment From 9aed08d7af92dea404bbf35849f57c72ad0eb50d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 18 Oct 2024 12:36:00 +0200 Subject: [PATCH 06/22] removing unused function and data --- program_structure/src/utils/memory_slice.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index c918a1ba6..d392f9d52 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -45,7 +45,6 @@ pub type SimpleSlice = MemorySlice; pub struct MemorySlice { route: Vec, values: Vec, - number_inserts: usize, } impl PartialEq for MemorySlice { @@ -59,7 +58,6 @@ impl Clone for MemorySlice { MemorySlice { route: self.route.clone(), values: self.values.clone(), - number_inserts: self.number_inserts, } } } @@ -201,7 +199,7 @@ impl MemorySlice { offset += 1; } - Result::Ok(MemorySlice { route: size, values, number_inserts: 0 }) + Result::Ok(MemorySlice { route: size, values }) } fn generate_references_from_access<'a>( @@ -265,7 +263,7 @@ impl MemorySlice { MemorySlice::new_with_route(&[], initial_value) } pub fn new_array(route: Vec, values: Vec) -> MemorySlice { - MemorySlice { route, values, number_inserts: 0 } + MemorySlice { route, values } } pub fn new_with_route(route: &[SliceCapacity], initial_value: &C) -> MemorySlice { let mut length = 1; @@ -278,7 +276,7 @@ impl MemorySlice { values.push(initial_value.clone()); } - MemorySlice { route: route.to_vec(), values, number_inserts: 0 } + MemorySlice { route: route.to_vec(), values } } pub fn insert_values( memory_slice: &mut MemorySlice, @@ -290,7 +288,6 @@ impl MemorySlice { Result::Ok(_) => { let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; - memory_slice.number_inserts += MemorySlice::get_number_of_cells(new_values); for value in new_values.values.iter() { memory_slice.values[cell] = value.clone(); cell += 1; @@ -306,7 +303,6 @@ impl MemorySlice { MemorySlice::get_number_of_cells(memory_slice) ); - memory_slice.number_inserts += number_inserts; for i in 0..number_inserts{ memory_slice.values[cell] = new_values.values[i].clone(); cell += 1; @@ -326,7 +322,6 @@ impl MemorySlice { if index > MemorySlice::get_number_of_cells(memory_slice) { return Result::Err(MemoryError::OutOfBoundsError); } - memory_slice.number_inserts += 1; memory_slice.values[index] = new_value; return Result::Ok(()); } @@ -433,9 +428,7 @@ impl MemorySlice { pub fn get_number_of_cells(memory_slice: &MemorySlice) -> SliceCapacity { memory_slice.values.len() } - pub fn get_number_of_inserts(memory_slice: &MemorySlice) -> SliceCapacity { - memory_slice.number_inserts - } + pub fn route(&self) -> &[SliceCapacity] { &self.route } From 95a7116f6c516072ccf668a811553d7e75703ee4 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Fri, 18 Oct 2024 23:20:07 +0200 Subject: [PATCH 07/22] minor, fixing bus prop --- .../src/environment_utils/component_representation.rs | 1 - constraint_generation/src/execute.rs | 5 +++-- constraint_generation/src/execution_data/type_definitions.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 8b686d6c6..bb4b613a8 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -751,7 +751,6 @@ impl ComponentRepresentation { Result::Ok(()) } - check_tags( input_tags, &mut component.unassigned_tags, diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index de96638fa..2a4eb3dfb 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1303,9 +1303,10 @@ fn execute_bus_declaration( if let Some(tags_input) = node.tag_instances().get(bus_name){ environment_shortcut_add_bus_input(environment, bus_name, dimensions, tags_input); } else{ + let tag_wire = TagWire{ tags, - fields: None + fields: None // TODO: FILL THE TAGS }; environment_shortcut_add_bus_input(environment, bus_name, dimensions, &tag_wire); } @@ -2841,7 +2842,7 @@ fn execute_bus( to_do_access = to_do_access.remaining_access.as_ref().unwrap(); } // Compute which tags are propagated - let tags_propagated = compute_propagated_tags_bus(&tag_data); + let tags_propagated = compute_propagated_tags_bus(&ref_tag_data); // match the result and generate the output match result{ diff --git a/constraint_generation/src/execution_data/type_definitions.rs b/constraint_generation/src/execution_data/type_definitions.rs index 8c90e20f7..9ad5067f8 100644 --- a/constraint_generation/src/execution_data/type_definitions.rs +++ b/constraint_generation/src/execution_data/type_definitions.rs @@ -17,7 +17,7 @@ pub struct TagNames{ pub fields: Option>, } -#[derive(Clone, PartialEq, Default)] +#[derive(Clone, PartialEq, Default, Debug)] pub struct TagWire{ pub tags: TagInfo, pub fields: Option>, From e85680dce9b47f0d7b17fd2c63aa1c6ae5bcdad1 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 21 Oct 2024 23:33:21 +0200 Subject: [PATCH 08/22] small changes: case inputs main component and handling single arrow assignments --- constraint_generation/src/assignment_utils.rs | 12 ++++++++-- .../component_representation.rs | 22 ++++++++++++++----- constraint_generation/src/execute.rs | 13 ++++++----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/constraint_generation/src/assignment_utils.rs b/constraint_generation/src/assignment_utils.rs index ede82f0bb..a42416471 100644 --- a/constraint_generation/src/assignment_utils.rs +++ b/constraint_generation/src/assignment_utils.rs @@ -130,9 +130,17 @@ pub fn perform_tag_propagation_bus(tag_data: &mut BusTagInfo, assigned_tags: &Ta perform_tag_propagation(&mut tag_data.tags, &mut tag_data.definitions, &assigned_tags.tags, tag_data.is_init); tag_data.remaining_inserts -= n_inserts; tag_data.is_init = true; + for (field_name, field_data) in &mut tag_data.fields{ - let aux = assigned_tags.fields.as_ref().unwrap(); - let field_assigned = aux.get(field_name).unwrap(); + // if the field does not appear in the assigned tags we take an empty TagWire + let mut field_assigned = &TagWire::default(); + + if assigned_tags.fields.is_some() { + let assigned_tag_fields = assigned_tags.fields.as_ref().unwrap(); + if assigned_tag_fields.contains_key(field_name){ // check if it appears in the fields + field_assigned = assigned_tag_fields.get(field_name).unwrap(); + } + } let field_n_inserts = field_data.size * n_inserts; perform_tag_propagation_bus(field_data, field_assigned, field_n_inserts); } diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index bb4b613a8..86eed6679 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -735,14 +735,19 @@ impl ComponentRepresentation { } if input_tags.fields.is_some(){ let input_fields = input_tags.fields.as_mut().unwrap(); - let tags_fields = tags_info.fields.as_ref().unwrap(); for (field_name, input_field) in input_fields{ - let tags = tags_fields.get(field_name).unwrap(); + let mut tags_assigned = &TagWire::default(); + if tags_info.fields.is_some(){ + let tags_fields = tags_info.fields.as_ref().unwrap(); + if tags_fields.contains_key(field_name){ + tags_assigned = tags_fields.get(field_name).unwrap(); + } + } signal_name.push(field_name.clone()); check_tags( input_field, unassigned_tags, - tags, + tags_assigned, signal_name )?; signal_name.pop(); @@ -787,12 +792,19 @@ impl ComponentRepresentation { } } if input_tags.fields.is_some(){ - let tags_field = tags.fields.as_ref().unwrap(); for (field_name, input_field) in input_tags.fields.as_ref().unwrap(){ + + let mut tags_assigned = &TagWire::default(); + if tags.fields.is_some(){ + let tags_fields = tags.fields.as_ref().unwrap(); + if tags_fields.contains_key(field_name){ + tags_assigned = tags_fields.get(field_name).unwrap(); + } + } signal_name.push(field_name.clone()); check_tags( input_field, - tags_field.get(field_name).as_ref().unwrap(), + tags_assigned, signal_name )?; signal_name.pop(); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 2a4eb3dfb..6cc9f257d 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -1694,7 +1694,7 @@ fn perform_assign( // it is signal assignment of a input signal or a field of the bus let signal_accessed = accessing_information.field_access.as_ref().unwrap(); let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); - let tags = if r_folded.tags.is_some() { + let tags = if r_folded.tags.is_some() && op == AssignOp::AssignConstraintSignal { r_folded.tags.unwrap() } else { TagWire::default() @@ -1741,7 +1741,7 @@ fn perform_assign( let (name_bus, assigned_bus_slice) = r_folded.bus_slice.unwrap(); - let tags = if r_folded.tags.is_some() { + let tags = if r_folded.tags.is_some() && op == AssignOp::AssignConstraintSignal{ r_folded.tags.unwrap() } else { TagWire::default() @@ -2012,8 +2012,9 @@ fn perform_assign( } fields } - // only if it is not an input_bus - if !is_input_bus { + // only if it is not an input_bus if we are in the main component + let is_main_component = runtime.call_trace.len() == 1; + if !is_input_bus || is_main_component{ let bus_inside_tags = collect_info_tags(bus_info, &runtime.exec_program, BusSlice::get_number_of_cells(&bus_slice)); tags_info.fields = bus_inside_tags; } @@ -2060,7 +2061,7 @@ fn perform_assign( assert!(accessing_information.field_access.is_some()); let arithmetic_slice = r_folded.arithmetic_slice.unwrap(); - let tags = if r_folded.tags.is_some() { + let tags = if r_folded.tags.is_some() && op == AssignOp::AssignConstraintSignal{ r_folded.tags.unwrap() } else { TagWire::default() @@ -2098,7 +2099,7 @@ fn perform_assign( } let l_slice = AExpressionSlice::new_array(arithmetic_slice.route().to_vec(), l_expressions); Some((l_slice, arithmetic_slice)) - + } else if meta.get_type_knowledge().is_tag(){ // in case we are assigning a tag of the complete bus // check not valid in input buses From cd50d1362b73f6567f23da7fa8a59d9878c28525 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Tue, 22 Oct 2024 11:37:10 +0200 Subject: [PATCH 09/22] minor: check unassigned inputs --- .../src/environment_utils/component_representation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 86eed6679..8180bf994 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -671,7 +671,7 @@ impl ComponentRepresentation { } pub fn has_unassigned_inputs(&self) -> bool{ - !self.unassigned_inputs.is_empty() + !self.unassigned_tags.is_empty () || !self.unassigned_inputs.is_empty() } @@ -704,7 +704,7 @@ impl ComponentRepresentation { let input_tags = accessed_info.get_mut(&signal_name[signal_name.len()-1]).unwrap(); // We copy tags in any case, complete or incomplete assignment - // Th.e values of the tags must be the same than the ones stored before + // The values of the tags must be the same than the ones stored before fn check_tags( input_tags: &mut TagWire, From cd145e5605cc50cc5ee82d0dd57b93a90e5ce439 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 23 Oct 2024 02:22:36 +0200 Subject: [PATCH 10/22] Refactor tag checking logic to allow only accesses without array accesses (but in case array access in a component) --- type_analysis/src/analyzers/type_check.rs | 115 +++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 3c708ac3f..b9d4bfc97 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1040,6 +1040,116 @@ enum SymbolInformation { Tag, } +fn check_if_it_is_a_tag( + symbol: &str, + meta: &Meta, + access_information: AccessInfo, + environment: &TypingEnvironment, + reports: &mut ReportCollection, + program_archive: &ProgramArchive, +) -> Result { + let buses_and_signals = if access_information.1.is_none() { // no access + return Result::Ok(false); + } else { + access_information.1.unwrap() + }; + let mut num_dims_accessed = 0; + let mut pos = 0; + let (mut kind, mut symbol, mut tags) = if environment.has_component(symbol){ + // we are inside component + let (name, dim) = environment.get_component_or_break(symbol, file!(), line!()).clone(); + let current_dim = dim - access_information.0; + if current_dim != 0{ // only allowed complete accesses to component + return add_report_and_end(ReportCode::InvalidPartialArray, meta, reports); + } else if buses_and_signals.len() <= 1 { + return Result::Ok(false); + } + //current_dim == 0 => component completely defined + //buses_and_signals.len() > 1 => we are accessing a signal, or a bus and later maybe a tag + let template_name = name.unwrap(); + let (accessed_element,accessed_dim) = buses_and_signals.get(0).unwrap(); + pos += 1; + num_dims_accessed += accessed_dim; + let input = program_archive.get_template_data(&template_name).get_input_info(&accessed_element); + let output = program_archive.get_template_data(&template_name).get_output_info(&accessed_element); + let (dim, kind, atags) = match (input, output) { + (Option::Some(wire_data), _) | (_, Option::Some(wire_data)) => + (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()), + _ => { + return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); + } + }; + (kind, accessed_element.as_str(), atags.clone()) + } + else { // we are outside component + num_dims_accessed = access_information.0; + let (kind, possible_tags) = if environment.has_variable(symbol) { return Result::Ok(false); } + else if environment.has_bus(symbol){ + let (current_bus,_,possible_tags) = environment.get_bus_or_break(symbol, file!(), line!()).clone(); + let kind = WireType::Bus(current_bus.unwrap()); + (kind, possible_tags) + } else { + let kind = WireType::Signal; + let (_, possible_tags) = environment.get_signal_or_break(symbol, file!(), line!()).clone(); + (kind,possible_tags) + }; + let mut tags = HashSet::new(); + for i in possible_tags.clone() { + tags.insert(i); + } + (kind, symbol, tags) }; + while pos < buses_and_signals.len() { + let (accessed_element, accessed_dim) = buses_and_signals.get(pos).unwrap().clone(); + num_dims_accessed += accessed_dim; + if kind == WireType::Signal { + if tags.contains(&accessed_element) { + + //Tags cannot be partially accessed. Then, the previous bus or signal cannot be array accessed. + if pos == buses_and_signals.len()-1 && num_dims_accessed == 0{ + return Result::Ok(true); + } else if num_dims_accessed > 0 { + return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); + } else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } + else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } else if let WireType::Bus(b_name) = kind { + let field = program_archive.get_bus_data(&b_name).get_field_info(&accessed_element); + match field { + Some(wire) => { + if pos == buses_and_signals.len()-1 { + return Result::Ok(false); + } else { + kind = wire.get_type(); + tags = wire.get_tags().clone(); + } + }, + Option::None => { + if tags.contains(&accessed_element) { + if pos == buses_and_signals.len()-1 && num_dims_accessed == 0{ + return Result::Ok(true); + } else if num_dims_accessed > 0 { + return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); + } else{ + return add_report_and_end(ReportCode::InvalidTagAccess, meta, reports); + } + } + else { + return Ok(false); + } + }, + } + } else{ + unreachable!() + } + pos += 1; + } + return Ok(false); +} + fn apply_access_to_symbol( symbol: &str, meta: &Meta, @@ -1048,6 +1158,10 @@ fn apply_access_to_symbol( reports: &mut ReportCollection, program_archive: &ProgramArchive, ) -> Result { + let it_is_tag = check_if_it_is_a_tag(symbol, meta, access_information.clone(), environment, reports, program_archive)?; + if it_is_tag { + return Result::Ok(SymbolInformation::Tag); + } let (current_template_or_bus, mut current_dim, possible_tags) = if environment.has_component(symbol) { let (temp, dim) = environment.get_component_or_break(symbol, file!(), line!()).clone(); (temp.clone(),dim, Vec::new()) @@ -1060,7 +1174,6 @@ fn apply_access_to_symbol( let dim = environment.get_variable_or_break(symbol, file!(), line!()); (Option::None, *dim, Vec::new()) }; - if access_information.0 > current_dim { return add_report_and_end(ReportCode::InvalidArrayAccess(current_dim, access_information.0), meta, reports); } else { From 4eef792e4338afa9e74778ec7eb14780d501a73c Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 23 Oct 2024 09:46:23 +0200 Subject: [PATCH 11/22] allowing tag accesses of subcomponents io signals --- .../component_representation.rs | 32 ++++++- constraint_generation/src/execute.rs | 93 +++++++++++-------- 2 files changed, 86 insertions(+), 39 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 8180bf994..9182b57f1 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -6,6 +6,7 @@ use std::collections::{HashMap, HashSet}; use crate::ast::Meta; use crate::execution_data::type_definitions::{TagNames,TagWire}; use crate::assignment_utils::*; +use num_bigint_dig::BigInt; pub struct ComponentRepresentation { pub node_pointer: Option, @@ -370,14 +371,43 @@ impl ComponentRepresentation { let mut to_access = remaining_access; while to_access.field_access != None { let acc = to_access.field_access.as_ref().unwrap(); + tag_info = tag_info.fields.as_ref().unwrap().get(acc).unwrap(); - to_access = remaining_access.remaining_access.as_ref().unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); } Ok((tag_info.clone(), result)) } } + pub fn get_tag_value(&self, field_name: &str, remaining_access: &AccessingInformationBus)-> Result{ + + if let Result::Err(value) = self.check_initialized_inputs(field_name) { + return Err(value); + } + + let mut tags_info = if self.inputs_tags.contains_key(field_name){ + self.inputs_tags.get(field_name).unwrap() + } else{ + self.outputs_tags.get(field_name).unwrap() + }; + let mut to_access = remaining_access; + let mut next_access = remaining_access.remaining_access.as_ref().unwrap(); + while next_access.field_access.is_some(){ + let field = to_access.field_access.as_ref().unwrap(); + tags_info = tags_info.fields.as_ref().unwrap().get(field).unwrap(); + to_access = to_access.remaining_access.as_ref().unwrap(); + next_access = next_access.remaining_access.as_ref().unwrap(); + } + let tag_value = tags_info.tags.get(to_access.field_access.as_ref().unwrap()).unwrap(); + if let Some(value_tag) = tag_value { // tag has value + Result::Ok(value_tag.clone() ) + } else { + let error = MemoryError::TagValueNotInitializedAccess; + return Result::Err(error); + } + } + // Assign signals: Operations to assign signals -> case init and no init pub fn assign_value_to_signal( diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 6cc9f257d..bfc72b75f 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2936,57 +2936,74 @@ fn execute_component( let remaining_access = access_information.remaining_access.as_ref().unwrap(); let symbol = create_symbol_bus(symbol, &access_information); - let (tags, result) = treat_result_with_memory_error( - resulting_component.get_io_value(signal_name, remaining_access), - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - )?; - - match result{ - FoldedResult::Signal(signals) =>{ - let result = signal_to_arith(symbol, signals) - .map(|s| FoldedValue { - arithmetic_slice: Option::Some(s), - tags: Option::Some(tags), - ..FoldedValue::default() - }); - treat_result_with_memory_error( - result, - meta, - &mut runtime.runtime_errors, - &runtime.call_trace, - ) - }, - FoldedResult::Bus(buses) =>{ - // Check that all the buses are completely assigned + if meta.get_type_knowledge().is_tag(){ + // case accessing a tag of a field of the subcomponent + let result = treat_result_with_memory_error( + resulting_component.get_tag_value(signal_name, remaining_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + let a_value = AExpr::Number { value: result }; + let ae_slice = AExpressionSlice::new(&a_value); + Result::Ok(FoldedValue { arithmetic_slice: Option::Some(ae_slice), ..FoldedValue::default() }) - for i in 0..BusSlice::get_number_of_cells(&buses){ - let value_left = treat_result_with_memory_error( - BusSlice::get_reference_to_single_value_by_index(&buses, i), + } else{ + // case accessing a field + let (tags, result) = treat_result_with_memory_error( + resulting_component.get_io_value(signal_name, remaining_access), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + + match result{ + FoldedResult::Signal(signals) =>{ + let result = signal_to_arith(symbol, signals) + .map(|s| FoldedValue { + arithmetic_slice: Option::Some(s), + tags: Option::Some(tags), + ..FoldedValue::default() + }); + treat_result_with_memory_error( + result, meta, &mut runtime.runtime_errors, &runtime.call_trace, - )?; - - if value_left.has_unassigned_fields(){ - treat_result_with_memory_error( - Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + ) + }, + FoldedResult::Bus(buses) =>{ + // Check that all the buses are completely assigned + + for i in 0..BusSlice::get_number_of_cells(&buses){ + let value_left = treat_result_with_memory_error( + BusSlice::get_reference_to_single_value_by_index(&buses, i), meta, &mut runtime.runtime_errors, &runtime.call_trace, )?; + + if value_left.has_unassigned_fields(){ + treat_result_with_memory_error( + Result::Err(MemoryError::InvalidAccess(TypeInvalidAccess::NoInitializedBus)), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + } } + Ok(FoldedValue { + bus_slice: Option::Some((symbol, buses)), + tags: Option::Some(tags), + ..FoldedValue::default() + }) + } - Ok(FoldedValue { - bus_slice: Option::Some((symbol, buses)), - tags: Option::Some(tags), - ..FoldedValue::default() - }) - } } + + } else { let read_result = if resulting_component.is_ready_initialize() { Result::Ok(resulting_component) From 0500ddafcd612f5e65d0cb0998068f8101c62720 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 23 Oct 2024 11:28:00 +0200 Subject: [PATCH 12/22] Tags of subcomponents inputs cannot be accessed/modified --- .../src/program_library/error_code.rs | 6 ++++- type_analysis/src/analyzers/type_check.rs | 26 +++++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 6318e712c..e05a004cf 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -91,6 +91,8 @@ pub enum ReportCode { MustBeSingleArithmeticB, MustBeArithmetic, OutputTagCannotBeModifiedOutside, + InputTagCannotBeAccessedOutside, + InputTagCannotBeModifiedOutside, MustBeSameDimension(usize, usize), ExpectedDimDiffGotDim(usize, usize), RuntimeError, @@ -198,7 +200,9 @@ impl fmt::Display for ReportCode { ExpectedDimDiffGotDim(..) => "T2045", MustBeSameDimension(..) => "T2046", MustBeArithmetic => "T2047", - OutputTagCannotBeModifiedOutside => "T2048", + OutputTagCannotBeModifiedOutside => "T2048-A", + InputTagCannotBeModifiedOutside => "T2048-B", + InputTagCannotBeAccessedOutside => "T2048-C", UnreachableTags => "T2049", UnreachableSignals => "T2050", MainComponentWithTags => "T2051", diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index b9d4bfc97..d7f7ef12f 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -290,6 +290,10 @@ fn type_statement( if output.is_some() { return add_report( ReportCode::OutputTagCannotBeModifiedOutside,meta, &mut analysis_information.reports); } + let input = program_archive.get_template_data(&template_name).get_input_info(&first_access); + if input.is_some() { + return add_report( ReportCode::InputTagCannotBeModifiedOutside,meta, &mut analysis_information.reports); + } } } } @@ -1055,6 +1059,7 @@ fn check_if_it_is_a_tag( }; let mut num_dims_accessed = 0; let mut pos = 0; + let mut it_is_input_subcomponent = false; let (mut kind, mut symbol, mut tags) = if environment.has_component(symbol){ // we are inside component let (name, dim) = environment.get_component_or_break(symbol, file!(), line!()).clone(); @@ -1072,12 +1077,13 @@ fn check_if_it_is_a_tag( num_dims_accessed += accessed_dim; let input = program_archive.get_template_data(&template_name).get_input_info(&accessed_element); let output = program_archive.get_template_data(&template_name).get_output_info(&accessed_element); - let (dim, kind, atags) = match (input, output) { - (Option::Some(wire_data), _) | (_, Option::Some(wire_data)) => - (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()), - _ => { - return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); - } + let (dim, kind, atags) = if let Some(wire_data) = input { + it_is_input_subcomponent = true; + (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()) + } else if let Some(wire_data) = output { + (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()) + } else { + return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); }; (kind, accessed_element.as_str(), atags.clone()) } @@ -1106,7 +1112,8 @@ fn check_if_it_is_a_tag( //Tags cannot be partially accessed. Then, the previous bus or signal cannot be array accessed. if pos == buses_and_signals.len()-1 && num_dims_accessed == 0{ - return Result::Ok(true); + return if it_is_input_subcomponent { add_report_and_end(ReportCode::InputTagCannotBeAccessedOutside, meta, reports)} + else {Result::Ok(true)}; } else if num_dims_accessed > 0 { return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); } else{ @@ -1130,7 +1137,8 @@ fn check_if_it_is_a_tag( Option::None => { if tags.contains(&accessed_element) { if pos == buses_and_signals.len()-1 && num_dims_accessed == 0{ - return Result::Ok(true); + return if it_is_input_subcomponent { add_report_and_end(ReportCode::InputTagCannotBeAccessedOutside, meta, reports)} + else {Result::Ok(true)}; } else if num_dims_accessed > 0 { return add_report_and_end(ReportCode::InvalidTagAccessAfterArray, meta, reports); } else{ @@ -1501,6 +1509,8 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio MustBeSingleArithmeticB => format!("Must be a single arithmetic expression.\n Found bus"), MustBeArithmetic => "Must be a single arithmetic expression or an array of arithmetic expressions. \n Found component".to_string(), OutputTagCannotBeModifiedOutside => "Output tag from a subcomponent cannot be modified".to_string(), + InputTagCannotBeModifiedOutside => "Input tag from a subcomponent cannot be modified".to_string(), + InputTagCannotBeAccessedOutside => "Input tag from a subcomponent cannot be accessed".to_string(), MustBeSameDimension(dim_1, dim_2) =>{ format!("Must be two arrays of the same dimensions.\n Found {} and {} dimensions", dim_1, dim_2) } From 21595fa000c48fed79122abd279cea87f427b254 Mon Sep 17 00:00:00 2001 From: miguelis Date: Wed, 23 Oct 2024 11:38:26 +0200 Subject: [PATCH 13/22] Removing warnings --- type_analysis/src/analyzers/type_check.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index d7f7ef12f..93c6269f1 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -1060,7 +1060,7 @@ fn check_if_it_is_a_tag( let mut num_dims_accessed = 0; let mut pos = 0; let mut it_is_input_subcomponent = false; - let (mut kind, mut symbol, mut tags) = if environment.has_component(symbol){ + let (mut kind, mut tags) = if environment.has_component(symbol){ // we are inside component let (name, dim) = environment.get_component_or_break(symbol, file!(), line!()).clone(); let current_dim = dim - access_information.0; @@ -1077,15 +1077,15 @@ fn check_if_it_is_a_tag( num_dims_accessed += accessed_dim; let input = program_archive.get_template_data(&template_name).get_input_info(&accessed_element); let output = program_archive.get_template_data(&template_name).get_output_info(&accessed_element); - let (dim, kind, atags) = if let Some(wire_data) = input { + let (kind, atags) = if let Some(wire_data) = input { it_is_input_subcomponent = true; - (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()) + (wire_data.get_type(), wire_data.get_tags()) } else if let Some(wire_data) = output { - (wire_data.get_dimension(), wire_data.get_type(), wire_data.get_tags()) + (wire_data.get_type(), wire_data.get_tags()) } else { return add_report_and_end(ReportCode::InvalidSignalAccess, meta, reports); }; - (kind, accessed_element.as_str(), atags.clone()) + (kind, atags.clone()) } else { // we are outside component num_dims_accessed = access_information.0; @@ -1103,7 +1103,7 @@ fn check_if_it_is_a_tag( for i in possible_tags.clone() { tags.insert(i); } - (kind, symbol, tags) }; + (kind, tags) }; while pos < buses_and_signals.len() { let (accessed_element, accessed_dim) = buses_and_signals.get(pos).unwrap().clone(); num_dims_accessed += accessed_dim; From 7be5f5b4689080da21401f0ace31d2bee4d68e0d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Wed, 23 Oct 2024 12:05:50 +0200 Subject: [PATCH 14/22] minor: outputs tags --- .../src/environment_utils/component_representation.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 9182b57f1..f8d1e4252 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -197,9 +197,9 @@ impl ComponentRepresentation { for (tag_name, value) in &node.signal_to_tags{ if component.outputs_tags.contains_key(&tag_name[0]){ // in this case we have to store the value - let info_output_tags = component.outputs_tags.get_mut(&tag_name[0]).unwrap(); + let mut info_output_tags = component.outputs_tags.get_mut(&tag_name[0]).unwrap(); for i in 1..tag_name.len()-1{ - info_output_tags.fields.as_mut().unwrap().get_mut(&tag_name[i]).unwrap(); + info_output_tags = info_output_tags.fields.as_mut().unwrap().get_mut(&tag_name[i]).unwrap(); } info_output_tags.tags.insert(tag_name.last().unwrap().clone(), Some(value.clone())); } @@ -391,6 +391,7 @@ impl ComponentRepresentation { } else{ self.outputs_tags.get(field_name).unwrap() }; + let mut to_access = remaining_access; let mut next_access = remaining_access.remaining_access.as_ref().unwrap(); while next_access.field_access.is_some(){ From aac13d458653638d42f75eb25f9cf2e1ee67c22f Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 28 Oct 2024 12:54:50 +0100 Subject: [PATCH 15/22] solving minor issues --- constraint_generation/src/execute.rs | 20 +++++++++++++++++++ .../src/decorators/type_reduction.rs | 6 +++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index bfc72b75f..5fa58a1aa 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -2408,8 +2408,28 @@ fn execute_conditional_statement( if let Option::Some(else_stmt) = false_case { let (else_ret, can_simplify_else) = execute_statement(else_stmt, program_archive, runtime, actual_node, flags)?; can_simplify &= can_simplify_else; + + // Choose the biggest return value possible + if ret_value.is_none() { ret_value = else_ret; + } else if ret_value.is_some() && else_ret.is_some(){ + let slice_if = safe_unwrap_to_arithmetic_slice(ret_value.unwrap(),line!()); + let size_if = AExpressionSlice::get_number_of_cells(&slice_if); + let slice_else = safe_unwrap_to_arithmetic_slice(else_ret.unwrap(),line!()); + let size_else = AExpressionSlice::get_number_of_cells(&slice_else); + if size_else > size_if{ + ret_value = Some(FoldedValue{ + arithmetic_slice: Some(slice_else), + ..FoldedValue::default() + }); + } else{ + ret_value = Some(FoldedValue{ + arithmetic_slice: Some(slice_if), + ..FoldedValue::default() + }); + } + } } runtime.block_type = previous_block_type; diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index 37903b28d..6694645d7 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -89,7 +89,11 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ } InfixOp { lhe, rhe, .. } => reduce_types_in_infix(lhe, rhe, environment,program_archive), PrefixOp { rhe, .. } => reduce_types_in_expression(rhe, environment,program_archive), - ParallelOp { rhe, .. } => reduce_types_in_expression(rhe, environment,program_archive), + ParallelOp { meta, rhe, .. } => { + let report = reduce_types_in_expression(rhe, environment,program_archive); + meta.get_mut_type_knowledge().set_reduces_to(rhe.get_meta().get_type_knowledge().get_reduces_to()); + report + } InlineSwitchOp { cond, if_true, if_false, .. } => { reduce_types_in_inline_switch(cond, if_true, if_false, environment,program_archive) } From 477bb8deb9267bf200b6152cd88b3ad264ff959b Mon Sep 17 00:00:00 2001 From: clararod9 Date: Mon, 28 Oct 2024 14:56:37 +0100 Subject: [PATCH 16/22] adding multiple size case to Eq --- .../compute_bucket.rs | 48 ++++++++++++++----- .../load_bucket.rs | 12 ++--- .../intermediate_representation/translate.rs | 15 +++--- .../src/intermediate_representation/types.rs | 2 +- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/compiler/src/intermediate_representation/compute_bucket.rs b/compiler/src/intermediate_representation/compute_bucket.rs index 31a4498cb..7abca79a7 100644 --- a/compiler/src/intermediate_representation/compute_bucket.rs +++ b/compiler/src/intermediate_representation/compute_bucket.rs @@ -3,7 +3,7 @@ use crate::translating_traits::*; use code_producers::c_elements::*; use code_producers::wasm_elements::*; -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq)] pub enum OperatorType { Mul, Div, @@ -18,7 +18,7 @@ pub enum OperatorType { GreaterEq, Lesser, Greater, - Eq(usize), + Eq(SizeOption), NotEq, BoolOr, BoolAnd, @@ -42,7 +42,8 @@ impl OperatorType { pub fn is_multiple_eq(&self) -> bool { match self { - OperatorType::Eq(n) => *n > 1, + OperatorType::Eq(SizeOption::Single(n)) => *n > 1, + OperatorType::Eq(SizeOption::Multiple(_)) => true, _ => false } } @@ -52,7 +53,7 @@ impl ToString for OperatorType { fn to_string(&self) -> String { use OperatorType::*; if let Eq(n) = self { - format!("EQ({})", n) + format!("EQ({:?})", n) } else { match self { Mul => "MUL", @@ -170,7 +171,7 @@ impl WriteWasm for ComputeBucket { instructions.push(call("$Fr_toInt")); } _ => { - match self.op { + match &self.op { OperatorType::Add => { instructions.push(call("$Fr_add")); // Result, Argument, Argument } @@ -211,14 +212,19 @@ impl WriteWasm for ComputeBucket { instructions.push(call("$Fr_gt")); } OperatorType::Eq(n) => { - assert!(n != 0); - if n == 1 { + // TODO: COMPUTE THE SIZE AS IN THE MULTIPLE STORE, NOW JUST USING FIRST POSITION + let length = match n{ + SizeOption::Single(v) => *v, + SizeOption::Multiple(v) => v[0].1.clone() + }; + assert!(length != 0); + if length == 1 { instructions.push(call("$Fr_eq")); } else { instructions.push(set_local(producer.get_aux_2_tag())); instructions.push(set_local(producer.get_aux_1_tag())); instructions.push(set_local(producer.get_aux_0_tag())); - instructions.push(set_constant(&n.to_string())); + instructions.push(set_constant(&length.to_string())); instructions.push(set_local(producer.get_counter_tag())); instructions.push(add_block()); instructions.push(add_loop()); @@ -295,7 +301,7 @@ impl WriteWasm for ComputeBucket { impl WriteC for ComputeBucket { fn produce_c(&self, producer: &CProducer, parallel: Option) -> (Vec, String) { use c_code_generator::*; - fn get_fr_op(op_type: OperatorType) -> String { + fn get_fr_op(op_type: &OperatorType) -> String { match op_type { OperatorType::Add => "Fr_add".to_string(), OperatorType::Div => "Fr_div".to_string(), @@ -346,15 +352,31 @@ impl WriteC for ComputeBucket { OperatorType::Eq(n) => { let exp_aux_index = self.op_aux_no.to_string(); - let operator = get_fr_op(self.op); + let operator = get_fr_op(&self.op); let result_ref = format!("&{}", expaux(exp_aux_index.clone())); let mut arguments = vec![result_ref.clone()]; let operands_copy = operands.clone(); arguments.append(&mut operands); compute_c.push(format!("{}; // line circom {}", build_call(operator.clone(), arguments),self.line.to_string())); - if *n > 1 { + + // We compute the possible sizes, case multiple sizes + let expr_size = match &n{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + let cmp_index_ref = "cmp_index_ref_load".to_string(); + + compute_c.push(format!("std::map size_store {};", + set_list_tuple(values.clone()) + )); + let sub_component_pos_in_memory = format!("{}[{}]", MY_SUBCOMPONENTS, cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_expr[{}]", temp_id) + } + }; + + if expr_size != "1" { compute_c.push(format!("{} = 1;", index_multiple_eq())); - compute_c.push(format!("while({} < {} && Fr_isTrue({})) {{", index_multiple_eq(), n, result_ref)); + compute_c.push(format!("while({} < {} && Fr_isTrue({})) {{", index_multiple_eq(), expr_size, result_ref)); operands = vec![]; arguments = vec![result_ref.clone()]; for operand in &operands_copy { @@ -374,7 +396,7 @@ impl WriteC for ComputeBucket { _ => { let exp_aux_index = self.op_aux_no.to_string(); // build assign - let operator = get_fr_op(self.op); + let operator = get_fr_op(&self.op); let result_ref = format!("&{}", expaux(exp_aux_index.clone())); let mut arguments = vec![result_ref.clone()]; arguments.append(&mut operands); diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index 9e4b523da..a0494757e 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -350,7 +350,7 @@ impl WriteC for LoadBucket { if uniform_parallel_value.is_some(){ if uniform_parallel_value.unwrap(){ prologue.push(format!("{{")); - prologue.push(format!("int aux1 = {};",cmp_index_ref.clone())); + prologue.push(format!("int cmp_index_ref_load = {};",cmp_index_ref.clone())); prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one @@ -361,11 +361,11 @@ impl WriteC for LoadBucket { prologue.push(format!("ctx->numThreadMutex.unlock();")); prologue.push(format!("ctx->ntcvs.notify_one();")); prologue.push(format!( - "std::unique_lock lk({}->componentMemory[{}[aux1]].mutexes[aux2 + i]);", + "std::unique_lock lk({}->componentMemory[{}[cmp_index_ref_load]].mutexes[aux2 + i]);", CIRCOM_CALC_WIT, MY_SUBCOMPONENTS) ); prologue.push(format!( - "{}->componentMemory[{}[aux1]].cvs[aux2 + i].wait(lk, [{},{},aux1,aux2, i]() {{return {}->componentMemory[{}[aux1]].outputIsSet[aux2 + i];}});", + "{}->componentMemory[{}[cmp_index_ref_load]].cvs[aux2 + i].wait(lk, [{},{},cmp_index_ref_load,aux2, i]() {{return {}->componentMemory[{}[cmp_index_ref_load]].outputIsSet[aux2 + i];}});", CIRCOM_CALC_WIT, MY_SUBCOMPONENTS, CIRCOM_CALC_WIT, MY_SUBCOMPONENTS, CIRCOM_CALC_WIT, MY_SUBCOMPONENTS) ); @@ -387,7 +387,7 @@ impl WriteC for LoadBucket { // case parallel prologue.push(format!("{{")); - prologue.push(format!("int aux1 = {};",cmp_index_ref.clone())); + prologue.push(format!("int cmp_index_ref_load = {};",cmp_index_ref.clone())); prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); @@ -397,11 +397,11 @@ impl WriteC for LoadBucket { prologue.push(format!("ctx->numThreadMutex.unlock();")); prologue.push(format!("ctx->ntcvs.notify_one();")); prologue.push(format!( - "std::unique_lock lk({}->componentMemory[{}[aux1]].mutexes[aux2 + i]);", + "std::unique_lock lk({}->componentMemory[{}[cmp_index_ref_load]].mutexes[aux2 + i]);", CIRCOM_CALC_WIT, MY_SUBCOMPONENTS) ); prologue.push(format!( - "{}->componentMemory[{}[aux1]].cvs[aux2 + i].wait(lk, [{},{},aux1,aux2, i]() {{return {}->componentMemory[{}[aux1]].outputIsSet[aux2 + i];}});", + "{}->componentMemory[{}[cmp_index_ref_load]].cvs[aux2 + i].wait(lk, [{},{},cmp_index_ref_load,aux2, i]() {{return {}->componentMemory[{}[cmp_index_ref_load]].outputIsSet[aux2 + i];}});", CIRCOM_CALC_WIT, MY_SUBCOMPONENTS, CIRCOM_CALC_WIT, MY_SUBCOMPONENTS, CIRCOM_CALC_WIT, MY_SUBCOMPONENTS) ); diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index c195c5a34..49b79b09e 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -669,14 +669,13 @@ fn translate_constraint_equality(stmt: Statement, state: &mut State, context: &C if let ConstraintEquality { meta, lhe, rhe } = stmt { let starts_at = context.files.get_line(meta.start, meta.get_file_id()).unwrap(); - let length = if let Variable { meta, name, access} = lhe.clone() { + let length = if let Variable { meta, name, access} = rhe.clone() { let def = SymbolDef { meta, symbol: name, acc: access }; let aux = ProcessedSymbol::new(def, state, context).length; - match aux{ - SizeOption::Single(value) => value, - SizeOption::Multiple(_) => unreachable!("Should be single possible lenght"), - } - } else {1}; + aux + } else { + SizeOption::Single(1) + }; let lhe_pointer = translate_expression(lhe, state, context); let rhe_pointer = translate_expression(rhe, state, context); @@ -935,7 +934,7 @@ fn translate_infix_operator(op: ExpressionInfixOpcode) -> OperatorType { GreaterEq => OperatorType::GreaterEq, Lesser => OperatorType::Lesser, Greater => OperatorType::Greater, - Eq => OperatorType::Eq(1), + Eq => OperatorType::Eq(SizeOption::Single(1)), NotEq => OperatorType::NotEq, BoolOr => OperatorType::BoolOr, BoolAnd => OperatorType::BoolAnd, @@ -1745,7 +1744,7 @@ fn fold(using: OperatorType, mut stack: Vec, state: &State) line: instruction.get_line(), message_id: instruction.get_message_id(), op_aux_no: 0, - op: using, + op: using.clone(), stack: vec![fold(using, stack, state), instruction], } .allocate() diff --git a/compiler/src/intermediate_representation/types.rs b/compiler/src/intermediate_representation/types.rs index 95b490031..060041224 100644 --- a/compiler/src/intermediate_representation/types.rs +++ b/compiler/src/intermediate_representation/types.rs @@ -14,7 +14,7 @@ impl ToString for ValueType { } } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum SizeOption{ Single(usize), Multiple(Vec<(usize, usize)>) // The first value indicates the cmp_id, the second the size From 55fd6b34670f4587430b0671dd0408a3bf5c0039 Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 30 Oct 2024 11:23:28 +0100 Subject: [PATCH 17/22] handling multiple sizes for Equality in wasm --- .../compute_bucket.rs | 28 +++++++++++++------ .../load_bucket.rs | 26 ++++++++--------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/compiler/src/intermediate_representation/compute_bucket.rs b/compiler/src/intermediate_representation/compute_bucket.rs index 7abca79a7..167885324 100644 --- a/compiler/src/intermediate_representation/compute_bucket.rs +++ b/compiler/src/intermediate_representation/compute_bucket.rs @@ -212,18 +212,30 @@ impl WriteWasm for ComputeBucket { instructions.push(call("$Fr_gt")); } OperatorType::Eq(n) => { - // TODO: COMPUTE THE SIZE AS IN THE MULTIPLE STORE, NOW JUST USING FIRST POSITION - let length = match n{ - SizeOption::Single(v) => *v, - SizeOption::Multiple(v) => v[0].1.clone() + let mut is_multiple = false; + let (length,values) = match n{ + SizeOption::Single(v) => (*v,vec![]), + SizeOption::Multiple(v) => { + is_multiple = true; + (v.len(),v.clone()) + } }; assert!(length != 0); - if length == 1 { + if !is_multiple && length == 1 { instructions.push(call("$Fr_eq")); } else { - instructions.push(set_local(producer.get_aux_2_tag())); - instructions.push(set_local(producer.get_aux_1_tag())); - instructions.push(set_local(producer.get_aux_0_tag())); + if is_multiple { //create a nested if-else with all cases + instructions.push(get_local(producer.get_sub_cmp_load_tag())); + instructions.push(load32(None)); // get template id + instructions.push(set_local(producer.get_aux_0_tag())); + let mut instr_if = create_if_selection(&values,producer.get_aux_0_tag()); + instructions.append(&mut instr_if); + } else { + instructions.push(set_constant(&length.to_string())); + } + instructions.push(set_local(producer.get_aux_2_tag())); // size + instructions.push(set_local(producer.get_aux_1_tag())); // second argument initial position + instructions.push(set_local(producer.get_aux_0_tag())); // first argument initial position instructions.push(set_constant(&length.to_string())); instructions.push(set_local(producer.get_counter_tag())); instructions.push(add_block()); diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index a0494757e..c78699cb1 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -111,9 +111,12 @@ impl WriteWasm for LoadBucket { instructions.push(add32()); instructions.push(load32(None)); //subcomponent block instructions.push(tee_local(producer.get_sub_cmp_load_tag())); - //instructions.push(set_local(producer.get_sub_cmp_load_tag())); - //instructions.push(get_local(producer.get_sub_cmp_load_tag())); - instructions.push(load32(None)); // get template id A + instructions.push(load32(Some( + &producer.get_signal_start_address_in_component().to_string() + ))); //subcomponent start_of_signals + // and now, we compute the offset + instructions.push(get_local(producer.get_sub_cmp_load_tag())); + instructions.push(load32(None)); // get template id instructions.push(set_constant("4")); //size in byte of i32 instructions.push(mul32()); instructions.push(load32(Some( @@ -136,12 +139,10 @@ impl WriteWasm for LoadBucket { } let mut idxpos = 0; while idxpos < indexes.len() { - if let AccessType::Indexed(index_info) = &indexes[idxpos] { - - let index_list = &index_info.indexes; - let dim = index_info.symbol_dim; - - let mut infopos = 0; + if let AccessType::Indexed(index_info) = &indexes[idxpos] { + let index_list = &index_info.indexes; + let dim = index_info.symbol_dim; + let mut infopos = 0; assert!(index_list.len() > 0); //We first compute the number of elements as //((index_list[0] * length_of_dim[1]) + index_list[1]) * length_of_dim[2] + ... )* length_of_dim[n-1] + index_list[n-1] @@ -227,12 +228,7 @@ impl WriteWasm for LoadBucket { } } } - instructions.push(get_local(producer.get_sub_cmp_load_tag())); - instructions.push(set_constant( - &producer.get_signal_start_address_in_component().to_string(), - )); - instructions.push(add32()); - instructions.push(load32(None)); //subcomponent start_of_signals + //after this we have the offset on top of the stack and the subcomponent start_of_signals just below instructions.push(add32()); // we get the position of the signal (with indexes) in memory if producer.needs_comments() { instructions.push(";; end of load bucket".to_string()); From f4d7561d9c2b83b5ad8a02c656a09aeba4072b7d Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sun, 3 Nov 2024 23:16:17 +0100 Subject: [PATCH 18/22] case multiple sizes in Constraint Equalities (Code generation) --- compiler/src/circuit_design/template.rs | 3 ++ .../compute_bucket.rs | 7 ++- .../load_bucket.rs | 43 +++++++++++++------ .../intermediate_representation/translate.rs | 22 ++++++++++ 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/compiler/src/circuit_design/template.rs b/compiler/src/circuit_design/template.rs index 7b9c4b687..0caebd825 100644 --- a/compiler/src/circuit_design/template.rs +++ b/compiler/src/circuit_design/template.rs @@ -290,6 +290,9 @@ impl TemplateCodeInfo { run_body.push(format!("{};", declare_lvar(self.var_stack_depth))); run_body.push(format!("{};", declare_sub_component_aux())); run_body.push(format!("{};", declare_index_multiple_eq())); + run_body.push(format!("int cmp_index_ref_load = -1;")); + + for t in &self.body { let (mut instructions_body, _) = t.produce_c(producer, Some(parallel)); diff --git a/compiler/src/intermediate_representation/compute_bucket.rs b/compiler/src/intermediate_representation/compute_bucket.rs index 7abca79a7..b8b7b07eb 100644 --- a/compiler/src/intermediate_representation/compute_bucket.rs +++ b/compiler/src/intermediate_representation/compute_bucket.rs @@ -357,6 +357,7 @@ impl WriteC for ComputeBucket { let mut arguments = vec![result_ref.clone()]; let operands_copy = operands.clone(); arguments.append(&mut operands); + compute_c.push("{{".to_string()); compute_c.push(format!("{}; // line circom {}", build_call(operator.clone(), arguments),self.line.to_string())); // We compute the possible sizes, case multiple sizes @@ -365,12 +366,12 @@ impl WriteC for ComputeBucket { SizeOption::Multiple(values) => { let cmp_index_ref = "cmp_index_ref_load".to_string(); - compute_c.push(format!("std::map size_store {};", + compute_c.push(format!("std::map size_eq {};", set_list_tuple(values.clone()) )); let sub_component_pos_in_memory = format!("{}[{}]", MY_SUBCOMPONENTS, cmp_index_ref); let temp_id = template_id_in_component(sub_component_pos_in_memory); - format!("size_expr[{}]", temp_id) + format!("size_eq[{}]", temp_id) } }; @@ -388,6 +389,8 @@ impl WriteC for ComputeBucket { compute_c.push(format!("}}")); } + compute_c.push("}}".to_string()); + result = result_ref; diff --git a/compiler/src/intermediate_representation/load_bucket.rs b/compiler/src/intermediate_representation/load_bucket.rs index a0494757e..92982bd5f 100644 --- a/compiler/src/intermediate_representation/load_bucket.rs +++ b/compiler/src/intermediate_representation/load_bucket.rs @@ -334,23 +334,26 @@ impl WriteC for LoadBucket { format!("&{}", signal_values(src_index)) } AddressType::SubcmpSignal { uniform_parallel_value, is_output, .. } => { + + // we store the value of the cmp index + prologue.push(format!("cmp_index_ref_load = {};",cmp_index_ref.clone())); + if *is_output { - // We compute the possible sizes, case multiple size - let size = match &self.context.size{ - SizeOption::Single(value) => value.to_string(), - SizeOption::Multiple(values) => { - prologue.push(format!("std::map size_store {};", - set_list_tuple(values.clone()) - )); - let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); - let temp_id = template_id_in_component(sub_component_pos_in_memory); - format!("size_load[{}]", temp_id) - } - }; if uniform_parallel_value.is_some(){ if uniform_parallel_value.unwrap(){ prologue.push(format!("{{")); - prologue.push(format!("int cmp_index_ref_load = {};",cmp_index_ref.clone())); + // We compute the possible sizes, case multiple size + let size = match &self.context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("std::map size_load {};", + set_list_tuple(values.clone()) + )); + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_load[{}]", temp_id) + } + }; prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one @@ -379,6 +382,18 @@ impl WriteC for LoadBucket { } // Case we only know if it is parallel at execution else{ + // We compute the possible sizes, case multiple size + let size = match &self.context.size{ + SizeOption::Single(value) => value.to_string(), + SizeOption::Multiple(values) => { + prologue.push(format!("std::map size_load {};", + set_list_tuple(values.clone()) + )); + let sub_component_pos_in_memory = format!("{}[{}]",MY_SUBCOMPONENTS,cmp_index_ref); + let temp_id = template_id_in_component(sub_component_pos_in_memory); + format!("size_load[{}]", temp_id) + } + }; prologue.push(format!( "if ({}[{}]){{", MY_SUBCOMPONENTS_PARALLEL, @@ -387,7 +402,6 @@ impl WriteC for LoadBucket { // case parallel prologue.push(format!("{{")); - prologue.push(format!("int cmp_index_ref_load = {};",cmp_index_ref.clone())); prologue.push(format!("int aux2 = {};",src_index.clone())); // check each one of the outputs of the assignment, we add i to check them one by one prologue.push(format!("for (int i = 0; i < {}; i++) {{", size)); @@ -425,6 +439,7 @@ impl WriteC for LoadBucket { format!("&{}->signalValues[{} + {}]", CIRCOM_CALC_WIT, sub_cmp_start, src_index) } }; + //prologue.push(format!("// end of load line {} with access {}",self.line.to_string(),access)); (prologue, access) } diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 49b79b09e..6096702b2 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -672,11 +672,33 @@ fn translate_constraint_equality(stmt: Statement, state: &mut State, context: &C let length = if let Variable { meta, name, access} = rhe.clone() { let def = SymbolDef { meta, symbol: name, acc: access }; let aux = ProcessedSymbol::new(def, state, context).length; + aux + + // TODO: only multiple if both of them are multiple, if not take the Single one + /* + match aux{ + SizeOption::Single(_) => aux, + SizeOption::Multiple(possible_lengths) =>{ + if let Variable { meta, name, access} = lhe.clone() { + let def_left = SymbolDef { meta, symbol: name, acc: access }; + let aux_left = ProcessedSymbol::new(def_left, state, context).length; + match aux_left{ + SizeOption::Single(v) => SizeOption::Single(v), + SizeOption::Multiple(_) =>{ + SizeOption::Multiple(possible_lengths) + } + } + } else{ + SizeOption::Single(1) + } + } + }*/ } else { SizeOption::Single(1) }; + let lhe_pointer = translate_expression(lhe, state, context); let rhe_pointer = translate_expression(rhe, state, context); let stack = vec![lhe_pointer, rhe_pointer]; From d0f28326c1235df3dc00ab0c62dbe2656c228d2a Mon Sep 17 00:00:00 2001 From: alrubio Date: Wed, 6 Nov 2024 15:01:23 +0100 Subject: [PATCH 19/22] bug fixed in Eq with Multiple for wasm --- compiler/src/intermediate_representation/compute_bucket.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/src/intermediate_representation/compute_bucket.rs b/compiler/src/intermediate_representation/compute_bucket.rs index a33ad2a4a..408c977c2 100644 --- a/compiler/src/intermediate_representation/compute_bucket.rs +++ b/compiler/src/intermediate_representation/compute_bucket.rs @@ -233,11 +233,10 @@ impl WriteWasm for ComputeBucket { } else { instructions.push(set_constant(&length.to_string())); } - instructions.push(set_local(producer.get_aux_2_tag())); // size - instructions.push(set_local(producer.get_aux_1_tag())); // second argument initial position - instructions.push(set_local(producer.get_aux_0_tag())); // first argument initial position - instructions.push(set_constant(&length.to_string())); instructions.push(set_local(producer.get_counter_tag())); + instructions.push(set_local(producer.get_aux_2_tag())); // second argument initial position + instructions.push(set_local(producer.get_aux_1_tag())); // first argument initial position + instructions.push(set_local(producer.get_aux_0_tag())); // resut position instructions.push(add_block()); instructions.push(add_loop()); instructions.push(get_local(producer.get_aux_0_tag())); From 25537e1a9446007629e567e684381cd56769bea9 Mon Sep 17 00:00:00 2001 From: miguelis Date: Fri, 8 Nov 2024 15:18:33 +0100 Subject: [PATCH 20/22] Improving parser and new release information --- RELEASES.md | 13 +++++++++++++ parser/src/lang.lalrpop | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 3f7e198d1..bf6990919 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,17 @@ # Release notes +## November 08, 2024 circom 2.2.1 +#### Improvements: +- Improving the use and heritance of tags inside buses. Now the values are propagated correctly following the same rules as arrays. +- Unassigned inputs: do not executing the circuit twice in C++. +- Allowing tag accesses of subcomponent input/output signals. +- Handling equality checks with dynamic size in witness generation code. +- Improving error messages. +- Improving error recovery in parser. + +#### Fixed bugs: +- Importing function printDebug removed from WASM (circom tests from circomlib working now). + + ## October 07, 2024 circom 2.2.0 #### New features - Buses: more information [here](https://github.com/iden3/circom/blob/master/mkdocs/docs/circom-language/buses.md). diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index e71e69630..6a820194b 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -528,7 +528,12 @@ ParseStatement2 : Statement = { } }, - ParseBlock + ParseBlock, + + ! Semicolon => { + errors.push(produce_report(ReportCode::IllegalExpression, s..e, file_id)); + build_block(Meta::new(s,e), Vec::new()) + } }; ParseStatementLog : Statement = { From 602d0527e79ae0e74c56a1de383bf5bd51926ef7 Mon Sep 17 00:00:00 2001 From: clararod9 Date: Sat, 9 Nov 2024 10:53:46 +0100 Subject: [PATCH 21/22] adding flag: --constraint_assert_dissabled to removed the asserts in the generated c++/wasm code generated by the === instructions --- circom/src/compilation_user.rs | 8 +- circom/src/input_user.rs | 17 ++++ circom/src/main.rs | 1 + compiler/src/circuit_design/build.rs | 12 ++- compiler/src/circuit_design/circuit.rs | 1 + compiler/src/compiler_interface.rs | 7 +- .../intermediate_representation/translate.rs | 97 ++++++++++--------- 7 files changed, 92 insertions(+), 51 deletions(-) diff --git a/circom/src/compilation_user.rs b/circom/src/compilation_user.rs index c2b03bfa7..123bd40ac 100644 --- a/circom/src/compilation_user.rs +++ b/circom/src/compilation_user.rs @@ -21,6 +21,7 @@ pub struct CompilerConfig { pub c_flag: bool, pub debug_output: bool, pub produce_input_log: bool, + pub constraint_assert_dissabled_flag: bool, pub vcp: VCP, } @@ -30,7 +31,12 @@ pub fn compile(config: CompilerConfig) -> Result<(), ()> { if config.c_flag || config.wat_flag || config.wasm_flag{ let circuit = compiler_interface::run_compiler( config.vcp, - Config { debug_output: config.debug_output, produce_input_log: config.produce_input_log, wat_flag: config.wat_flag }, + Config { + debug_output: config.debug_output, + produce_input_log: config.produce_input_log, + wat_flag: config.wat_flag, + constraint_assert_dissabled_flag: config.constraint_assert_dissabled_flag, + }, VERSION )?; diff --git a/circom/src/input_user.rs b/circom/src/input_user.rs index d396d3dbd..97394ceea 100644 --- a/circom/src/input_user.rs +++ b/circom/src/input_user.rs @@ -27,6 +27,7 @@ pub struct Input { pub fast_flag: bool, pub reduced_simplification_flag: bool, pub parallel_simplification_flag: bool, + pub constraint_assert_dissabled_flag: bool, pub flag_old_heuristics: bool, pub inspect_constraints_flag: bool, pub no_rounds: usize, @@ -101,6 +102,7 @@ impl Input { fast_flag: o_style == SimplificationStyle::O0, reduced_simplification_flag: o_style == SimplificationStyle::O1, parallel_simplification_flag: input_processing::get_parallel_simplification(&matches), + constraint_assert_dissabled_flag: input_processing::get_constraint_assert_dissabled(&matches), inspect_constraints_flag: input_processing::get_inspect_constraints(&matches), flag_old_heuristics: input_processing::get_flag_old_heuristics(&matches), flag_verbose: input_processing::get_flag_verbose(&matches), @@ -209,6 +211,9 @@ impl Input { pub fn parallel_simplification_flag(&self) -> bool { self.parallel_simplification_flag } + pub fn constraint_assert_dissabled_flag(&self) -> bool { + self.constraint_assert_dissabled_flag + } pub fn flag_old_heuristics(&self) -> bool { self.flag_old_heuristics } @@ -304,6 +309,10 @@ mod input_processing { matches.is_present("parallel_simplification") } + pub fn get_constraint_assert_dissabled(matches: &ArgMatches) -> bool { + matches.is_present("constraint_assert_dissabled") + } + pub fn get_ir(matches: &ArgMatches) -> bool { matches.is_present("print_ir") } @@ -477,6 +486,14 @@ mod input_processing { .display_order(180) .help("Runs non-linear simplification in parallel"), ) + .arg( + Arg::with_name("constraint_assert_dissabled") + .long("constraint_assert_dissabled") + .takes_value(false) + .hidden(false) + .display_order(810) + .help("Does not add asserts in the generated code for === constraint equalities"), + ) .arg( Arg::with_name("main_inputs_log") .long("inputs") diff --git a/circom/src/main.rs b/circom/src/main.rs index 614bad155..735641d22 100644 --- a/circom/src/main.rs +++ b/circom/src/main.rs @@ -61,6 +61,7 @@ fn start() -> Result<(), ()> { wat_file: user_input.wat_file().to_string(), wasm_file: user_input.wasm_file().to_string(), produce_input_log: user_input.main_inputs_flag(), + constraint_assert_dissabled_flag: user_input.constraint_assert_dissabled_flag() }; compilation_user::compile(compilation_config)?; Result::Ok(()) diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 4f7c57366..99075c6e4 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -25,6 +25,7 @@ fn build_template_instances( c_info: &CircuitInfo, ti: Vec, mut field_tracker: FieldTracker, + constraint_assert_dissabled_flag: bool ) -> (FieldTracker, HashMap) { fn compute_jump(lengths: &Vec, indexes: &[usize]) -> usize { @@ -99,6 +100,7 @@ fn build_template_instances( template_database: &c_info.template_database, string_table : string_table, signals_to_tags: template.signals_to_tags, + constraint_assert_dissabled_flag }; let mut template_info = TemplateCodeInfo { name, @@ -134,7 +136,8 @@ fn build_function_instances( c_info: &CircuitInfo, instances: Vec, mut field_tracker: FieldTracker, - mut string_table : HashMap + mut string_table : HashMap, + constraint_assert_dissabled_flag: bool, ) -> (FieldTracker, HashMap, HashMap) { let mut function_to_arena_size = HashMap::new(); for instance in instances { @@ -163,7 +166,8 @@ fn build_function_instances( template_database: &c_info.template_database, string_table : string_table, signals_to_tags: HashMap::new(), - buses: &c_info.buses + buses: &c_info.buses, + constraint_assert_dissabled_flag }; let mut function_info = FunctionCodeInfo { name, @@ -598,9 +602,9 @@ pub fn build_circuit(vcp: VCP, flag: CompilationFlags, version: &str) -> Circuit }; let (field_tracker, string_table) = - build_template_instances(&mut circuit, &circuit_info, vcp.templates, field_tracker); + build_template_instances(&mut circuit, &circuit_info, vcp.templates, field_tracker, flag.constraint_assert_dissabled_flag); let (field_tracker, function_to_arena_size, table_string_to_usize) = - build_function_instances(&mut circuit, &circuit_info, vcp.functions, field_tracker,string_table); + build_function_instances(&mut circuit, &circuit_info, vcp.functions, field_tracker,string_table, flag.constraint_assert_dissabled_flag); let table_usize_to_string = create_table_usize_to_string(table_string_to_usize); circuit.wasm_producer.set_string_table(table_usize_to_string.clone()); diff --git a/compiler/src/circuit_design/circuit.rs b/compiler/src/circuit_design/circuit.rs index 8dee26286..98397f4f5 100644 --- a/compiler/src/circuit_design/circuit.rs +++ b/compiler/src/circuit_design/circuit.rs @@ -10,6 +10,7 @@ use std::io::Write; pub struct CompilationFlags { pub main_inputs_log: bool, pub wat_flag:bool, + pub constraint_assert_dissabled_flag: bool } pub struct Circuit { diff --git a/compiler/src/compiler_interface.rs b/compiler/src/compiler_interface.rs index cb84476c8..311be447b 100644 --- a/compiler/src/compiler_interface.rs +++ b/compiler/src/compiler_interface.rs @@ -7,10 +7,15 @@ pub struct Config { pub debug_output: bool, pub produce_input_log: bool, pub wat_flag: bool, + pub constraint_assert_dissabled_flag: bool } pub fn run_compiler(vcp: VCP, config: Config, version: &str) -> Result { - let flags = CompilationFlags { main_inputs_log: config.produce_input_log, wat_flag: config.wat_flag }; + let flags = CompilationFlags { + main_inputs_log: config.produce_input_log, + wat_flag: config.wat_flag, + constraint_assert_dissabled_flag: config.constraint_assert_dissabled_flag + }; let circuit = Circuit::build(vcp, flags, version); if config.debug_output { produce_debug_output(&circuit)?; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 6096702b2..2a55f9c75 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -190,7 +190,8 @@ struct Context<'a> { tmp_database: &'a TemplateDB, _functions: &'a HashMap>, cmp_to_type: HashMap, - buses: &'a Vec + buses: &'a Vec, + constraint_assert_dissabled_flag: bool, } fn initialize_parameters(state: &mut State, params: Vec) { @@ -667,53 +668,57 @@ fn translate_constraint_equality(stmt: Statement, state: &mut State, context: &C use Statement::ConstraintEquality; use Expression::Variable; if let ConstraintEquality { meta, lhe, rhe } = stmt { - let starts_at = context.files.get_line(meta.start, meta.get_file_id()).unwrap(); - - let length = if let Variable { meta, name, access} = rhe.clone() { - let def = SymbolDef { meta, symbol: name, acc: access }; - let aux = ProcessedSymbol::new(def, state, context).length; + // if constraint_assert_dissabled is active then do not translate + if !context.constraint_assert_dissabled_flag{ + let starts_at = context.files.get_line(meta.start, meta.get_file_id()).unwrap(); - aux - - // TODO: only multiple if both of them are multiple, if not take the Single one - /* - match aux{ - SizeOption::Single(_) => aux, - SizeOption::Multiple(possible_lengths) =>{ - if let Variable { meta, name, access} = lhe.clone() { - let def_left = SymbolDef { meta, symbol: name, acc: access }; - let aux_left = ProcessedSymbol::new(def_left, state, context).length; - match aux_left{ - SizeOption::Single(v) => SizeOption::Single(v), - SizeOption::Multiple(_) =>{ - SizeOption::Multiple(possible_lengths) + let length = if let Variable { meta, name, access} = rhe.clone() { + let def = SymbolDef { meta, symbol: name, acc: access }; + let aux = ProcessedSymbol::new(def, state, context).length; + + aux + + // TODO: only multiple if both of them are multiple, if not take the Single one + /* + match aux{ + SizeOption::Single(_) => aux, + SizeOption::Multiple(possible_lengths) =>{ + if let Variable { meta, name, access} = lhe.clone() { + let def_left = SymbolDef { meta, symbol: name, acc: access }; + let aux_left = ProcessedSymbol::new(def_left, state, context).length; + match aux_left{ + SizeOption::Single(v) => SizeOption::Single(v), + SizeOption::Multiple(_) =>{ + SizeOption::Multiple(possible_lengths) + } } + } else{ + SizeOption::Single(1) } - } else{ - SizeOption::Single(1) } - } - }*/ - } else { - SizeOption::Single(1) - }; - - - let lhe_pointer = translate_expression(lhe, state, context); - let rhe_pointer = translate_expression(rhe, state, context); - let stack = vec![lhe_pointer, rhe_pointer]; - let equality = ComputeBucket { - line: starts_at, - message_id: state.message_id, - op_aux_no: 0, - op: OperatorType::Eq(length), - stack, + }*/ + } else { + SizeOption::Single(1) + }; + + + let lhe_pointer = translate_expression(lhe, state, context); + let rhe_pointer = translate_expression(rhe, state, context); + let stack = vec![lhe_pointer, rhe_pointer]; + let equality = ComputeBucket { + line: starts_at, + message_id: state.message_id, + op_aux_no: 0, + op: OperatorType::Eq(length), + stack, + } + .allocate(); + let assert_instruction = + AssertBucket { line: starts_at, message_id: state.message_id, evaluate: equality } + .allocate(); + state.code.push(assert_instruction); } - .allocate(); - let assert_instruction = - AssertBucket { line: starts_at, message_id: state.message_id, evaluate: equality } - .allocate(); - state.code.push(assert_instruction); + } else { unimplemented!() } @@ -1883,7 +1888,8 @@ pub struct CodeInfo<'a> { pub component_to_parallel: HashMap, pub string_table: HashMap, pub signals_to_tags: HashMap, BigInt>, - pub buses: &'a Vec + pub buses: &'a Vec, + pub constraint_assert_dissabled_flag: bool } pub struct CodeOutput { @@ -1917,7 +1923,8 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { _functions: code_info.functions, cmp_to_type: code_info.cmp_to_type, tmp_database: code_info.template_database, - buses: code_info.buses + buses: code_info.buses, + constraint_assert_dissabled_flag: code_info.constraint_assert_dissabled_flag, }; create_components(&mut state, &code_info.triggers, code_info.clusters); From faf69bdb2047806d7e0963f08b9c0044e75f570d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clara=20Rodr=C3=ADguez?= Date: Tue, 12 Nov 2024 15:15:42 +0100 Subject: [PATCH 22/22] Update RELEASES.md --- RELEASES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index bf6990919..7af74a6f2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,5 @@ # Release notes -## November 08, 2024 circom 2.2.1 +## November 12, 2024 circom 2.2.1 #### Improvements: - Improving the use and heritance of tags inside buses. Now the values are propagated correctly following the same rules as arrays. - Unassigned inputs: do not executing the circuit twice in C++. @@ -7,6 +7,8 @@ - Handling equality checks with dynamic size in witness generation code. - Improving error messages. - Improving error recovery in parser. +- Adding flag --constraint_assert_dissabled. When this flag is activated the compiler does not add asserts in the generated code (C++, WASM) for === constraint equalities + #### Fixed bugs: - Importing function printDebug removed from WASM (circom tests from circomlib working now).