Skip to content

Commit

Permalink
Change spray json to circe
Browse files Browse the repository at this point in the history
  • Loading branch information
jaeho committed Mar 7, 2024
1 parent 2e29a4b commit a1786ca
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 95 deletions.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ lazy val root = project
"org.twc" % "t2" % "1.0" from file(
"lib/terminator-compiler-1.0.jar",
).toURI.toString,
"io.spray" %% "spray-json" % "1.3.6",
"io.circe" %% "circe-core" % "0.14.1",
"io.circe" %% "circe-generic" % "0.14.1",
"io.circe" %% "circe-parser" % "0.14.1",
),
// set the main class for 'sbt run'
Compile / mainClass := Some("fhetest.FHETest"),
Expand Down
230 changes: 140 additions & 90 deletions src/main/scala/fhetest/Checker/Utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,108 +2,158 @@ package fhetest.Checker

import fhetest.Utils.*
import fhetest.Generate.T2Program

import fhetest.TEST_DIR
import fhetest.LibConfig

import io.circe._
import io.circe.generic.semiauto._
import io.circe.syntax._

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 =
new PrintWriter(new File(filename))
case class Failure(library: String, failedResult: String)
case class ResultInfo(
programId: Int,
program: T2Program,
result: String,
failures: List[Failure],
expected: String,
SEAL: String,
OpenFHE: String,
)

// dump given data to a file
def dumpFile(data: Any, filename: String): Unit = {
val nf = getPrintWriter(filename)
nf.print(data)
nf.close()
// Define en/decoders using Circe
// Scheme
implicit val schemeEncoder: Encoder[Scheme] = Encoder.instance {
case Scheme.BFV => Json.fromString("BFV")
case Scheme.BGV => Json.fromString("BGV")
case Scheme.CKKS => Json.fromString("CKKS")
}
implicit val schemeDecoder: Decoder[Scheme] = Decoder.decodeString.emap {
case "BFV" => Right(Scheme.BFV)
case "BGV" => Right(Scheme.BGV)
case "CKKS" => Right(Scheme.CKKS)
case other => Left(s"Unknown scheme: $other")
}

// dump given data as JSON
def dumpJson[T](data: T, filename: String)(implicit
writer: JsonWriter[T],
): Unit =
dumpFile(data.toJson.prettyPrint, filename)
// SecurityLevel
implicit val securityLevelEncoder: Encoder[SecurityLevel] = Encoder.instance {
case SecurityLevel.HEStd_128_classic => Json.fromString("HEStd_128_classic")
case SecurityLevel.HEStd_192_classic => Json.fromString("HEStd_192_classic")
case SecurityLevel.HEStd_256_classic => Json.fromString("HEStd_256_classic")
case SecurityLevel.HEStd_NotSet => Json.fromString("HEStd_NotSet")
}
implicit val securityLevelDecoder: Decoder[SecurityLevel] =
Decoder.decodeString.emap {
case "HEStd_128_classic" => Right(SecurityLevel.HEStd_128_classic)
case "HEStd_192_classic" => Right(SecurityLevel.HEStd_192_classic)
case "HEStd_256_classic" => Right(SecurityLevel.HEStd_256_classic)
case "HEStd_NotSet" => Right(SecurityLevel.HEStd_NotSet)
case other => Left(s"Unknown security level: $other")
}

// FIXME: LibConfig
def dumpResult(
program: T2Program,
i: Int,
res: CheckResult,
sealVersion: String,
openfheVersion: String,
): Unit = {
val backend_info = Map(
("SEAL" -> JsString(sealVersion)),
("OpenFHE" -> JsString(openfheVersion)),
)
val libConfig = program.libConfig
val encParams = libConfig.encParams
val encParams_info = JsObject(
("ringDim" -> JsString(encParams.ringDim.toString)),
("multDepth" -> JsString(encParams.mulDepth.toString)),
("plainMod" -> JsString(encParams.plainMod.toString)),
)
val libConfig_info = JsObject(
("scheme" -> JsString(libConfig.scheme.toString)),
("encParams" -> encParams_info.toJson),
("firstModSize" -> JsString(libConfig.firstModSize.toString)),
("scalingModSize" -> JsString(libConfig.scalingModSize.toString)),
("securityLevel" -> JsString(libConfig.securityLevel.toString)),
("scalingTechnique" -> JsString(libConfig.scalingTechnique.toString)),
("lenOpt" -> JsString(libConfig.lenOpt.getOrElse(0).toString)),
("boundOpt" -> JsString(libConfig.boundOpt.getOrElse(0).toString)),
)
val pgm_info = Map(
("programId" -> JsString(i.toString)),
("program" -> JsString(program.content)),
("libConfig" -> libConfig_info),
)
val info = pgm_info ++ backend_info
res match {
case Same(res) => {
val (expectedLst, obtainedLst) = res.partition(_.backend == "CLEAR")
val expected_res = expectedLst.apply(0).result
val result = info ++ Map(
"result" -> JsString("Success"),
"failedLibraires" -> JsString("0"),
"failures" -> JsArray(),
"expected" -> JsString(expected_res.toString),
)
val succFilename = s"$succDir/$i.json"
dumpJson(result, succFilename)
// ScalingTechnique
implicit val scalingTechniqueEncoder: Encoder[ScalingTechnique] =
Encoder.instance {
case ScalingTechnique.FIXEDMANUAL => Json.fromString("FIXEDMANUAL")
case ScalingTechnique.FIXEDAUTO => Json.fromString("FIXEDAUTO")
case ScalingTechnique.FLEXIBLEAUTO => Json.fromString("FLEXIBLEAUTO")
case ScalingTechnique.FLEXIBLEAUTOEXT => Json.fromString("FLEXIBLEAUTOEXT")
case ScalingTechnique.NORESCALE => Json.fromString("NORESCALE")
}
implicit val scalingTechniqueDecoder: Decoder[ScalingTechnique] =
Decoder.decodeString.emap {
case "FIXEDMANUAL" => Right(ScalingTechnique.FIXEDMANUAL)
case "FIXEDAUTO" => Right(ScalingTechnique.FIXEDAUTO)
case "FLEXIBLEAUTO" => Right(ScalingTechnique.FLEXIBLEAUTO)
case "FLEXIBLEAUTOEXT" => Right(ScalingTechnique.FLEXIBLEAUTOEXT)
case "NORESCALE" => Right(ScalingTechnique.NORESCALE)
case other => Left(s"Unknown scaling technique: $other")
}
implicit val encParamsEncoder: Encoder[EncParams] = deriveEncoder
implicit val libConfigEncoder: Encoder[LibConfig] = deriveEncoder
implicit val t2ProgramEncoder: Encoder[T2Program] = deriveEncoder
implicit val failureEncoder: Encoder[Failure] = deriveEncoder
implicit val resultInfoEncoder: Encoder[ResultInfo] = Encoder.forProduct7(
"programId",
"program",
"result",
"failures",
"expected",
"SEAL",
"OpenFHE",
)(ri =>
(
ri.programId,
ri.program,
ri.result,
ri.failures,
ri.expected,
ri.SEAL,
ri.OpenFHE,
),
)
implicit val encodeIntOrDouble: Encoder[Int | Double] = Encoder.instance {
case i: Int => Json.fromInt(i)
case d: Double => Json.fromDoubleOrNull(d)
}

object DumpUtil {
// 파일에 문자열 데이터 쓰기 함수
def dumpFile(data: String, filename: String): Unit = {
val writer = new PrintWriter(filename)
try writer.write(data)
finally writer.close()
}

// dumpResult 함수 구현
def dumpResult(
program: T2Program, // 가정: 이미 정의되어 있음
i: Int,
res: CheckResult,
sealVersion: String,
openfheVersion: String,
): Unit = {
val resultString = res match {
case Same(_) => "Success"
case Diff(_, fails) => "Fail"
case ParserError(_) => "ParseError"
}
case Diff(res, fails) => {
val (expectedLst, obtainedLst) = res.partition(_.backend == "CLEAR")
val expected = expectedLst.apply(0)
// val diffResults = obtainedLst.filter(isDiff(expected, _, ))
val failures = fails.map(r =>
Map(
("library" -> r.backend),
("failedResult" -> r.result.toString),
),
)
val result = info ++ Map(
"result" -> JsString("Fail"),
"failedLibraires" -> JsString(fails.size.toString),
"failures" -> failures.toJson,
"expected" -> JsString(expected._2.toString),
)
val failFilename = s"$failDir/$i.json"
dumpJson(result, failFilename)

val failures = res match {
case Diff(_, fails) =>
fails.map(fail => Failure(fail.backend, fail.result.toString()))
case _ => List.empty[Failure]
}
case ParserError(_) => {
val result = info ++ Map(
"result" -> JsString("ParseError"),
"failedLibraires" -> JsString("NaN"),
"failures" -> JsArray(),
"expected" -> JsString(""),
)
val psrErrFilename = s"$psrErrDir/$i.json"
dumpJson(result, psrErrFilename)

val expected = res match {
case Same(results) =>
results.headOption.map(_.result.toString()).getOrElse("")
case Diff(results, _) =>
results
.partition(_.backend == "CLEAR")
._1
.headOption
.map(_.result.toString())
.getOrElse("")
}

val resultInfo = ResultInfo(
i,
program,
resultString,
failures,
expected,
sealVersion,
openfheVersion,
)

val filename = res match
case Same(_) => s"$succDir$i.json"
case Diff(_, fails) => s"$failDir/$i.json"
case ParserError(_) => s"$psrErrDir/$i.json"
dumpFile(resultInfo.asJson.spaces2, filename)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/fhetest/Generate/LibConfigGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def generateLibConfig(encType: ENC_TYPE): LibConfig = {
val randomLenOpt: Option[Int] = Some(Random.between(1, 100000 + 1))
val randomBoundOpt: Option[Int | Double] = randomScheme match {
case Scheme.BFV | Scheme.BGV =>
Some(Random.nextInt(Int.MaxValue))
Some(Random.nextInt(100000))
case Scheme.CKKS => Some(Random.between(0, math.pow(2, 64)))
}
LibConfig(
Expand Down
18 changes: 15 additions & 3 deletions src/main/scala/fhetest/Phase/Check.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import fhetest.Checker.*
import fhetest.Generate.T2Program
import fhetest.LibConfig
import fhetest.Utils.*
import fhetest.Checker.DumpUtil

import org.twc.terminator.t2dsl_compiler.T2DSLsyntaxtree.*;
import org.twc.terminator.SymbolTable;

import java.nio.file.{Files, Paths};
import java.io.{File, InputStream, ByteArrayInputStream}
import scala.jdk.CollectionConverters._
import spray.json._

import scala.util.{Try, Success, Failure}

Expand Down Expand Up @@ -90,7 +90,13 @@ case object Check {
encParams.plainMod,
)
if (toJson)
dumpResult(program, i, checkResult, sealVersion, openfheVersion)
DumpUtil.dumpResult(
program,
i,
checkResult,
sealVersion,
openfheVersion,
)
if (debug) {
println(s"Program $i:")
}
Expand Down Expand Up @@ -140,7 +146,13 @@ case object Check {
val program = T2Program(fileStr, libConfig)
val checkResult = apply(program, backends, encParamsOpt)
if (toJson)
dumpResult(program, i, checkResult, sealVersion, openfheVersion)
DumpUtil.dumpResult(
program,
i,
checkResult,
sealVersion,
openfheVersion,
)
val pgmStr = "-" * 10 + " Program " + "-" * 10 + "\n" + fileStr + "\n"
val libConfigStr =
"-" * 10 + " LibConfig " + "-" * 10 + "\n" + libConfig
Expand Down
6 changes: 6 additions & 0 deletions src/main/scala/fhetest/Phase/Execute.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ case object Execute {
"Program terminated with segmentation fault (exit code 139).\n",
)
return errorSB.toString()
} else if (executeExitCode == 136) {
// If program terminated with segmentation fault, return error message
errorSB.append(
"Program terminated with floating point exception (exit code 136).\n",
)
return errorSB.toString()
} else {
// If execute failed, append error message
return errorSB.toString()
Expand Down

0 comments on commit a1786ca

Please sign in to comment.