@@ -6,6 +6,7 @@ use itertools::Itertools;
6
6
use num_bigint:: BigUint ;
7
7
use num_traits:: { One , Zero } ;
8
8
use std:: fmt:: Display ;
9
+ use crate :: BooleanFunctionError ;
9
10
10
11
#[ derive( Debug , Clone , Eq , PartialEq ) ]
11
12
enum PolynomialFormat {
@@ -122,6 +123,70 @@ impl AnfPolynomial {
122
123
. join ( " + " )
123
124
}
124
125
126
+ /// Computes the ANF polynomial from string representation
127
+ ///
128
+ /// Representation must be in the form "`x0*x2*x3 + x2*x3 + x1 + 1`".
129
+ ///
130
+ /// X's index start at 0, meaning the maximum index is variable count - 1.
131
+ ///
132
+ /// # Parameters:
133
+ /// - `anf_polynomial`: The string representation of the ANF form
134
+ /// - `num_variables`: Variable count of the polynomial
135
+ ///
136
+ /// # Returns:
137
+ /// The ANF polynomial, or an error if the input string doesn't respect the format and `unsafe_disable_safety_checks` feature is not activated.
138
+ pub fn from_str ( anf_polynomial : & str , num_variables : usize ) -> Result < Self , BooleanFunctionError > {
139
+ let anf_polynomial_filtered = anf_polynomial. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . collect :: < String > ( ) ;
140
+
141
+ let mut anf_polynomial_obj = Self {
142
+ polynomial : if num_variables <= 6 {
143
+ PolynomialFormat :: Small ( 0u64 )
144
+ } else {
145
+ PolynomialFormat :: Big ( BigUint :: zero ( ) )
146
+ } ,
147
+ num_variables,
148
+ } ;
149
+
150
+ for monomial_string in anf_polynomial_filtered. split ( '+' ) {
151
+ if monomial_string == "1" {
152
+ anf_polynomial_obj. flip_bit_pos ( 0 ) ?;
153
+ continue ;
154
+ }
155
+ let mut bit_position_to_flip = 0u64 ;
156
+ for factor in monomial_string. split ( '*' ) {
157
+ #[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
158
+ if factor. chars ( ) . nth ( 0 ) . ok_or ( BooleanFunctionError :: ErrorParsingAnfString ) ? != 'x' {
159
+ return Err ( BooleanFunctionError :: ErrorParsingAnfString ) ;
160
+ }
161
+ let factor_index = factor[ 1 ..] . parse :: < u64 > ( ) . map_err ( |_| BooleanFunctionError :: ErrorParsingAnfString ) ?;
162
+ #[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
163
+ if factor_index as usize >= num_variables {
164
+ return Err ( BooleanFunctionError :: AnfFormNVariableTooBigFactor ( num_variables, factor_index as usize ) ) ;
165
+ }
166
+ bit_position_to_flip |= 1 << factor_index;
167
+ }
168
+ anf_polynomial_obj. flip_bit_pos ( bit_position_to_flip) ?;
169
+ }
170
+
171
+ Ok ( anf_polynomial_obj)
172
+ }
173
+
174
+ fn flip_bit_pos ( & mut self , bit_position : u64 ) -> Result < ( ) , BooleanFunctionError > {
175
+ #[ cfg( not( feature = "unsafe_disable_safety_checks" ) ) ]
176
+ if bit_position >= 1 << self . num_variables {
177
+ return Err ( BooleanFunctionError :: UnexpectedError ) ;
178
+ }
179
+ match & mut self . polynomial {
180
+ PolynomialFormat :: Small ( anf) => {
181
+ * anf ^= 1u64 << bit_position
182
+ } ,
183
+ PolynomialFormat :: Big ( anf) => {
184
+ anf. set_bit ( bit_position, !anf. bit ( bit_position) )
185
+ }
186
+ }
187
+ Ok ( ( ) )
188
+ }
189
+
125
190
/// Monomial and number of variables in the monomial
126
191
fn bit_monomial_to_string ( & self , bit_position : u64 ) -> ( String , usize ) {
127
192
if bit_position == 0 {
@@ -133,6 +198,17 @@ impl AnfPolynomial {
133
198
. collect ( ) ;
134
199
( monomial_coefs_list. join ( "*" ) , monomial_coefs_list. len ( ) )
135
200
}
201
+
202
+ /// Returns Boolean function internal storage type:
203
+ ///
204
+ /// - [Small](crate::BooleanFunctionType::Small) for `u64` internal storage (less or equal than 6 variables Boolean function)
205
+ /// - [Big](crate::BooleanFunctionType::Big) for `BigUInt` internal storage (more than 6 variables Boolean function)
206
+ pub fn get_boolean_function_type ( & self ) -> crate :: BooleanFunctionType {
207
+ match self . polynomial {
208
+ PolynomialFormat :: Small ( _) => crate :: BooleanFunctionType :: Small ,
209
+ PolynomialFormat :: Big ( _) => crate :: BooleanFunctionType :: Big
210
+ }
211
+ }
136
212
}
137
213
138
214
/// Display implementation for `AnfPolynomial`.
@@ -149,6 +225,7 @@ mod tests {
149
225
use crate :: anf_polynom:: AnfPolynomial ;
150
226
use num_bigint:: BigUint ;
151
227
use num_traits:: { Num , One , Zero } ;
228
+ use crate :: BooleanFunctionError ;
152
229
153
230
#[ test]
154
231
fn test_get_polynomial_small ( ) {
@@ -237,4 +314,47 @@ mod tests {
237
314
let anf_polynomial = AnfPolynomial :: from_anf_big ( & BigUint :: one ( ) , 3 ) ;
238
315
assert_eq ! ( anf_polynomial. to_string( ) , "1" ) ;
239
316
}
317
+
318
+ #[ test]
319
+ fn test_from_str ( ) {
320
+ let anf_str = "x0*x1 + x0 + x0 + x0 + 1" ;
321
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
322
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1 + x0 + 1" ) ;
323
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
324
+
325
+ let anf_str = "x2 + x0*x1 + x0" ;
326
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) . unwrap ( ) ;
327
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1 + x0 + x2" ) ;
328
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Small ) ;
329
+
330
+ let anf_str = "x0*x1 + x2 + x0 + 1" ;
331
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 2 ) ;
332
+ assert ! ( anf_polynomial. is_err( ) ) ;
333
+ assert_eq ! ( anf_polynomial. unwrap_err( ) , BooleanFunctionError :: AnfFormNVariableTooBigFactor ( 2 , 2 ) ) ;
334
+
335
+ let anf_str = "x0*y1 + x2 + x0 + 1" ;
336
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) ;
337
+ assert ! ( anf_polynomial. is_err( ) ) ;
338
+ assert_eq ! ( anf_polynomial. unwrap_err( ) , BooleanFunctionError :: ErrorParsingAnfString ) ;
339
+
340
+ let anf_str = "x0*xy1 + x2 + x0 + 1" ;
341
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 3 ) ;
342
+ assert ! ( anf_polynomial. is_err( ) ) ;
343
+ assert_eq ! ( anf_polynomial. unwrap_err( ) , BooleanFunctionError :: ErrorParsingAnfString ) ;
344
+
345
+ let anf_str = "x0*x1*x2*x3*x4*x5*x6 + x7 + x6 + x6 + 1" ;
346
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 8 ) . unwrap ( ) ;
347
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1*x2*x3*x4*x5*x6 + x7 + 1" ) ;
348
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Big ) ;
349
+
350
+ let anf_str = "x0*x1*x2*x3*x4*x5*x6 + x7" ;
351
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 8 ) . unwrap ( ) ;
352
+ assert_eq ! ( anf_polynomial. to_string( ) , "x0*x1*x2*x3*x4*x5*x6 + x7" ) ;
353
+ assert_eq ! ( anf_polynomial. get_boolean_function_type( ) , crate :: BooleanFunctionType :: Big ) ;
354
+
355
+ let anf_str = "x0x1*x2*x3*x4*x5*x6 + x7" ;
356
+ let anf_polynomial = AnfPolynomial :: from_str ( anf_str, 8 ) ;
357
+ assert ! ( anf_polynomial. is_err( ) ) ;
358
+ assert_eq ! ( anf_polynomial. unwrap_err( ) , BooleanFunctionError :: ErrorParsingAnfString ) ;
359
+ }
240
360
}
0 commit comments