226 lines
5.9 KiB
Scala
226 lines
5.9 KiB
Scala
package utm.scala
|
|
|
|
import scala.annotation.tailrec
|
|
import scala.language.implicitConversions
|
|
|
|
/**
|
|
* Implementation of Universal Turing Machine in Scala that can simulate an arbitrary
|
|
* Turing machine on arbitrary input
|
|
*
|
|
* @author Abdulla Abdurakhmanov (https://github.com/abdolence/utms)
|
|
*/
|
|
class UniversalTuringMachine[S](
|
|
val rules: List[UTMRule[S]],
|
|
val initialState: S,
|
|
val finalStates: Set[S],
|
|
val blankSymbol: String,
|
|
val inputTapeVals: Iterable[String],
|
|
printEveryIter: Int = 1
|
|
) {
|
|
|
|
private val initialTape = UTMTape( inputTapeVals.toVector, 0, blankSymbol )
|
|
|
|
@tailrec
|
|
private def iterate( state: S, curIteration: Int, tape: UTMTape ): UTMTape = {
|
|
if (curIteration % printEveryIter == 0) {
|
|
print( s"${curIteration}: ${state}: " )
|
|
tape.printTape()
|
|
}
|
|
|
|
if (finalStates.contains( state )) {
|
|
println( s"Finished in the final state: ${state}" )
|
|
tape.printTape()
|
|
tape
|
|
} else {
|
|
rules.find(rule => rule.state == state && rule.fromSymbol == tape.current() ) match {
|
|
case Some( rule ) => {
|
|
val updatedTape = tape.updated( rule.toSymbol, rule.action )
|
|
|
|
iterate( rule.toState, curIteration + 1, updatedTape )
|
|
}
|
|
case _ => {
|
|
println(
|
|
s"Finished: no suitable rules found for ${state}/${tape.current()}"
|
|
)
|
|
tape.printTape()
|
|
tape
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
def run(): UTMTape =
|
|
iterate( state = initialState, curIteration = 0, tape = initialTape )
|
|
|
|
}
|
|
|
|
/**
|
|
* Universal Turing Machine actions
|
|
*/
|
|
sealed trait UTMAction
|
|
|
|
object UTMAction {
|
|
case object left extends UTMAction
|
|
case object right extends UTMAction
|
|
case object stay extends UTMAction
|
|
}
|
|
|
|
/**
|
|
* Universal Turing Machine rule definition
|
|
*/
|
|
case class UTMRule[S]( state: S, fromSymbol: String, toSymbol: String, action: UTMAction, toState: S )
|
|
|
|
object UTMRule {
|
|
|
|
implicit def tupleToUTMLRule[S](
|
|
tuple: ( S, String, String, UTMAction, S )
|
|
): UTMRule[S] =
|
|
UTMRule[S]( tuple._1, tuple._2, tuple._3, tuple._4, tuple._5 )
|
|
}
|
|
|
|
/**
|
|
* Universal Turing Machine Tape
|
|
*/
|
|
case class UTMTape( content: Vector[String], position: Int, blankSymbol: String ) {
|
|
|
|
private def updateContentAtPos( symbol: String ) = {
|
|
if (position >= content.length) {
|
|
content :+ symbol
|
|
} else if (position < 0) {
|
|
symbol +: content
|
|
} else if (content( position ) != symbol)
|
|
content.updated( position, symbol )
|
|
else
|
|
content
|
|
}
|
|
|
|
private[scala] def updated( symbol: String, action: UTMAction ): UTMTape = {
|
|
val updatedTape =
|
|
this.copy( content = updateContentAtPos( symbol ), position = action match {
|
|
case UTMAction.left => position - 1
|
|
case UTMAction.right => position + 1
|
|
case UTMAction.stay => position
|
|
} )
|
|
|
|
if (updatedTape.position < 0) {
|
|
updatedTape.copy(
|
|
content = blankSymbol +: updatedTape.content,
|
|
position = 0
|
|
)
|
|
} else if (updatedTape.position >= updatedTape.content.length) {
|
|
updatedTape.copy( content = updatedTape.content :+ blankSymbol )
|
|
} else
|
|
updatedTape
|
|
}
|
|
|
|
private[scala] def current(): String = {
|
|
if (content.isDefinedAt( position ))
|
|
content( position )
|
|
else
|
|
blankSymbol
|
|
}
|
|
|
|
def printTape(): Unit = {
|
|
print( "[" )
|
|
if (position < 0)
|
|
print( "˅" )
|
|
content.zipWithIndex.foreach {
|
|
case ( symbol, index ) =>
|
|
if (position == index)
|
|
print( "˅" )
|
|
else
|
|
print( " " )
|
|
print( s"$symbol" )
|
|
}
|
|
if (position >= content.length)
|
|
print( "˅" )
|
|
println( "]" )
|
|
}
|
|
|
|
}
|
|
|
|
object UniversalTuringMachine extends App {
|
|
|
|
main()
|
|
|
|
def main(): Unit = {
|
|
import UTMAction._
|
|
|
|
def createIncrementMachine() = {
|
|
|
|
sealed trait IncrementStates
|
|
case object q0 extends IncrementStates
|
|
case object qf extends IncrementStates
|
|
|
|
new UniversalTuringMachine[IncrementStates](
|
|
rules = List( ( q0, "1", "1", right, q0 ), ( q0, "B", "1", stay, qf ) ),
|
|
initialState = q0,
|
|
finalStates = Set( qf ),
|
|
blankSymbol = "B",
|
|
inputTapeVals = Seq( "1", "1", "1" )
|
|
).run()
|
|
|
|
}
|
|
|
|
def createThreeStateBusyBeaver() = {
|
|
|
|
sealed trait ThreeStateBusyStates
|
|
case object a extends ThreeStateBusyStates
|
|
case object b extends ThreeStateBusyStates
|
|
case object c extends ThreeStateBusyStates
|
|
case object halt extends ThreeStateBusyStates
|
|
|
|
new UniversalTuringMachine[ThreeStateBusyStates](
|
|
rules = List(
|
|
( a, "0", "1", right, b ),
|
|
( a, "1", "1", left, c ),
|
|
( b, "0", "1", left, a ),
|
|
( b, "1", "1", right, b ),
|
|
( c, "0", "1", left, b ),
|
|
( c, "1", "1", stay, halt )
|
|
),
|
|
initialState = a,
|
|
finalStates = Set( halt ),
|
|
blankSymbol = "0",
|
|
inputTapeVals = Seq()
|
|
).run()
|
|
|
|
}
|
|
|
|
def createFiveState2SymBusyBeaverMachine() = {
|
|
sealed trait FiveBeaverStates
|
|
case object FA extends FiveBeaverStates
|
|
case object FB extends FiveBeaverStates
|
|
case object FC extends FiveBeaverStates
|
|
case object FD extends FiveBeaverStates
|
|
case object FE extends FiveBeaverStates
|
|
case object FH extends FiveBeaverStates
|
|
|
|
new UniversalTuringMachine[FiveBeaverStates](
|
|
rules = List(
|
|
( FA, "0", "1", right, FB ),
|
|
( FA, "1", "1", left, FC ),
|
|
( FB, "0", "1", right, FC ),
|
|
( FB, "1", "1", right, FB ),
|
|
( FC, "0", "1", right, FD ),
|
|
( FC, "1", "0", left, FE ),
|
|
( FD, "0", "1", left, FA ),
|
|
( FD, "1", "1", left, FD ),
|
|
( FE, "0", "1", stay, FH ),
|
|
( FE, "1", "0", left, FA )
|
|
),
|
|
initialState = FA,
|
|
finalStates = Set( FH ),
|
|
blankSymbol = "0",
|
|
inputTapeVals = Seq(),
|
|
printEveryIter = 100000
|
|
).run()
|
|
}
|
|
|
|
createIncrementMachine()
|
|
createThreeStateBusyBeaver()
|
|
// careful here, 47 mln iterations
|
|
createFiveState2SymBusyBeaverMachine()
|
|
}
|
|
}
|