All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unibo.scafi.lib.StateManagement.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2016-2019, Roberto Casadei, Mirko Viroli, and contributors.
 * See the LICENSE file distributed with this work for additional information regarding copyright ownership.
*/

package it.unibo.scafi.lib

trait StdLibStateManagement{
  self: StandardLibrary.Subcomponent =>

  trait StateManagement {
    self: FieldCalculusSyntax =>

    /**
      * Counts the number of rounds, refreshing each time the computation is re-entered.
      * TODO: consider boundedness as a limitation for long-lived/eternal systems
      * @return the number of the round
      */
    def roundCounter(): Long =
      rep(0L)(_ + 1)

    /**
      * Remembers the provided value
      */
    def remember[T](value: => T): T =
      rep(value)(identity)

    /**
      * Alias for [[remember()]]
      */
    def constant[T](value: => T): T = remember(value)

    /**
      * Remembers the provided optional value, unless empty
      */
    def keep[T](expr: => Option[T]): Option[T] = rep[Option[T]](None){ _.orElse(expr) }

    /**
      * Remembers the occurrence of some condition or event
      */
    def keep(expr: => Boolean): Boolean = rep(false)(b => if(b) b else expr)

    /**
      * @return true only when a discontinuity (i.e., a change) is observed on `x` (you may choose how to handle the first observation)
      */
    def captureChange[T](x: T, initially: Boolean = true): Boolean = rep((Option.empty[T],false)) { case (value, _) =>
      (Some(x), value.map(_ != x).getOrElse(initially))
    }._2

    def countChanges[T](x: T, initially: Boolean = true): (Long,Boolean) = {
      val changed = captureChange(x, initially)
      (rep(0L)(k => if(changed) k + 1 else k), changed)
    }

    /**
      * @return true when the given parameter goes from false to true (starting from false); false otherwise
      */
    def goesUp(value: Boolean): Boolean = rep((false, false)) { case (old, trigger) =>
      (value, value && value != old)
    }._2

    /**
      * @return true when the given parameter goes from true to false (starting from false); false otherwise
      */
    def goesDown(value: Boolean): Boolean = rep((false, false)) { case (old, trigger) =>
      (value, !value && value != old)
    }._2

    /**
      * It is a simple building block which returns the same values
      *  it receives in input delayed by one computation round.
      */
    def delay[T](value: T): T = {
      var res = value
      rep(value){ old => res = old; value }
      res
    }

    private def none[T]: Option[T] = None

    /**
      * Returns a non-empty optional with the provided value just once, then None
      */
    def once[T](expr: => T): Option[T] = rep((true,none[T])){ case (first,value) => (false, if(first) Some(expr)  else None) }._2
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy