scala/recs.scala
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Tue, 26 Feb 2013 17:39:47 +0000
changeset 200 8dde2e46c69d
parent 198 d93cc4295306
child 201 09befdf4fc99
permissions -rw-r--r--
added all recursive functions needed for the UF

package object recs {

//Recursive Functions

abstract class Rec {
  def eval(ns: List[Int]) : Int
  def eval(ns: Int*) : Int = eval(ns.toList)
}

case object Z extends Rec {
  override def eval(ns: List[Int]) = ns match {
    case n::Nil => 0
    case _ => throw new IllegalArgumentException("Z args: " + ns)
  }
} 

case object S extends Rec {
  override def eval(ns: List[Int]) = ns match {
    case n::Nil => n + 1
    case _ => throw new IllegalArgumentException("S args: " + ns)
  }
} 

case class Id(n: Int, m: Int) extends Rec {
  override def eval(ns: List[Int]) = 
    if (ns.length == n && m < n) ns(m)
    else throw new IllegalArgumentException("Id args: " + ns + "," + n + "," + m)
}

case class Cn(n: Int, f: Rec, gs: List[Rec]) extends Rec {
  override def eval(ns: List[Int]) = 
    if (ns.length == n) f.eval(gs.map(_.eval(ns)))
    else throw new IllegalArgumentException("Cn: args")
}

case class Pr(n: Int, f: Rec, g: Rec) extends Rec {
  override def eval(ns: List[Int]) = 
    if (ns.length == n + 1) {
      if (ns.last == 0) f.eval(ns.init)
      else {
        val r = Pr(n, f, g).eval(ns.init ::: List(ns.last - 1))
        g.eval(ns.init ::: List(ns.last - 1, r))
      }
    }
    else throw new IllegalArgumentException("Pr: args")
}

case class Mn(n: Int, f: Rec) extends Rec {
  def evaln(ns: List[Int], n: Int) : Int = 
    if (f.eval(ns ::: List(n)) == 0) n else evaln(ns, n + 1)

  override def eval(ns: List[Int]) = 
    if (ns.length == n) evaln(ns, 0) 
    else throw new IllegalArgumentException("Mn: args")
}



// Recursive Function examples
def arity(f: Rec) = f match {
  case Z => 1
  case S => 1
  case Id(n, _) => n
  case Cn(n, _, _) => n
  case Pr(n, _, _) => n + 1
  case Mn(n, _) => n 
}

val Add = Pr(1, Id(1, 0), Cn(3, S, List(Id(3, 2))))
val Mult = Pr(1, Z, Cn(3, Add, List(Id(3, 0), Id(3, 2))))
val Twice = Cn(1, Mult, List(Id(1, 0), Const(2)))
val Fourtimes = Cn(1, Mult, List(Id(1, 0), Const(4)))
val Pred = Cn(1, Pr(1, Z, Id(3, 1)), List(Id(1, 0), Id(1, 0)))
val Minus = Pr(1, Id(1, 0), Cn(3, Pred, List(Id(3, 2))))
def Const(n: Int) : Rec = n match {
  case 0 => Z
  case n => Cn(1, S, List(Const(n - 1)))
}

val Power = Pr(1, Const(1), Cn(3, Mult, List(Id(3, 0), Id(3, 2))))
val Sign = Cn(1, Minus, List(Const(1), Cn(1, Minus, List(Const(1), Id(1, 0)))))
val Less = Cn(2, Sign, List(Cn(2, Minus, List(Id(2, 1), Id(2, 0)))))
val Not = Cn(1, Minus, List(Const(1), Id(1, 0)))
val Eq = Cn(2, Minus, List(Cn(2, Const(1), List(Id(2, 0))), 
           Cn(2, Add, List(Cn(2, Minus, List(Id(2, 0), Id(2, 1))), 
             Cn(2, Minus, List(Id(2, 1), Id(2, 0)))))))
val Noteq = Cn(2, Not, List(Cn(2, Eq, List(Id(2, 0), Id(2, 1))))) 
val Conj = Cn(2, Sign, List(Cn(2, Mult, List(Id(2, 0), Id(2, 1)))))
val Disj = Cn(2, Sign, List(Cn(2, Add, List(Id(2, 0), Id(2, 1)))))

def Nargs(n: Int, m: Int) : List[Rec] = m match {
  case 0 => Nil
  case m => Nargs(n, m - 1) ::: List(Id(n, m - 1))
}

def Sigma(f: Rec) = {
  val ar = arity(f)  
  Pr(ar - 1, Cn(ar - 1, f, Nargs(ar - 1, ar - 1) :::
                    List(Cn(ar - 1, Const(0), List(Id(ar - 1, 0))))), 
             Cn(ar + 1, Add, List(Id(ar + 1, ar), 
                    Cn(ar + 1, f, Nargs(ar + 1, ar - 1) :::
                        List(Cn(ar + 1, S, List(Id(ar + 1, ar - 1))))))))
}

def Accum(f: Rec) = {
  val ar = arity(f)  
  Pr(ar - 1, Cn(ar - 1, f, Nargs(ar - 1, ar - 1) :::
                    List(Cn(ar - 1, Const(0), List(Id(ar - 1, 0))))), 
             Cn(ar + 1, Mult, List(Id(ar + 1, ar), 
                    Cn(ar + 1, f, Nargs(ar + 1, ar - 1) :::
                        List(Cn(ar + 1, S, List(Id(ar + 1, ar - 1))))))))
}

def All(t: Rec, f: Rec) = {
  val ar = arity(f)
  Cn(ar - 1, Sign, List(Cn(ar - 1, Accum(f), Nargs(ar - 1, ar - 1) ::: List(t))))
}

def Ex(t: Rec, f: Rec) = {
  val ar = arity(f)
  Cn(ar - 1, Sign, List(Cn(ar - 1, Sigma(f), Nargs(ar - 1, ar - 1) ::: List(t))))
}

//Definition on page 77 of Boolos's book.
def Minr(f: Rec) = {
  val ar = arity(f)
  val rq = All(Id(ar, ar - 1), 
    Cn(ar + 1, Not, List(Cn(ar + 1, f, Nargs(ar + 1, ar - 1) ::: List(Id(ar + 1, ar)))))) 
  Sigma(rq)
}

//Definition on page 77 of Boolos's book.
def Maxr(f: Rec) = {
  val ar  = arity(f) 
  val rt  = Id(ar + 1, ar - 1) 
  val rf1 = Cn(ar + 2, Less, List(Id(ar + 2, ar + 1), Id(ar + 2, ar))) 
  val rf2 = Cn(ar + 2, Not, List(Cn (ar + 2, f, Nargs(ar + 2, ar - 1) ::: List(Id(ar + 2, ar + 1))))) 
  val rf  = Cn(ar + 2, Disj, List(rf1, rf2)) 
  val rq  = All(rt, rf) 
  val Qf  = Cn(ar + 1, Not, List(rq))
  Cn(ar, Sigma(Qf), Nargs(ar, ar) ::: List(Id(ar, ar - 1)))
}

//Mutli-way branching statement on page 79 of Boolos's book
def Branch(rs: List[(Rec, Rec)]) = {
  val ar = arity(rs.head._1)
  
  def Branch_aux(rs: List[(Rec, Rec)], l: Int) : Rec = rs match {
    case Nil => Cn(l, Z, List(Id(l, l - 1)))
    case (rg, rc)::recs => Cn(l, Add, List(Cn(l, Mult, List(rg, rc)), Branch_aux(recs, l)))
  }

  Branch_aux(rs, ar)
}

//Factorial
val Fact = {
  val Fact_aux = Pr(1, Const(1), Cn(3, Mult, List(Id(3, 2), Cn(3, S, List(Id(3, 1))))))
  Cn(1, Fact_aux, List(Id(1, 0), Id(1, 0)))
}

//Prime test
val Prime = Cn(1, Conj, List(Cn(1, Less, List(Const(1), Id(1, 0))),
                             All(Cn(1, Minus, List(Id(1, 0), Const(1))), 
                                 All(Cn(2, Minus, List(Id(2, 0), Cn(2, Const(1), List(Id(2, 0))))), 
                                     Cn(3, Noteq, List(Cn(3, Mult, List(Id(3, 1), Id(3, 2))), Id(3, 0)))))))

//Returns the first prime number after n
val NextPrime = {
  val R = Cn(2, Conj, List(Cn(2, Less, List(Id(2, 0), Id(2, 1))), 
                           Cn(2, Prime, List(Id(2, 1)))))
  Cn(1, Minr(R), List(Id(1, 0), Cn(1, S, List(Fact))))
}

val NthPrime = {
  val NthPrime_aux = Pr(1, Const(2), Cn(3, NextPrime, List(Id(3, 2))))
  Cn(1, NthPrime_aux, List(Id(1, 0), Id(1, 0)))
}

def Listsum(k: Int, m: Int) : Rec = m match {
  case 0 => Cn(k, Z, List(Id(k, 0)))
  case n => Cn(k, Add, List(Listsum(k, n - 1), Id(k, n - 1)))
}

//strt-function on page 90 of Boolos, but our definition generalises 
//the original one in order to deal with multiple input-arguments

def Strt(n: Int) = {
  def Strt_aux(l: Int, k: Int) : Rec = k match {
    case 0 => Cn(l, Z, List(Id(l, 0)))
    case n => {
      val rec_dbound = Cn(l, Add, List(Listsum(l, n - 1), Cn(l, Const(n - 1), List(Id(l, 0)))))
      Cn(l, Add, List(Strt_aux(l, n - 1), 
                      Cn(l, Minus, List(Cn(l, Power, List(Cn(l, Const(2), List(Id(l, 0))), 
                                                          Cn(l, Add, List(Id(l, n - 1), rec_dbound)))), 
                                        Cn(l, Power, List(Cn(l, Const(2), List(Id(l, 0))), rec_dbound))))))
    }
  }

  def Rmap(f: Rec, k: Int) = (0 until k).map{i => Cn(k, f, List(Id(k, i)))}.toList
 
  Cn(n, Strt_aux(n, n), Rmap(S, n))
}

}