When you are a Bear of Very Little Brain, and you Think of Things, you find sometimes that a Thing which seemed very Thingish inside you is quite different when it gets out into the open and has other people looking at it.
final class StatefulLFSR(var seed: Int, val mask: Int = 0x002D) {
import java.lang.Integer.bitCount
def next(): Int = {
seed = (seed >> 1) | ((bitCount(seed & mask) & 1) << 15)
seed
}
}
def three(lfsr: StatefulLFSR): (Int, Int, Int) =
(lfsr.next(), lfsr.next(), lfsr.next())
// scala> three(new StatefulLFSR(0xACE1))
// res0: (Int, Int, Int) = (22128,43832,21916)
def period(lfsr: StatefulLFSR): Int = {
val seed = lfsr.seed
var period = 0
while (seed != lfsr.next()) period += 1
period
}
// scala> period(new StatefulLFSR(0xACE1))
// res1: Int = 65534
def parallel(lfsr: StatefulLFSR)(implicit ec: ExecutionContext): Future[Int] = {
def eSet = Future {
val rs = mutable.Set.empty[Int]
(0 until 10000).foreach(_ => rs += lfsr.next())
rs
}
Future.sequence(List.fill(2)(eSet)).map(_.reduce(_ & _).size)
}
//scala> Await.result(parallel(new StatefulLFSR(0xACE1)), 10.seconds)
//res3: Int = 4325
def parallel(lfsr: StatefulLFSR)(implicit ec: ExecutionContext): Future[Int] = {
def eSet = Future {
val rs = mutable.Set.empty[Int]
(0 until 10000).foreach(_ => rs += lfsr.synchronized(lfsr.next()))
rs
}
Future.sequence(List.fill(2)(eSet)).map(_.reduce(_ & _).size)
}
//scala> Await.result(parallel(new StatefulLFSR(0xACE1)), 10.seconds)
//res4: Int = 0
final case class StatelessLFSR(seed: Int, mask: Int = 0x002D)
object StatelessLFSR {
import java.lang.Integer.bitCount
def next(lfsr: StatelessLFSR): StatelessLFSR = {
import lfsr._
lfsr.copy(seed = (seed >> 1) | ((bitCount(seed & mask) & 1) << 15))
}
}
def three(lfsr: StatelessLFSR): (Int, Int, Int) =
(next(lfsr).seed, next(lfsr).seed, next(lfsr).seed)
//scala> three(new StatelessLFSR(0xACE1))
//res0: (Int, Int, Int) = (22128,22128,22128)
//WTF?!
final case class StatelessLFSR(seed: Int, mask: Int = 0x002D)
object StatelessLFSR {
import java.lang.Integer.bitCount
def next(lfsr: StatelessLFSR): (StatelessLFSR, Int) = {
import lfsr._
val nxt = lfsr.copy(seed = (seed >> 1) | ((bitCount(seed & mask) & 1) << 15))
(nxt, nxt.seed)
}
}
def three(lfsr0: StatelessLFSR): (Int, Int, Int) = {
val (lfsr1, i1) = next(lfsr0)
val (lfsr2, i2) = next(lfsr1)
val (_, i3) = next(lfsr2)
(i1, i2, i3)
}
//scala> three(new StatelessLFSR(0xACE1))
//res1: (Int, Int, Int) = (22128,43832,21916)
def period(lfsr0: StatelessLFSR): Int = {
val seed = lfsr0.seed
var (lfsr1, nxt) = next(lfsr0)
var period = 0
while (seed != nxt) {
// (lfsr1, nxt) = next(lfsr1) would be so cool
val (l, n) = next(lfsr1)
period += 1
lfsr1 = l
nxt = n
}
period
}
//scala> period(new StatelessLFSR(0xACE1))
//res2: Int = 65534
def parallel(lfsr0: StatelessLFSR)(implicit ec: ExecutionContext): Future[Int] = {
def eSet = Future {
(0 until 10000)
.foldLeft(lfsr0 -> immutable.Set.empty[Int]) {
case ((lfsr1, rs), _) =>
val (lfsr2, nxt) = next(lfsr1)
(lfsr2, rs + nxt)
}
._2
}
Future.sequence(List.fill(2)(eSet)).map(_.reduce(_ & _).size)
}
//scala> Await.result(parallel(new StatelessLFSR(0xACE1)), 10.seconds)
//res0: Int = 10000
//
//scala> Await.result(parallel(new StatelessLFSR(0xACE1)), 10.seconds)
//res1: Int = 10000
//WTF?!
def parallel(lfsr0: StatelessLFSR)(implicit ec: ExecutionContext): Future[Int] = {
val ar = new AtomicReference(lfsr0)
def eSet = Future {
(0 until 10000)
.foldLeft(immutable.Set.empty[Int]) {
case (rs, _) =>
var lfsr1 = ar.get()
var (lfsr2, nxt) = next(lfsr1)
var rs1 = rs + nxt
while (!ar.compareAndSet(lfsr1, lfsr2)) {
rs1 -= nxt
lfsr1 = ar.get()
val (l, n) = next(lfsr1)
lfsr2 = l
nxt = n
rs1 = rs1 + nxt
}
rs1
}
}
Future.sequence(List.fill(2)(eSet)).map(_.reduce(_ & _).size)
}
//scala> Await.result(parallel1(new StatelessLFSR(0xACE1)), 10.seconds)
//res3: Int = 0
def next(lfsr: StatelessLFSR): (StatelesLFSR, Int) = ...
val next: (StatelessLFSR) => (StatelessLFSR, Int) = ...
def run[S, A]: (S) => (S, A) = ...
final class State[S, A](val run: (S) => (S, A)) { self =>
val runA: (S) => A = run(_)._2
val runS: (S) => S = run(_)._1
}
object State {
def apply[S, A](f: (S) => (S, A)): State[S, A] = new State[S, A](f)
def inspect[S, A](f: (S) => A): State[S, A] = State(s => (s, f(s)))
def modify[S](f: (S) => S): State[S, Unit] = State(s => (f(s), ()))
def get[S]: State[S, S] = inspect(identity)
def set[S](s: S): State[S, Unit] = modify(_ => s)
def pure[S, A](a: A): State[S, A] = inspect(_ => a)
implicit val StateMonad: Monad[State[S, ?]] =
new Monad[State[S, ?]] { .. }
}
final case class StatelessLFSR(seed: Int, mask: Int = 0x002D)
object StatelessLFSR {
import cats.data.State
import java.lang.Integer.bitCount
type LFSR[A] = State[StatelessLFSR, A]
val next: LFSR[Int] = State { lfsr =>
import lfsr._
val nxt = lfsr.copy(seed = (seed >> 1) | ((bitCount(seed & mask) & 1) << 15))
(nxt, nxt.seed)
}
}
val three: LFSR[(Int, Int, Int)] = for {
i1 <- next
i2 <- next
i3 <- next
} yield (i1, i2, i3)
//three: State[lfsr.StatelessLFSR,(Int, Int, Int)] = cats.data.IndexedStateT@b2b8a14
//scala> three.runA(StatelessLFSR(0xACE1)).value
//res0: (Int, Int, Int) = (22128,43832,21916)
def period(lfsr0: StatelessLFSR): Int = {
val seed = lfsr0.seed
var (lfsr1, nxt) = next.run(lfsr0).value
var period = 0
while (seed != nxt) {
val (l, n) = next.run(lfsr1).value
period += 1
lfsr1 = l
nxt = n
}
period
}
//scala> period(StatelessLFSR(0xACE1))
//res0: Int = 65534
def period(lfsr: StatelessLFSR): Int = {
val seed = lfsr.seed
val go: LFSR[Int] = Monad[LFSR].tailRecM(none[Int] -> 0) {
case (Some(`seed`), p) => State.pure(Right(p))
case (s, p) => next.map(n => Left(n.some -> s.fold(p)(_ => p + 1)))
}
go.runA(StatelessLFSR(seed)).value
}
//scala> period(StatelessLFSR(0xACE1))
//res1: Int = 65534
trait Monad[F[_]] {
// calls f(a) till Right(b)
def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B] = ...
}
package fs2
class Stream[F[_], +O] { .. }
type Pipe[F[_], -I, +O] = Stream[F, I] => Stream[F, O]
type Sink[F[_], -I] = Pipe[F, I, Unit]
class Stream[F[_], +O] {
def map[O2](f: O => O2): Stream[F, O2] = ...
def flatMap[O2](f: O => Stream[F, O2]): Stream[F, O2] = ...
def mapAccumulate[S, O2](init: S)(
f: (S, O) => (S, O2)
): Stream[F, (S, O2)] = ...
// ...
}
def runState[F[_], S, A](init: S): Pipe[F, State[S, A], A] = { in =>
in.mapAccumulate(init)((init, sa) => sa.run(init).value)
.map(_._2)
}
def three(lfsr: StatelessLFSR): List[Int] = Stream
.constant(next) // Stream(next, next, ..)
.through(runState(lfsr)) // (StatelessLFSR, LFSR[A]) => (StatelessLFSR, A)
.take(3) // first 3 elements
.toList // Stream => List
//scala> three(StatelessLFSR(0xACE1))
//res0: List[Int] = List(22128, 43832, 21916)
def period(lfsr: StatelessLFSR): Int = Stream
.constant(next) // Stream(next, next, ..)
.through(runState(lfsr)) // (StatelessLFSR, LFSR[A]) => (StatelessLFSR, A)
.takeWhile(_ != lfsr.seed) // while current not equal first
.foldMap(_ => 1) // add one for each element
.lastOr(0) // result or zero
.toList // Stream => List
.head // result
//scala> period(StatelessLFSR(0xACE1))
//res1: Int = 65534
sealed abstract class IO[+A] {
final def unsafeToFuture(): Future[A] = ..
}
object IO {
def apply[A](a: => A): IO[A] = ..
def shift(implicit ec: ExecutionContext): IO[Unit] = ..
}
class Stream[F[_], +O] {
def compile: Stream.ToEffect[F, O] = ..
def evalMap[F2[_], O2](f: O => F2[O2]): Stream[F2, O2] = ..
def merge[O2 >: O](that: Stream[F, O2])(implicit F: Effect[F],
ec: ExecutionContext): Stream[F, O2] = ..
}
object Stream {
class ToEffect[F[_], O] {
def last(implicit F: Sync[F]): F[Option[O]] = ..
def toList(implicit F: Sync[F]): F[List[O]] = ..
def fold[B](init: B)(f: (B, O) => B)(implicit F: Sync[F]): F[B] = ..
}
}
def parallel(lfsr: StatelessLFSR)(implicit ec: ExecutionContext): Future[Option[Int]] = {
val nxt = Stream
.constant(next) // Stream(next, next, ..)
.zipWithIndex // A => (A, Int)
.evalMap {
case (l, i) if i % 128 == 0 => IO.shift *> IO(l) // async barrier
case (l, _) => IO(l) // evaluate A
}
val str1 = nxt.map(_.map(v => Set(v).leftIor[Set[Int]])).take(10000)
val str2 = nxt
.map(_.map { v =>
Set(v).rightIor[Set[Int]] // A => Ior(Set[A], Set[A])
})
.take(10000) // first 10'000 elements
str1
.merge(str2) // from one Stream or another
.through(runState(lfsr))
.fold(Ior.both(Set.empty[Int], Set.empty[Int]))(_ |+| _) // combine
.map(_.fold(identity, identity, _ & _)) // intersect results
.map(_.size) // result cardinality
.compile.last // Stream[IO, A] => IO[Option[A]]
.unsafeToFuture() // IO[A] => Future[A]
}
//scala> Await.result(parallel(StatelessLFSR(0xACE1)), 10.seconds)
//res0: Option[Int] = Some(0)