Skip to content

Commit

Permalink
Refactor argument parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Maokami committed Feb 27, 2024
1 parent 21916b2 commit 2da33ab
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 231 deletions.
57 changes: 57 additions & 0 deletions src/main/scala/fhetest/Checker/Utils.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package fhetest.Checker

import fhetest.Utils.*

import java.io.{File, PrintWriter}
import java.nio.file.{Files, Path, Paths, StandardCopyOption}
import spray.json._
import spray.json.DefaultJsonProtocol._

// file writer
def getPrintWriter(filename: String): PrintWriter =
Expand All @@ -21,6 +24,60 @@ def dumpJson[T](data: T, filename: String)(implicit
): Unit =
dumpFile(data.toJson.prettyPrint, filename)

def dumpResult(
program: T2Program,
i: Int,
res: CheckResult,
): Unit = {
val pgm_info = Map(
("programId" -> JsString(i.toString)),
("program" -> JsString(program.content)),
)
res match {
case Same(res) => {
val (expectedLst, obtainedLst) = res.partition(_.backend == "CLEAR")
val expected_res = expectedLst.apply(0).result
val result = pgm_info ++ Map(
"result" -> JsString("Success"),
"failedLibraires" -> JsString("0"),
"failures" -> JsArray(),
"expected" -> JsString(expected_res.toString),
)
val succFilename = s"$succDir/$i.json"
dumpJson(result, succFilename)
}
case Diff(res) => {
val (expectedLst, obtainedLst) = res.partition(_.backend == "CLEAR")
val expected = expectedLst.apply(0)
val diffResults = obtainedLst.filter(isDiff(expected, _))
val failures = diffResults.map(r =>
Map(
("library" -> r.backend),
("failedResult" -> r.result.toString),
),
)
val result = pgm_info ++ Map(
"result" -> JsString("Fail"),
"failedLibraires" -> JsString(diffResults.size.toString),
"failures" -> failures.toJson,
"expected" -> JsString(expected._2.toString),
)
val failFilename = s"$failDir/$i.json"
dumpJson(result, failFilename)
}
case ParserError(_) => {
val result = pgm_info ++ Map(
"result" -> JsString("ParseError"),
"failedLibraires" -> JsString("NaN"),
"failures" -> JsArray(),
"expected" -> JsString(""),
)
val psrErrFilename = s"$psrErrDir/$i.json"
dumpJson(result, psrErrFilename)
}
}
}

val TEST_DIR = fhetest.TEST_DIR
val succDir = s"$TEST_DIR/succ"
val failDir = s"$TEST_DIR/fail"
Expand Down
236 changes: 99 additions & 137 deletions src/main/scala/fhetest/Command.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fhetest

import fhetest.Utils.*
import fhetest.Generate.*
import fhetest.Phase.{Parse, Interp, Print, Execute, Generate, Check}

sealed abstract class Command(
Expand All @@ -15,15 +16,21 @@ sealed abstract class Command(
/** help message */
def examples: List[String]

/** run command with parsed arguments */
def runJob(config: Config): Unit

/** run command with command-line arguments */
def apply(args: List[String]): Unit
def apply(args: List[String]) = {
val config = Config(args)
runJob(config)
}
}

/** base command */
case object CmdBase extends Command("") {
val help = "does nothing."
val examples = Nil
def apply(args: List[String]) = ()
def runJob(config: Config) = ()
}

/** `help` command */
Expand All @@ -32,7 +39,7 @@ case object CmdHelp extends Command("help") {
val examples = List(
"fhetest help",
)
def apply(args: List[String]): Unit = {
def runJob(config: Config): Unit = {
println("Usage: fhetest <command> [options]")
println("Commands:")
for cmd <- FHETest.commands do println(s" ${cmd.name}\n\t${cmd.help}")
Expand All @@ -43,185 +50,140 @@ case object CmdHelp extends Command("help") {
case object CmdInterp extends Command("interp") {
val help = "Interp a T2 file."
val examples = List(
"fhetest interp tmp.t2",
"fhetest interp tmp.t2 -n 4096 -m 40961",
"fhetest interp -file:tmp.t2",
"fhetest interp -file:tmp.t2 -n:4096 -m:40961",
)
def apply(args: List[String]): Unit = args match {
case file :: Nil => {
val (ast, _, _) = Parse(file)
val result = Interp(ast, 32768, 65537)
print(result)
}
case file :: remainArgs => {
val (ast, _, _) = Parse(file)
val (_, encParams) = parseWordSizeAndEncParams(remainArgs)
val result = Interp(ast, encParams.ringDim, encParams.plainMod)
print(result)
}
case Nil => println("No T2 file given.")
}
def runJob(config: Config): Unit =
val fname = config.fileName.getOrElseThrow("No T2 file given.")
val (ast, _, _) = Parse(fname)
val ringDim: Int = config.encParams.map(_.ringDim).getOrElse(32768)
val plainMod: Int = config.encParams.map(_.plainMod).getOrElse(65537)
val result = Interp(ast, ringDim, plainMod)
print(result)
}

/** `run` command */
case object CmdRun extends Command("run") {
val help = "Run the given T2 program."
val examples = List(
"fhetest run tmp.t2 --SEAL",
"fhetest run tmp.t2 --OpenFHE",
"fhetest run tmp.t2 --SEAL -w 4 -n 4096 -d 5 -m 40961",
"fhetest run tmp.t2",
"fhetest run -file:tmp.t2 -b:SEAL",
"fhetest run -file:tmp.t2 -b:OpenFHE",
"fhetest run -file:tmp.t2 -b:SEAL -w:4 -n:4096 -d:5 -m:40961",
"fhetest run -file:tmp.t2",
)
// TODO: Refactor this function: parseWordSizeAndEncParams
def apply(args: List[String]): Unit = args match {
case file :: backendString :: remainArgs =>
parseBackend(backendString) match {
case Some(backend) =>
given DirName = getWorkspaceDir(backend)
val (ast, symbolTable, encType) = Parse(file)
val (wordSizeOpt, encParams) = parseWordSizeAndEncParams(remainArgs)
Print(
ast,
symbolTable,
encType,
backend,
wordSizeOpt,
Some(encParams),
)
val result = Execute(backend)
print(result)
case None => println("Argument parsing error: Invalid backend.")
}
case file :: Nil =>
val (ast, _, _) = Parse(file)
val result = Interp(ast, 32768, 65537)
print(result)
case Nil => println("No T2 file given.")
}
def runJob(config: Config): Unit =
val fname = config.fileName.getOrElseThrow("No T2 file given.")
val encParams: EncParams =
config.encParams.getOrElse(EncParams(32768, 5, 65537))
val wordSizeOpt: Option[Int] = config.wordSize
val plainMod: Int = config.encParams.map(_.plainMod).getOrElse(65537)
config.backend match {
case Some(backend) =>
given DirName = getWorkspaceDir(backend)
val (ast, symbolTable, encType) = Parse(fname)
Print(
ast,
symbolTable,
encType,
backend,
wordSizeOpt,
Some(encParams),
)
case None =>
val (ast, _, _) = Parse(fname)
val result = Interp(ast, 32768, 65537)
print(result)
}
}

/** `compile` command */
case object CmdCompile extends Command("compile") {
val help = "compiles a T2 file to the given backend."
val examples = List(
"fhetest compile tmp.t2 --SEAL",
"fhetest compile tmp.t2 --OpenFHE",
"fhetest compile -file:tmp.t2 -b:SEAL",
"fhetest compile -file:tmp.t2 -b:OpenFHE",
)
def apply(args: List[String]): Unit = args match {
case file :: backendString :: remain =>
parseBackend(backendString) match {
case Some(backend) =>
given DirName = getWorkspaceDir(backend)
val (ast, symbolTable, encType) = Parse(file)
remain match {
case params :: _ => ???
case Nil => Print(ast, symbolTable, encType, backend)
}
case None => println("Argument parsing error: Invalid backend.")
}
case _ :: Nil => println("No backend given.")
case Nil => println("No T2 file given.")
}

def runJob(config: Config): Unit =
val fname = config.fileName.getOrElseThrow("No T2 file given.")
val backend = config.backend.getOrElseThrow("No backend given.")
given DirName = getWorkspaceDir(backend)
val (ast, symbolTable, encType) = Parse(fname)
Print(ast, symbolTable, encType, backend)
}

/** `execute` command */
case object CmdExecute extends Command("execute") {
val help = "Execute the compiled code in the given backend."
val examples = List(
"fhetest execute --SEAL",
"fhetest execute --OpenFHE",
"fhetest execute -b:SEAL",
"fhetest execute -b:OpenFHE",
)
def apply(args: List[String]): Unit = args match {
case backendString :: _ =>
parseBackend(backendString) match {
case Some(backend) =>
given DirName = getWorkspaceDir(backend)
val output = Execute(backend)
println(output)
case None => println("Argument parsing error: Invalid backend.")
}
case Nil => println("No backend given.")
}
def runJob(config: Config): Unit =
val backend = config.backend.getOrElseThrow("No backend given.")
given DirName = getWorkspaceDir(backend)
val output = Execute(backend)
println(output)
}

// TODO : Get Strategy from the command line
/** `gen` command */
case object CmdGen extends Command("gen") {
val help = "Generate random T2 programs."
val examples = List(
"fhetest gen --INT 10",
"fhetest gen --DOUBLE 10",
"fhetest gen -type:int -c:10",
"fhetest gen -type:double -c:10",
"fhetest gen -type:int -stg:exhaust -c:10",
"fhetest gen -type:double -stg:random -c:10",
)
def apply(args: List[String]): Unit = args match {
case Nil => println("No argument given.")
case encTypeString :: remain =>
val encType = parseEncType(encTypeString)
val generator = Generate(encType)
val n = remain match {
case nString :: Nil =>
nString.toInt
case _ => 10 // default value
}
generator.show(List(Backend.SEAL, Backend.OpenFHE), n)
}
def runJob(config: Config): Unit =
val encType = config.encType.getOrElseThrow("No encType given.")
val genCount = config.genCount.getOrElse(10)
val generator = Generate(encType)
generator.show(List(Backend.SEAL, Backend.OpenFHE), genCount)
}

/** `check` command */
case object CmdCheck extends Command("check") {
val help = "Check results of T2 program execution."
val examples = List(
"fhetest check tmp --SEAL --OpenFHE",
"fhetest check -dir:tmp -json:true",
)
// TODO: json option 추가
def apply(args: List[String]): Unit = args match {
case dir :: backendStrings => {
val backendList = backendStrings.flatMap(parseBackend(_))
if (backendStrings.size == backendList.size) {
// TODO: temporary encParams. Fix after having parameter genernation.
val encParams = EncParams(32768, 5, 65537)
val outputs = Check(dir, backendList, encParams)
for output <- outputs do {
println(output)
}
} else { println("Argument parsing error: Invalid backend.") }
def runJob(config: Config): Unit =
val dir = config.dirName.getOrElseThrow("No directory given.")
val encParams: EncParams =
config.encParams.getOrElse(EncParams(32768, 5, 65537))
val backends = List(Backend.SEAL, Backend.OpenFHE)
val toJson = config.toJson
val outputs = Check(dir, backends, encParams, toJson)
for output <- outputs do {
println(output)
}
case _ => println("Invalid arguments")
}
}

/** `test` command */
case object CmdTest extends Command("test") {
val help = "Check after Generate random T2 programs."
val examples = List(
"fhetest test --INT --random",
"fhetest test --INT --random 10",
"fhetest test --DOUBLE --exhaust 10",
"fhetest test -type:int -stg:random",
"fhetest test -type:int -stg:random -count:10",
"fhetest test -type:double -stg:exhaust -count:10",
)
// TODO: json option 추가
def apply(args: List[String]): Unit = args match {
case Nil => println("No argument given.")
case encTypeString :: stgString :: remain => {
val nOpt = remain match {
case nString :: _ =>
Some(nString.toInt)
case _ => None
}
val encType = parseEncType(encTypeString)
val strategy = parseStrategy(stgString)
val generator = Generate(encType, strategy)
val programs = generator(nOpt).map(T2Program(_))
val backendList = List(Backend.SEAL, Backend.OpenFHE)
// TODO: temporary encParams. Fix after having parameter genernation.
val encParams = EncParams(32768, 5, 65537)
val outputs = Check(programs, backendList, encParams)
for (program, output) <- outputs do {
println("=" * 80)
println("Program : " + program.content)
println("-" * 80)
println(output)
println("=" * 80)
}
def runJob(config: Config): Unit =
val encType = config.encType.getOrElseThrow("No encType given.")
val genStrategy = config.genStrategy.getOrElse(Strategy.Random)
val genCount = config.genCount
val generator = Generate(encType, genStrategy)
val programs = generator(genCount).map(T2Program(_))
val backendList = List(Backend.SEAL, Backend.OpenFHE)
val encParams = config.encParams.getOrElse(EncParams(32768, 5, 65537))
val toJson = config.toJson
val outputs = Check(programs, backendList, encParams, toJson)
for (program, output) <- outputs do {
println("=" * 80)
println("Program : " + program.content)
println("-" * 80)
println(output)
println("=" * 80)
}
case _ => println("EncType and Strategy are required.")
}
}
Loading

0 comments on commit 2da33ab

Please sign in to comment.