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

spire.math.Trilean.scala Maven / Gradle / Ivy

package spire.math

import spire.algebra.lattice.Heyting

/**
 * Implementation of three-valued logic.
 *
 * This type resembles Boolean, but has three values instead of two:
 *
 *  - Trilean.True (equivalent to true)
 *  - Trilean.False (equivalent to false)
 *  - Trilean.Unknown
 *
 * Trilean supports the same operations that Boolean does, and as long
 * as all values are True or False, the results will be the
 * same. However, the truth tables have to be extended to work with
 * unknown:
 *
 * not:
 * -+-
 * T|F
 * U|U
 * F|T
 *
 * and:
 *  |T U F
 * -+-----
 * T|T U F
 * U|U U F
 * F|F F F
 *
 * or:
 *  |T U F
 * -+-----
 * T|T T T
 * U|T U U
 * F|T U F
 *
 * Trilean is implemented as a value type, so in most cases it will
 * only have the overhead of a single Int. However, in some situations
 * it will be boxed.
 */
class Trilean (val value: Int) extends AnyVal { lhs =>
  def isTrue: Boolean = value == -1
  def isFalse: Boolean = value == 0
  def isUnknown: Boolean = value == 1

  def isKnown: Boolean = value != 1
  def isNotTrue: Boolean = value != -1
  def isNotFalse: Boolean = value != 0

  def fold[A](f: Boolean => A)(unknown: => A): A =
    if (value == 1) unknown else f(value == -1)

  def assumeTrue: Boolean =
    value != 0

  def assumeFalse: Boolean =
    value == -1

  def assume(b: Boolean): Boolean =
    if (value == 1) b else value == -1

  def toBoolean(b: => Boolean): Boolean =
    if (value == 1) b else value == -1

  def toOption: Option[Boolean] =
    if (value == 1) None else Some(value == -1)

  override def toString: String =
    if (value == -1) "true" else if (value == 0) "false" else "unknown"

  def &&(rhs: => Trilean): Trilean =
    if (lhs.value == 0) lhs else lhs & rhs

  def ||(rhs: => Trilean): Trilean =
    if (lhs.value == -1) lhs else lhs | rhs

  def unary_! : Trilean =
    if (value == 1) lhs else new Trilean(~lhs.value)

  //   T U F
  // T T U F
  // U U U F
  // F F F F
  def &(rhs: Trilean): Trilean =
    new Trilean(lhs.value & rhs.value)

  //   T U F
  // T T T T
  // U T U U
  // F T U F
  def |(rhs: Trilean): Trilean =
    new Trilean(lhs.value | rhs.value)

  //   T U F
  // T F U T
  // U U U U
  // F T U F
  def ^(rhs: Trilean): Trilean =
    if (lhs.value == 1) lhs
    else if (rhs.value == 1) rhs
    else new Trilean(lhs.value ^ rhs.value)

  //   T U F
  // T T U F
  // U T U U
  // F T T T
  def imp(rhs: Trilean): Trilean =
    (!lhs) | rhs

  def nand(rhs: Trilean): Trilean =
    !(lhs & rhs)

  def nor(rhs: Trilean): Trilean =
    !(lhs | rhs)

  //   T U F
  // T T U F
  // U U U U
  // F F U T
  def nxor(rhs: Trilean): Trilean =
    if (lhs.value == 1) lhs
    else if (rhs.value == 1) rhs
    else new Trilean(~(lhs.value ^ rhs.value))
}

object Trilean {
  final val True: Trilean = new Trilean(-1)
  final val False: Trilean = new Trilean(0)
  final val Unknown: Trilean = new Trilean(1)

  final def apply(b: Boolean): Trilean =
    if (b) True else False

  final def apply(o: Option[Boolean]): Trilean =
    o.map(Trilean(_)).getOrElse(Unknown)

  final def apply(t: scala.util.Try[Boolean]): Trilean =
    t.map(Trilean(_)).getOrElse(Unknown)

  final def liftPf[A](p0: PartialFunction[A, Boolean]): A => Trilean = {
    val p = p0.andThen(Trilean(_))
    (a: A) => p.applyOrElse(a, (_: A) => Unknown)
  }

  final def testRef[A <: AnyRef](a: A)(f: A => Boolean): Trilean =
    if (a == null) Unknown else Trilean(f(a))

  final def testFloat(n: Float)(f: Float => Boolean): Trilean =
    if (java.lang.Float.isNaN(n)) Unknown else Trilean(f(n))

  final def testDouble(n: Double)(f: Double => Boolean): Trilean =
    if (java.lang.Double.isNaN(n)) Unknown else Trilean(f(n))

  final def run(body: => Boolean): Trilean =
    try {
      apply(body)
    } catch {
      case _: Exception => Unknown
    }

  implicit val algebra = new TrileanAlgebra
}

class TrileanAlgebra extends Heyting[Trilean] {
  def one: Trilean = Trilean.True
  def zero: Trilean = Trilean.False
  def complement(a: Trilean): Trilean = !a
  def and(a: Trilean, b: Trilean): Trilean = a & b
  def or(a: Trilean, b: Trilean): Trilean = a | b
  def imp(a: Trilean, b: Trilean): Trilean = a imp b
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy