turing.scala
author Christian Urban <christian dot urban at kcl dot ac dot uk>
Sat, 16 Feb 2013 09:07:07 +0000
changeset 177 1c2e639d4e54
parent 176 d2c85556d290
child 178 8248f8adf17d
permissions -rw-r--r--
added abacus programs

abstract class Cell
case object Bk extends Cell { override def toString = "0" }
case object Oc extends Cell { override def toString = "1" }

abstract class Action
case object WBk extends Action
case object WOc extends Action
case object R extends Action
case object L extends Action
case object Nop extends Action

type State = Int
type Prog = List[(Action, State)]

//some list functions
def tl[A](xs: List[A]) : List[A] = xs match {
  case Nil => Nil
  case x::xs => xs
}

def hd[A](xs: List[A]) : A = xs.head

def nth_of[A](xs: List[A], n: Int) = 
  if (n <= xs.length) Some(xs(n)) else None 

//some map functions
def dget(m: Map[Int, Int], n: Int) = m.getOrElse(n, 0)



//tapes
case class Tape(l: List[Cell], r: List[Cell]) {
  def update(a: Action) = a match {
    case WBk => Tape(l, Bk::tl(r))
    case WOc => Tape(l, Oc::tl(r))
    case L => if (l == Nil) Tape(Nil, Bk::r) else Tape (tl(l), hd(l)::r)
    case R => if (r == Nil) Tape(Bk::l, Nil) else Tape(hd(r)::l, tl(r))
    case Nop => Tape(l, r)
  }

  def read = r match {
    case Nil => Bk
    case x::_ => x
  }

  override def toString = 
    l.reverse.map(_.toString).foldLeft("")(_+_) + 
    ">" + r.map(_.toString).foldLeft("")(_+_)
}

// standard tapes
def std(n: Int) : List[Cell] = n match {
  case 0 => List(Oc)
  case n => Oc::std(n - 1)
}

class STape(ns: Int*) extends Tape(Nil, ns.map(std).reduceLeft(_ ::: List(Bk) ::: _))
  
// configurations
case class Config(s: State, tp: Tape) {
  def is_final = s == 0

  override def toString = tp.toString
}


// Turing Machines
case class TM(p: Prog) {
  
  def fetch(s: State, a: Cell) = (s, a) match {
    case (0, _) => (Nop, 0)
      case (s, Bk) => nth_of(p, 2 * (s - 1)) match {
        case None => (Nop, 0)
        case Some(i) => i
      }
    case (s, Oc) => nth_of(p, 2 * (s - 1) + 1) match {
      case None => (Nop, 0)
      case Some(i) => i
    }
  } 

  def step(cf: Config) : Config = fetch (cf.s, cf.tp.read) match {
    case (a, s_next) => Config(s_next, cf.tp.update(a))
  }

  def steps(cf: Config, n: Int) : Config = n match {
    case 0 => cf
    case n => steps(step(cf), n - 1)
  } 

  def run(cf: Config) : Config = {
    if (cf.is_final) cf else run(step(cf))
  }
 
  def run(tp: Tape) : Tape = run(Config(1, tp)).tp
}



// examples
class TMCopy(n: Int) extends 
  TM(List((WBk, 5), (R, 2), (R, 3), (R, 2), (WOc, 3), 
          (L, 4), (L, 4), (L, 5), (R, 11), (R, 6), 
          (R, 7), (WBk, 6), (R, 7), (R, 8), (WOc, 9), 
          (R, 8), (L, 10), (L, 9), (L, 10), (L, 5), 
          (L, 0), (R, 12), (WOc, 13), (L, 14), (R, 12), 
          (R, 12), (L, 15), (WBk, 14), (R, 0), (L, 15)))

println("TM: " + (new TMCopy(0)).run(new STape(3)))


// Abacus
abstract class AInst 
case class Inc(n: Int) extends AInst
case class Dec(n: Int, l: Int) extends AInst
case class Goto(l: Int) extends AInst

type AProg = List[AInst]
type Regs = Map[Int, Int]



case class AConfig(s: Int, regs: Regs)  

case class Abacus(p: AProg) {
  
  def step(cf: AConfig) : AConfig = (nth_of(p, cf.s), cf.s) match {
    case (None, _) => cf
    case (Some(Inc(n)), s) => AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) + 1)))
    case (Some(Dec(n, l)), s) => {
      if (dget(cf.regs, n) == 0) AConfig(l, cf.regs)
      else AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) - 1)))
    }
    case (Some(Goto(l)), _) => AConfig(l, cf.regs)
  }  

  def steps(cf: AConfig, n: Int) : AConfig = n match {
    case 0 => cf
    case n => steps(step(cf), n - 1)
  } 

  def steps(regs: Regs, n: Int) : AConfig = steps(AConfig(0, regs), n)

  def run(cf: AConfig) : AConfig = {
    if (cf.s >= p.length || cf.s < 0) cf else run(step(cf))
  }
 
  def run(regs: Regs): Regs = run(AConfig(0, regs)).regs
}

// examples
class Copy(in: Int, out: Int) extends 
  Abacus(List(Dec(in, -1), Inc(out), Goto(0))) 

class Plus(in1: Int, in2: Int, out: Int) extends 
  Abacus(List(Dec(in1, 4), Inc(in2), Inc(out),
              Goto(0), Dec(out, -1), Inc(in1), Goto(4))) 


println("Ab: " + (new Plus(0, 1, 2)).run(Map(0 -> 3, 1 -> 4)))