@@ -2,7 +2,17 @@ use std::collections::hash_map::DefaultHasher;
22use std:: hash:: { Hash , Hasher } ;
33use std:: ops:: Not ;
44
5- use biodivine_lib_bdd:: Bdd as RsBdd ;
5+ use crate :: AsNative ;
6+ use crate :: bindings:: lib_bdd:: bdd:: Bdd ;
7+ use crate :: bindings:: lib_param_bn:: symbolic:: model_color:: ColorModel ;
8+ use crate :: bindings:: lib_param_bn:: symbolic:: set_colored_space:: ColoredSpaceSet ;
9+ use crate :: bindings:: lib_param_bn:: symbolic:: set_colored_vertex:: ColoredVertexSet ;
10+ use crate :: bindings:: lib_param_bn:: symbolic:: set_spaces:: SpaceSet ;
11+ use crate :: bindings:: lib_param_bn:: symbolic:: set_vertex:: VertexSet ;
12+ use crate :: bindings:: lib_param_bn:: symbolic:: symbolic_context:: SymbolicContext ;
13+ use crate :: bindings:: pbn_control:: { ColoredPerturbationSet , PerturbationSet } ;
14+ use biodivine_lib_bdd:: random_sampling:: UniformValuationSampler ;
15+ use biodivine_lib_bdd:: { Bdd as RsBdd , BddPartialValuation } ;
616use biodivine_lib_param_bn:: biodivine_std:: traits:: Set ;
717use biodivine_lib_param_bn:: symbolic_async_graph:: projected_iteration:: {
818 OwnedRawSymbolicIterator , RawProjection ,
@@ -15,16 +25,8 @@ use pyo3::IntoPyObjectExt;
1525use pyo3:: basic:: CompareOp ;
1626use pyo3:: prelude:: * ;
1727use pyo3:: types:: PyList ;
18-
19- use crate :: AsNative ;
20- use crate :: bindings:: lib_bdd:: bdd:: Bdd ;
21- use crate :: bindings:: lib_param_bn:: symbolic:: model_color:: ColorModel ;
22- use crate :: bindings:: lib_param_bn:: symbolic:: set_colored_space:: ColoredSpaceSet ;
23- use crate :: bindings:: lib_param_bn:: symbolic:: set_colored_vertex:: ColoredVertexSet ;
24- use crate :: bindings:: lib_param_bn:: symbolic:: set_spaces:: SpaceSet ;
25- use crate :: bindings:: lib_param_bn:: symbolic:: set_vertex:: VertexSet ;
26- use crate :: bindings:: lib_param_bn:: symbolic:: symbolic_context:: SymbolicContext ;
27- use crate :: bindings:: pbn_control:: { ColoredPerturbationSet , PerturbationSet } ;
28+ use rand:: SeedableRng ;
29+ use rand:: prelude:: StdRng ;
2830
2931/// A symbolic representation of a set of "colors", i.e., interpretations of explicit and
3032/// implicit parameters within a particular `BooleanNetwork`.
@@ -44,6 +46,20 @@ pub struct _ColorModelIterator {
4446 retained_implicit : Vec < biodivine_lib_param_bn:: VariableId > ,
4547}
4648
49+ /// An internal class used for random uniform sampling of `ColorModel` instances from a `ColorSet`.
50+ /// On the Python side, it just looks like an infinite iterator.
51+ ///
52+ /// Similar to [`_ColorModelIterator`], but uses a sampler to get valuations from the projection
53+ /// BDD instead of iterating it fully.
54+ #[ pyclass( module = "biodivine_aeon" ) ]
55+ pub struct _ColorModelSampler {
56+ ctx : Py < SymbolicContext > ,
57+ projection : RawProjection ,
58+ sampler : UniformValuationSampler < StdRng > ,
59+ retained_explicit : Vec < biodivine_lib_param_bn:: ParameterId > ,
60+ retained_implicit : Vec < biodivine_lib_param_bn:: VariableId > ,
61+ }
62+
4763impl AsNative < GraphColors > for ColorSet {
4864 fn as_native ( & self ) -> & GraphColors {
4965 & self . native
@@ -238,6 +254,75 @@ impl ColorSet {
238254 #[ pyo3( signature = ( retained = None ) ) ]
239255 pub fn items ( & self , retained : Option < & Bound < ' _ , PyList > > ) -> PyResult < _ColorModelIterator > {
240256 let ctx = self . ctx . get ( ) ;
257+ let ( retained, implicit, explicit) = Self :: read_retained_functions ( ctx, retained) ?;
258+
259+ let projection = RawProjection :: new ( retained, self . as_native ( ) . as_bdd ( ) ) ;
260+ Ok ( _ColorModelIterator {
261+ ctx : self . ctx . clone ( ) ,
262+ native : projection. into_iter ( ) ,
263+ retained_implicit : implicit,
264+ retained_explicit : explicit,
265+ } )
266+ }
267+
268+ /// Returns a sampler for random uniform sampling of colors from this `ColorSet` with an
269+ /// optional projection to a subset of uninterpreted functions. **If a projection is specified,
270+ /// the sampling is uniform with respect to the projected set.**
271+ ///
272+ /// See also the `items` method regarding the `retained` projection set.
273+ ///
274+ /// You can specify an optional seed to make the sampling random but deterministic.
275+ #[ pyo3( signature = ( retained = None , seed = None ) ) ]
276+ pub fn sample_items (
277+ & self ,
278+ retained : Option < & Bound < ' _ , PyList > > ,
279+ seed : Option < u64 > ,
280+ ) -> PyResult < _ColorModelSampler > {
281+ let ctx = self . ctx . get ( ) ;
282+ let ( retained, implicit, explicit) = Self :: read_retained_functions ( ctx, retained) ?;
283+ let projection = RawProjection :: new ( retained, self . as_native ( ) . as_bdd ( ) ) ;
284+ let rng = StdRng :: seed_from_u64 ( seed. unwrap_or_default ( ) ) ;
285+ let sampler = projection. bdd ( ) . mk_uniform_valuation_sampler ( rng) ;
286+ Ok ( _ColorModelSampler {
287+ ctx : self . ctx . clone ( ) ,
288+ projection,
289+ sampler,
290+ retained_explicit : explicit,
291+ retained_implicit : implicit,
292+ } )
293+ }
294+ }
295+
296+ impl ColorSet {
297+ pub fn mk_native ( ctx : Py < SymbolicContext > , native : GraphColors ) -> Self {
298+ Self { ctx, native }
299+ }
300+
301+ pub fn mk_derived ( & self , native : GraphColors ) -> ColorSet {
302+ ColorSet {
303+ ctx : self . ctx . clone ( ) ,
304+ native,
305+ }
306+ }
307+
308+ pub fn semantic_eq ( a : & ColorSet , b : & ColorSet ) -> bool {
309+ let a = a. as_native ( ) . as_bdd ( ) ;
310+ let b = b. as_native ( ) . as_bdd ( ) ;
311+ if a. num_vars ( ) != b. num_vars ( ) {
312+ return false ;
313+ }
314+
315+ RsBdd :: binary_op_with_limit ( 1 , a, b, biodivine_lib_bdd:: op_function:: xor) . is_some ( )
316+ }
317+
318+ pub fn read_retained_functions (
319+ ctx : & SymbolicContext ,
320+ retained : Option < & Bound < ' _ , PyList > > ,
321+ ) -> PyResult < (
322+ Vec < biodivine_lib_bdd:: BddVariable > ,
323+ Vec < biodivine_lib_param_bn:: VariableId > ,
324+ Vec < biodivine_lib_param_bn:: ParameterId > ,
325+ ) > {
241326 let mut retained_explicit = Vec :: new ( ) ;
242327 let mut retained_implicit = Vec :: new ( ) ;
243328 let retained = if let Some ( retained) = retained {
@@ -266,41 +351,12 @@ impl ColorSet {
266351 } else {
267352 retained_explicit. append ( & mut ctx. as_native ( ) . network_parameters ( ) . collect :: < Vec < _ > > ( ) ) ;
268353 retained_implicit. append ( & mut ctx. as_native ( ) . network_implicit_parameters ( ) ) ;
269- self . ctx . get ( ) . as_native ( ) . parameter_variables ( ) . clone ( )
354+ ctx. as_native ( ) . parameter_variables ( ) . clone ( )
270355 } ;
271356 retained_explicit. sort ( ) ;
272357 retained_implicit. sort ( ) ;
273358
274- let projection = RawProjection :: new ( retained, self . as_native ( ) . as_bdd ( ) ) ;
275- Ok ( _ColorModelIterator {
276- ctx : self . ctx . clone ( ) ,
277- native : projection. into_iter ( ) ,
278- retained_implicit,
279- retained_explicit,
280- } )
281- }
282- }
283-
284- impl ColorSet {
285- pub fn mk_native ( ctx : Py < SymbolicContext > , native : GraphColors ) -> Self {
286- Self { ctx, native }
287- }
288-
289- pub fn mk_derived ( & self , native : GraphColors ) -> ColorSet {
290- ColorSet {
291- ctx : self . ctx . clone ( ) ,
292- native,
293- }
294- }
295-
296- pub fn semantic_eq ( a : & ColorSet , b : & ColorSet ) -> bool {
297- let a = a. as_native ( ) . as_bdd ( ) ;
298- let b = b. as_native ( ) . as_bdd ( ) ;
299- if a. num_vars ( ) != b. num_vars ( ) {
300- return false ;
301- }
302-
303- RsBdd :: binary_op_with_limit ( 1 , a, b, biodivine_lib_bdd:: op_function:: xor) . is_some ( )
359+ Ok ( ( retained, retained_implicit, retained_explicit) )
304360 }
305361}
306362
@@ -326,3 +382,34 @@ impl _ColorModelIterator {
326382 self . __next__ ( )
327383 }
328384}
385+
386+ #[ pymethods]
387+ impl _ColorModelSampler {
388+ fn __iter__ ( self_ : Py < Self > ) -> Py < Self > {
389+ self_
390+ }
391+
392+ fn __next__ ( & mut self ) -> Option < ColorModel > {
393+ self . projection
394+ . bdd ( )
395+ . random_valuation_sample ( & mut self . sampler )
396+ . map ( |it| {
397+ let mut retained = BddPartialValuation :: empty ( ) ;
398+ for x in self . projection . retained_variables ( ) {
399+ retained. set_value ( * x, it[ * x] ) ;
400+ }
401+
402+ ColorModel :: new_native (
403+ self . ctx . clone ( ) ,
404+ retained,
405+ self . retained_implicit . clone ( ) ,
406+ self . retained_explicit . clone ( ) ,
407+ )
408+ } )
409+ }
410+
411+ #[ allow( clippy:: should_implement_trait) ]
412+ pub fn next ( & mut self ) -> Option < ColorModel > {
413+ self . __next__ ( )
414+ }
415+ }
0 commit comments