Skip to content

Commit 8bb0916

Browse files
authored
A pseudorandom number generator. (#56)
Introduces a new utility class `cgsuite.util.Random` that provides a pseudorandom number source.
1 parent 827d8c4 commit 8bb0916

File tree

8 files changed

+93
-7
lines changed

8 files changed

+93
-7
lines changed

lib/core/src/main/resources/org/cgsuite/lang/resources/cgsuite/lang/Collection.cgs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ system class Collection
2222
*/
2323
external def Concat(elements as Collection);
2424

25+
/** The number of elements of this `Collection` that match the
26+
* specified predicate. `predicate` must be a [[Boolean]]-valued
27+
* function.
28+
*/
29+
external def Count(predicate as Function);
30+
2531
/** `true` if there exists an element in this collection
2632
* that satisfies the given predicate.
2733
* `predicate` must be a [[Boolean]]-valued function.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*${cgsuite.banner}*/
2+
3+
/** A pseudorandom number generator.
4+
*
5+
* To construct an instance of `Random`, specify an integer seed:
6+
*
7+
* \display{random := Random(1474)}
8+
*
9+
* Then use the [[#NextInteger]] method to generate output. This example produces integers `n` with `0 <= n < 100`:
10+
*
11+
* \display{random.NextInteger(100)}
12+
*
13+
* \display{[random.NextInteger(100) for n from 1 to 20]}
14+
*/
15+
mutable system class Random(
16+
/** The seed for this `Random`. The seed must satisfy:
17+
*
18+
* `-2^63 <= seed < 2^63`
19+
*/
20+
seed as Integer
21+
)
22+
23+
/** The next `Integer` in this stream of pseudorandom numbers. The output `n` of `NextInteger(upperBound)` will always
24+
* satisfy
25+
*
26+
* `0 <= n < upperBound`
27+
*
28+
* and will be (pseudo-)uniformly distributed within that range.
29+
*/
30+
external def NextInteger(upperBound as Integer);
31+
32+
override def ToOutput := "Random(" + seed.ToOutput + ")";
33+
34+
end

lib/core/src/main/scala/org/cgsuite/core/Integer.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,17 @@ trait Integer extends DyadicRationalNumber with GeneralizedOrdinal {
8787

8888
def bigIntValue: BigInt
8989
override def intValue = {
90-
if (bigIntValue.bigInteger.bitLength() <= 32)
90+
if (bigIntValue.bigInteger.bitLength() < 32)
9191
bigIntValue.intValue
9292
else
9393
throw OverflowException("Overflow.")
9494
}
95-
def longValue = bigIntValue.longValue
95+
def longValue = {
96+
if (bigIntValue.bigInteger.bitLength() < 64)
97+
bigIntValue.longValue
98+
else
99+
throw OverflowException("Overflow.")
100+
}
96101
def floatValue = bigIntValue.floatValue
97102
def doubleValue = bigIntValue.doubleValue
98103
def byteValue = bigIntValue.byteValue

lib/core/src/main/scala/org/cgsuite/lang/SpecialMethods.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package org.cgsuite.lang
33
import org.cgsuite.core._
44
import org.cgsuite.core.impartial.Spawning
55
import org.cgsuite.exception.{EvalException, InvalidArgumentException, NotNumberException}
6-
import org.cgsuite.lang.CgscriptClass.SafeCast
6+
import org.cgsuite.lang.CgscriptClass.{SafeCast, internalize}
77
import org.cgsuite.output.{ScatterPlotOutput, StyledTextOutput}
88
import org.cgsuite.util.{Coordinates, Symmetry, Table}
99

@@ -72,6 +72,10 @@ object SpecialMethods {
7272

7373
"cgsuite.lang.Collection.Adjoin" -> { (collection: Iterable[_], obj: Any) => collection ++ Iterable(obj) },
7474
"cgsuite.lang.Collection.Concat" -> { (collection: Iterable[_], that: Iterable[_]) => collection ++ that },
75+
"cgsuite.lang.Collection.Count" -> { (collection: Iterable[_], fn: Function) =>
76+
validateArity(fn, 1)
77+
internalize(collection.count { x => fn.call(Array(x)).castAs[java.lang.Boolean] }.asInstanceOf[java.lang.Integer])
78+
},
7579
"cgsuite.lang.Collection.Exists" -> { (collection: Iterable[_], fn: Function) =>
7680
validateArity(fn, 1)
7781
collection.exists { x => fn.call(Array(x)).castAs[java.lang.Boolean] }
@@ -168,10 +172,6 @@ object SpecialMethods {
168172

169173
private val specialMethods2: Map[String, (_, _) => Any] = Map(
170174

171-
/*
172-
"cgsuite.util.Graph.FromList" -> { (_: ClassObject, args: (IndexedSeq[Any], IndexedSeq[Any])) =>
173-
Graph(args._1.map { _.asInstanceOf[IndexedSeq[Integer]] }, Option(args._2)) },
174-
*/
175175
"cgsuite.lang.List.Sublist" -> { (list: IndexedSeq[_], range: (Integer, Integer)) =>
176176
list.slice(range._1.intValue - 1, range._2.intValue)
177177
},

lib/core/src/main/scala/org/cgsuite/lang/SystemClassRegistry.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ private[lang] object SystemClassRegistry {
4242

4343
"cgsuite.util.Strip" -> classOf[Strip],
4444
"cgsuite.util.Grid" -> classOf[Grid],
45+
"cgsuite.util.Random" -> classOf[Random],
4546
"cgsuite.util.Symmetry" -> classOf[Symmetry],
4647
"cgsuite.util.DirectedGraph" -> classOf[DirectedGraph[_, _]],
4748
"cgsuite.util.Edge" -> classOf[Graph.Edge[_]],
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.cgsuite.util
2+
3+
import org.cgsuite.core.Integer
4+
import org.cgsuite.core.Values.one
5+
import org.cgsuite.exception.EvalException
6+
7+
class Random(val seed: Integer) {
8+
9+
private val random = new scala.util.Random(seed.longValue)
10+
11+
def nextInteger(upperBound: Integer): Integer = {
12+
if (upperBound < one) {
13+
throw EvalException("Upper bound for `NextInteger` must be >= 1.")
14+
}
15+
val bits = (upperBound - one).lb.intValue + 1
16+
var result: Integer = Integer(BigInt(bits, random))
17+
while (result >= upperBound) {
18+
result = Integer(BigInt(bits, random))
19+
}
20+
result
21+
}
22+
23+
}

lib/core/src/test/scala/org/cgsuite/lang/CgsuiteUtilTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,16 @@ class CgsuiteUtilTest extends CgscriptSpec {
7373

7474
}
7575

76+
"cgsuite.util.Random" should "implement methods correctly" in {
77+
78+
executeTests(Table(
79+
header,
80+
("Construct a Random", "random := Random(1474)", "Random(1474)"),
81+
("Random.NextInteger", "[random.NextInteger(100) for n from 1 to 20]",
82+
"[64,92,17,25,63,58,88,49,0,30,85,46,58,24,72,31,98,61,61,69]"),
83+
("Random overflow", "Random(2^63)", "!!Overflow.")
84+
))
85+
86+
}
87+
7688
}

lib/core/src/test/scala/org/cgsuite/lang/CollectionTestCase.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ object CollectionTestCase {
88
"[]", "[]",
99
adjoin = "[19]",
1010
concat = "[10,*2]",
11+
count = "0",
1112
exists = "false",
1213
flattened = "[]",
1314
forall = "true",
@@ -27,6 +28,7 @@ object CollectionTestCase {
2728
"[0,1,3,9,7,5]", "[0,1,3,9,7,5]",
2829
adjoin = "[0,1,3,9,7,5,19]",
2930
concat = "[0,1,3,9,7,5,10,*2]",
31+
count = "2",
3032
exists = "true",
3133
flattened = "[0,1,3,9,7,5]",
3234
forall = "false",
@@ -46,6 +48,7 @@ object CollectionTestCase {
4648
"""["Winning", "Ways", "Mathematical", "Plays"]""", """["Winning","Ways","Mathematical","Plays"]""",
4749
adjoin = """["Winning","Ways","Mathematical","Plays",19]""",
4850
concat = """["Winning","Ways","Mathematical","Plays",10,*2]""",
51+
count = "!!No operation `>=` for arguments of types `cgsuite.lang.String`, `game.Integer`",
4952
exists = "false",
5053
flattened = """["Winning","Ways","Mathematical","Plays"]""",
5154
forall = "false",
@@ -70,6 +73,7 @@ case class CollectionTestCase(
7073
xOut: String,
7174
adjoin: String,
7275
concat: String,
76+
count: String,
7377
exists: String,
7478
flattened: String,
7579
forall: String,
@@ -89,6 +93,7 @@ case class CollectionTestCase(
8993
(x, xOut),
9094
(s"($x).Adjoin(19)", adjoin),
9195
(s"($x).Concat([10,*2])", concat),
96+
(s"($x).Count(x -> x >= 2 and x < 7)", count),
9297
(s"($x).Exists(x -> x == 7)", exists),
9398
(s"($x).Flattened", flattened),
9499
(s"($x).ForAll(x -> x == 7)", forall),

0 commit comments

Comments
 (0)