@@ -17,14 +17,63 @@ use std::rc::Rc;
1717// upgraded RandomInt and RandomFloat codes should be altered.
1818// see comment https://github.com/trueagi-io/hyperon-experimental/pull/791#discussion_r1824355414
1919
20+ pub const ATOM_TYPE_RANDOM_GENERATOR : Atom = sym ! ( "RandomGenerator" ) ;
21+
22+ #[ derive( Clone , Debug ) ]
23+ pub struct RandomGenerator ( Rc < RefCell < StdRng > > ) ;
24+
25+ impl RandomGenerator {
26+ fn from_os_rng ( ) -> Self {
27+ Self ( Rc :: new ( RefCell :: new ( StdRng :: from_os_rng ( ) ) ) )
28+ }
29+
30+ fn from_seed_u64 ( seed : u64 ) -> Self {
31+ Self ( Rc :: new ( RefCell :: new ( StdRng :: seed_from_u64 ( seed) ) ) )
32+ }
33+
34+ fn reseed_from_u64 ( & self , seed : u64 ) {
35+ * self . 0 . borrow_mut ( ) = StdRng :: seed_from_u64 ( seed) ;
36+ }
37+
38+ fn reset ( & self ) {
39+ * self . 0 . borrow_mut ( ) = StdRng :: from_os_rng ( ) ;
40+ }
41+
42+ fn random_range < T , R > ( & self , range : R ) -> T
43+ where
44+ T : rand:: distr:: uniform:: SampleUniform ,
45+ R : rand:: distr:: uniform:: SampleRange < T > ,
46+ {
47+ self . 0 . borrow_mut ( ) . random_range ( range)
48+ }
49+ }
50+
51+ impl Grounded for RandomGenerator {
52+ fn type_ ( & self ) -> Atom {
53+ ATOM_TYPE_RANDOM_GENERATOR
54+ }
55+ }
56+
57+ impl Display for RandomGenerator {
58+ fn fmt ( & self , f : & mut Formatter ) -> std:: fmt:: Result {
59+ write ! ( f, "RandomGenerator-{:?}" , self . 0 . as_ptr( ) )
60+ }
61+ }
62+
63+ impl PartialEq for RandomGenerator {
64+ fn eq ( & self , other : & Self ) -> bool {
65+ self . 0 . as_ptr ( ) == other. 0 . as_ptr ( )
66+ }
67+ }
68+
2069#[ derive( Clone , Debug ) ]
2170pub struct RandomIntOp { }
2271
2372grounded_op ! ( RandomIntOp , "random-int" ) ;
2473
2574impl Grounded for RandomIntOp {
2675 fn type_ ( & self ) -> Atom {
27- Atom :: expr ( [ ARROW_SYMBOL , rust_type_atom :: < Rc < RefCell < StdRng > > > ( ) , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER ] )
76+ Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_RANDOM_GENERATOR , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER ] )
2877 }
2978
3079 fn as_execute ( & self ) -> Option < & dyn CustomExecute > {
@@ -38,12 +87,12 @@ impl CustomExecute for RandomIntOp {
3887 let generator = args. get ( 0 ) . ok_or_else ( arg_error) ?. into ( ) ;
3988 let start: i64 = args. get ( 1 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
4089 let end: i64 = args. get ( 2 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
41- let generator = Atom :: as_gnd :: < Rc < RefCell < StdRng > > > ( generator) . ok_or ( "random-int expects a random generator as its argument" ) ?;
90+ let generator = Atom :: as_gnd :: < RandomGenerator > ( generator) . ok_or ( "random-int expects a random generator as its argument" ) ?;
4291 let range = start..end;
4392 if range. is_empty ( ) {
44- return Err ( ExecError :: from ( "Range is empty " ) ) ;
93+ return Err ( ExecError :: from ( "RangeIsEmpty " ) ) ;
4594 }
46- Ok ( vec ! [ Atom :: gnd( Number :: Integer ( generator. borrow_mut ( ) . random_range( range) ) ) ] )
95+ Ok ( vec ! [ Atom :: gnd( Number :: Integer ( generator. random_range( range) ) ) ] )
4796 }
4897}
4998
@@ -54,7 +103,7 @@ grounded_op!(RandomFloatOp, "random-float");
54103
55104impl Grounded for RandomFloatOp {
56105 fn type_ ( & self ) -> Atom {
57- Atom :: expr ( [ ARROW_SYMBOL , rust_type_atom :: < Rc < RefCell < StdRng > > > ( ) , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER ] )
106+ Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_RANDOM_GENERATOR , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER , ATOM_TYPE_NUMBER ] )
58107 }
59108
60109 fn as_execute ( & self ) -> Option < & dyn CustomExecute > {
@@ -68,12 +117,12 @@ impl CustomExecute for RandomFloatOp {
68117 let generator = args. get ( 0 ) . ok_or_else ( arg_error) ?. into ( ) ;
69118 let start: f64 = args. get ( 1 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
70119 let end: f64 = args. get ( 2 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
71- let generator: & Rc < RefCell < StdRng > > = Atom :: as_gnd :: < Rc < RefCell < StdRng > > > ( generator) . ok_or ( "random-float expects a random generator as its argument" ) ?;
120+ let generator = Atom :: as_gnd :: < RandomGenerator > ( generator) . ok_or ( "random-float expects a random generator as its argument" ) ?;
72121 let range = start..end;
73122 if range. is_empty ( ) {
74- return Err ( ExecError :: from ( "Range is empty " ) ) ;
123+ return Err ( ExecError :: from ( "RangeIsEmpty " ) ) ;
75124 }
76- Ok ( vec ! [ Atom :: gnd( Number :: Float ( generator. borrow_mut ( ) . random_range( range) ) ) ] )
125+ Ok ( vec ! [ Atom :: gnd( Number :: Float ( generator. random_range( range) ) ) ] )
77126 }
78127}
79128
@@ -84,7 +133,7 @@ grounded_op!(SetRandomSeedOp, "set-random-seed");
84133
85134impl Grounded for SetRandomSeedOp {
86135 fn type_ ( & self ) -> Atom {
87- Atom :: expr ( [ ARROW_SYMBOL , rust_type_atom :: < Rc < RefCell < StdRng > > > ( ) , ATOM_TYPE_NUMBER , UNIT_TYPE ] )
136+ Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_RANDOM_GENERATOR , ATOM_TYPE_NUMBER , UNIT_TYPE ] )
88137 }
89138
90139 fn as_execute ( & self ) -> Option < & dyn CustomExecute > {
@@ -97,8 +146,8 @@ impl CustomExecute for SetRandomSeedOp {
97146 let arg_error = || ExecError :: from ( "set-random-seed expects two arguments: random generator and number (seed)" ) ;
98147 let generator = args. get ( 0 ) . ok_or_else ( arg_error) ?. into ( ) ;
99148 let seed: i64 = args. get ( 1 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
100- let generator: & Rc < RefCell < StdRng > > = Atom :: as_gnd :: < Rc < RefCell < StdRng > > > ( generator) . ok_or ( "set-random-seed expects a random generator as its argument" ) ?;
101- * generator. borrow_mut ( ) = StdRng :: seed_from_u64 ( seed as u64 ) ;
149+ let generator = Atom :: as_gnd :: < RandomGenerator > ( generator) . ok_or ( "set-random-seed expects a random generator as its argument" ) ?;
150+ generator. reseed_from_u64 ( seed as u64 ) ;
102151 Ok ( vec ! [ UNIT_ATOM ] )
103152 }
104153}
@@ -110,7 +159,7 @@ grounded_op!(NewRandomGeneratorOp, "new-random-generator");
110159
111160impl Grounded for NewRandomGeneratorOp {
112161 fn type_ ( & self ) -> Atom {
113- Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_NUMBER , rust_type_atom :: < Rc < RefCell < StdRng > > > ( ) ] )
162+ Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_NUMBER , ATOM_TYPE_RANDOM_GENERATOR ] )
114163 }
115164
116165 fn as_execute ( & self ) -> Option < & dyn CustomExecute > {
@@ -122,8 +171,8 @@ impl CustomExecute for NewRandomGeneratorOp {
122171 fn execute ( & self , args : & [ Atom ] ) -> Result < Vec < Atom > , ExecError > {
123172 let arg_error = || ExecError :: from ( "new-random-generator expects one argument: number (seed)" ) ;
124173 let seed: i64 = args. get ( 0 ) . and_then ( Number :: from_atom) . ok_or_else ( arg_error) ?. into ( ) ;
125- let new_generator: Rc < RefCell < StdRng > > = Rc :: new ( RefCell :: new ( StdRng :: seed_from_u64 ( seed as u64 ) ) ) ;
126- Ok ( vec ! [ Atom :: value ( new_generator) ] )
174+ let new_generator = RandomGenerator :: from_seed_u64 ( seed as u64 ) ;
175+ Ok ( vec ! [ Atom :: gnd ( new_generator) ] )
127176 }
128177}
129178
@@ -134,7 +183,7 @@ grounded_op!(ResetRandomGeneratorOp, "reset-random-generator");
134183
135184impl Grounded for ResetRandomGeneratorOp {
136185 fn type_ ( & self ) -> Atom {
137- Atom :: expr ( [ ARROW_SYMBOL , rust_type_atom :: < Rc < RefCell < StdRng > > > ( ) , UNIT_ATOM ] )
186+ Atom :: expr ( [ ARROW_SYMBOL , ATOM_TYPE_RANDOM_GENERATOR , UNIT_ATOM ] )
138187 }
139188
140189 fn as_execute ( & self ) -> Option < & dyn CustomExecute > {
@@ -146,8 +195,8 @@ impl CustomExecute for ResetRandomGeneratorOp {
146195 fn execute ( & self , args : & [ Atom ] ) -> Result < Vec < Atom > , ExecError > {
147196 let arg_error = || ExecError :: from ( "reset-random-generator expects one argument: random generator" ) ;
148197 let generator = args. get ( 0 ) . ok_or_else ( arg_error) ?. into ( ) ;
149- let generator: & Rc < RefCell < StdRng > > = Atom :: as_gnd :: < Rc < RefCell < StdRng > > > ( generator) . ok_or ( "set-random-seed expects a random generator as its argument" ) ?;
150- * generator. borrow_mut ( ) = StdRng :: from_os_rng ( ) ;
198+ let generator = Atom :: as_gnd :: < RandomGenerator > ( generator) . ok_or ( "set-random-seed expects a random generator as its argument" ) ?;
199+ generator. reset ( ) ;
151200 Ok ( vec ! [ UNIT_ATOM ] )
152201 }
153202}
@@ -190,8 +239,8 @@ pub fn register_common_tokens(tref: &mut Tokenizer) {
190239 tref. register_token ( regex ( r"new-random-generator" ) , move |_| { new_random_generator_op. clone ( ) } ) ;
191240 let reset_random_generator_op = Atom :: gnd ( ResetRandomGeneratorOp { } ) ;
192241 tref. register_token ( regex ( r"reset-random-generator" ) , move |_| { reset_random_generator_op. clone ( ) } ) ;
193- let generator = Rc :: new ( RefCell :: new ( StdRng :: from_os_rng ( ) ) ) ;
194- tref. register_token ( regex ( r"&rng" ) , move |_| { Atom :: value ( generator. clone ( ) ) } ) ;
242+ let generator = RandomGenerator :: from_os_rng ( ) ;
243+ tref. register_token ( regex ( r"&rng" ) , move |_| { Atom :: gnd ( generator. clone ( ) ) } ) ;
195244 let flip_op = Atom :: gnd ( FlipOp { } ) ;
196245 tref. register_token ( regex ( r"flip" ) , move |_| { flip_op. clone ( ) } ) ;
197246}
@@ -203,66 +252,76 @@ mod tests {
203252
204253 #[ test]
205254 fn metta_random ( ) {
206- assert_eq ! ( run_program( & format!( "!(chain (eval (random-int &rng 0 5)) $rint (and (>= $rint 0) (< $rint 5)))" ) ) , Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
207- // assert_eq!(run_program(&format!(
208- // "!(assertEqual
209- // (random-int &rng 5 0)
210- // (Error (random-int &rng 5 0) \"Range is empty\"))")),
211- // Ok(vec![vec![UNIT_ATOM]]));
212- assert_eq ! ( run_program( & format!( "!(chain (eval (random-float &rng 0.0 5.0)) $rfloat (and (>= $rfloat 0.0) (< $rfloat 5.0)))" ) ) , Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
213- // assert_eq!(run_program(&format!(
214- // "!(assertEqual
215- // (random-float &rng 5 0)
216- // (Error (random-float &rng 5 0) \"Range is empty\"))")),
217- // Ok(vec![vec![UNIT_ATOM]]));
255+ assert_eq ! ( run_program( & format!(
256+ "!(chain (eval (random-int &rng 0 5)) $rint
257+ (and (>= $rint 0) (< $rint 5)))" ) ) ,
258+ Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
259+ assert_eq ! ( run_program( & format!(
260+ "!(assertEqual
261+ (random-int &rng 5 0)
262+ (Error (random-int &rng 5 0) RangeIsEmpty))" ) ) ,
263+ Ok ( vec![ vec![ UNIT_ATOM ] ] ) ) ;
264+ assert_eq ! ( run_program( & format!(
265+ "!(chain (eval (random-float &rng 0.0 5.0)) $rfloat
266+ (and (>= $rfloat 0.0) (< $rfloat 5.0)))" ) ) ,
267+ Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
268+ assert_eq ! ( run_program( & format!(
269+ "!(assertEqual
270+ (random-float &rng 5 0)
271+ (Error (random-float &rng 5 0) RangeIsEmpty))" ) ) ,
272+ Ok ( vec![ vec![ UNIT_ATOM ] ] ) ) ;
218273
219274 assert_eq ! ( run_program( & format!( "!(set-random-seed &rng 0)" ) ) , Ok ( vec![ vec![ UNIT_ATOM ] ] ) ) ;
220275
221- assert_eq ! ( run_program( & format!(
222- " !(bind! &newrng (new-random-generator 0))\
223- !(random-float &newrng 0 10)"
224- ) ) , run_program( & format!(
225- " !(bind! &newrng (new-random-generator 0))\
226- !(random-float &newrng 0 10)"
227- ) ) ) ;
276+ assert_eq ! ( run_program( & format!( "
277+ !(bind! &newrng (new-random-generator 0))
278+ !(random-float &newrng 0 10)
279+ " ) ) , run_program( & format!( "
280+ !(bind! &newrng (new-random-generator 0))
281+ !(random-float &newrng 0 10)
282+ " ) ) ) ;
228283
229284 assert_eq ! ( run_program( & format!(
230- "!(let $newrng (new-random-generator 0)\
231- (let $t (set-random-seed $newrng 5)\
232- (let $res_1 (random-float $newrng 0 5)\
233- (let $t2 (set-random-seed $newrng 5)\
234- (let $res_2 (random-float $newrng 0 5)\
285+ "!(let $newrng (new-random-generator 0)
286+ (let $t (set-random-seed $newrng 5)
287+ (let $res_1 (random-float $newrng 0 5)
288+ (let $t2 (set-random-seed $newrng 5)
289+ (let $res_2 (random-float $newrng 0 5)
235290 (== $res_1 $res_2))))))"
236- ) ) ,
237- Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
291+ ) ) , Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
238292
239293 assert_eq ! ( run_program( & format!(
240- "!(let $seededrng (new-random-generator 0) \
241- (let $seededrng2 (new-random-generator 0) \
242- (let $t (reset-random-generator $seededrng) \
243- (let $rfloat (random-float $seededrng 0 100) \
244- (let $rfloat2 (random-float $seededrng2 0 100) \
294+ "!(let $seededrng (new-random-generator 0)
295+ (let $seededrng2 (new-random-generator 0)
296+ (let $t (reset-random-generator $seededrng)
297+ (let $rfloat (random-float $seededrng 0 100)
298+ (let $rfloat2 (random-float $seededrng2 0 100)
245299 (== $rfloat $rfloat2))))) )"
246- ) ) ,
247- Ok ( vec![ vec![ expr!( { Bool ( false ) } ) ] ] ) ) ;
248- assert_eq ! ( run_program( & format!( "!(let $newrng (new-random-generator 0) (let $t (reset-random-generator $newrng) (let $res (random-float $newrng 0 5) (and (>= $res 0.0) (< $res 5.0)))))" ) ) , Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
300+ ) ) , Ok ( vec![ vec![ expr!( { Bool ( false ) } ) ] ] ) ) ;
301+
302+ assert_eq ! ( run_program( & format!( "
303+ !(let $newrng (new-random-generator 0)
304+ (let $t (reset-random-generator $newrng)
305+ (let $res (random-float $newrng 0 5)
306+ (and (>= $res 0.0) (< $res 5.0)))))" ) ) ,
307+ Ok ( vec![ vec![ expr!( { Bool ( true ) } ) ] ] ) ) ;
249308 }
250309
251310 #[ test]
252311 fn random_op ( ) {
253- let res = RandomIntOp { } . execute ( & mut vec ! [ expr!( { Rc :: new ( RefCell :: new ( StdRng :: from_os_rng( ) ) ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 5 ) } ) ] ) ;
312+ let res = RandomIntOp { } . execute ( & mut vec ! [ expr!( { RandomGenerator :: from_os_rng( ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 5 ) } ) ] ) ;
254313 let range = 0 ..5 ;
255314 let res_i64: i64 = res. unwrap ( ) . get ( 0 ) . and_then ( Number :: from_atom) . unwrap ( ) . into ( ) ;
256315 assert ! ( range. contains( & res_i64) ) ;
257- let res = RandomIntOp { } . execute ( & mut vec ! [ expr!( { Rc :: new ( RefCell :: new ( StdRng :: from_os_rng( ) ) ) } ) , expr!( { Number :: Integer ( 2 ) } ) , expr!( { Number :: Integer ( -2 ) } ) ] ) ;
258- assert_eq ! ( res, Err ( ExecError :: from( "Range is empty " ) ) ) ;
316+ let res = RandomIntOp { } . execute ( & mut vec ! [ expr!( { RandomGenerator :: from_os_rng( ) } ) , expr!( { Number :: Integer ( 2 ) } ) , expr!( { Number :: Integer ( -2 ) } ) ] ) ;
317+ assert_eq ! ( res, Err ( ExecError :: from( "RangeIsEmpty " ) ) ) ;
259318
260- let res = RandomFloatOp { } . execute ( & mut vec ! [ expr!( { Rc :: new ( RefCell :: new ( StdRng :: from_os_rng( ) ) ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 5 ) } ) ] ) ;
319+ let res = RandomFloatOp { } . execute ( & mut vec ! [ expr!( { RandomGenerator :: from_os_rng( ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 5 ) } ) ] ) ;
261320 let range = 0.0 ..5.0 ;
262321 let res_f64: f64 = res. unwrap ( ) . get ( 0 ) . and_then ( Number :: from_atom) . unwrap ( ) . into ( ) ;
263322 assert ! ( range. contains( & res_f64) ) ;
264- let res = RandomFloatOp { } . execute ( & mut vec ! [ expr!( { Rc :: new ( RefCell :: new ( StdRng :: from_os_rng( ) ) ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 0 ) } ) ] ) ;
265- assert_eq ! ( res, Err ( ExecError :: from( "Range is empty " ) ) ) ;
323+ let res = RandomFloatOp { } . execute ( & mut vec ! [ expr!( { RandomGenerator :: from_os_rng( ) } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 0 ) } ) ] ) ;
324+ assert_eq ! ( res, Err ( ExecError :: from( "RangeIsEmpty " ) ) ) ;
266325
267326 let gen = NewRandomGeneratorOp { } . execute ( & mut vec ! [ expr!( { Number :: Integer ( 0 ) } ) ] ) ;
268327 let res1 = RandomFloatOp { } . execute ( & mut vec ! [ expr!( { gen } ) , expr!( { Number :: Integer ( 0 ) } ) , expr!( { Number :: Integer ( 5 ) } ) ] ) ;
0 commit comments