Skip to content

Commit

Permalink
Added support to generate trace from command line tool
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Thrane Hansen committed Jan 10, 2021
1 parent 4f646ee commit 6a6b6e7
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 36 deletions.
4 changes: 2 additions & 2 deletions release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ mkdir uppall_files_success
for f in examples/*.conf
do
OUT=./uppall_files_success/$(basename ${f%.*}).xml
java -jar $JARFILE -m ${f} -o $OUT
java -jar $JARFILE -m ${f} -o $OUT --verify
done

mkdir uppall_files_mistakes
for f in common_mistakes/*.conf
do
OUT=./uppall_files_mistakes/$(basename ${f%.*}).xml
java -jar $JARFILE -m ${f} -o $OUT
java -jar $JARFILE -m ${f} -o $OUT --verify --trace
done
3 changes: 2 additions & 1 deletion src/main/scala/cli/CLIConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import java.nio.file.Files
case class CLIConfig(
master: String = "examples/simple_master.conf",
output: String = Files.createTempFile("uppaal_", ".xml").toString,
verify: Boolean = false
verify: Boolean = false,
trace: Boolean = false
)
38 changes: 33 additions & 5 deletions src/main/scala/cli/ScenarioVerifierApp.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cli

import java.io.PrintWriter
import java.io.{File, PrintWriter}
import java.nio.file.{Files, Paths}

import core.{ModelEncoding, ScenarioGenerator, ScenarioLoader}
import org.apache.commons.io.FileUtils
import org.apache.logging.log4j.scala.Logging
import scopt.OParser
import trace_analyzer.TraceAnalyzer

object ScenarioVerifierApp extends App with Logging {

Expand All @@ -26,6 +28,9 @@ object ScenarioVerifierApp extends App with Logging {
opt[String]('o', "output")
.action((x, c) => c.copy(output = x))
.text("Output file containing master algorithm in UPPAAL."),
opt[Unit]("trace")
.action((_, c) => c.copy(trace = true))
.text("Create animation of the trace from the UPPAAL model"),
opt[Unit]("verify")
.action((_, c) => c.copy(verify = true))
.text("Uses verifyta to check the resulting UPPAAL model"),
Expand All @@ -35,9 +40,8 @@ object ScenarioVerifierApp extends App with Logging {
// OParser.parse returns Option[Config]
OParser.parse(parser, args, CLIConfig(), OParserSetup()) match {
case Some(config) =>

logger.info(f"Output file: ${config.output}.")
if (Files.exists(Paths.get(config.output))){
if (Files.exists(Paths.get(config.output))) {
logger.error(s"Output file already exists. Will not be overwritten. Delete it before running this app: ${config.output}")
System.exit(1)
}
Expand All @@ -49,14 +53,38 @@ object ScenarioVerifierApp extends App with Logging {

val queryModel = new ModelEncoding(masterModel)
val result = ScenarioGenerator.generate(queryModel)
new PrintWriter(config.output) { write(result); close() }
new PrintWriter(config.output) {
write(result);
close()
}

if (config.verify) {
logger.info(f"Verifying generated file.")
val checkExitCode = VerifyTA.checkEnvironment()
if (! checkExitCode){
if (!checkExitCode) {
System.exit(1)
}
val file = new File(config.output)
if (config.trace) {
val outputFolder = Paths.get(file.getParentFile.getName,"/video_trace")
if(!Files.exists(outputFolder))
Files.createDirectory(outputFolder)
val traceFile = Files.createTempFile("trace_", ".log").toFile
val result = VerifyTA.saveTraceToFile(file, traceFile)
if (result == 1) {
logger.info(s"Started generating the animation of trace ${masterModel.name} in folder: ${outputFolder}.")
val source = scala.io.Source.fromFile(traceFile)
try {
val lines = source.getLines()
TraceAnalyzer.AnalyseScenario(masterModel.name, lines, queryModel, outputFolder.toString)
}
finally source.close()
FileUtils.deleteQuietly(traceFile)
}
} else {
logger.info(s"Started verifying ${file.getName} in Uppaal.")
VerifyTA.verify(file)
}
}

case _ =>
Expand Down
40 changes: 23 additions & 17 deletions src/main/scala/cli/VerifyTA.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,44 @@ object VerifyTA extends Logging {
val output = pLog.output.toString
if (output.contains("Formula is NOT satisfied.")) {
logger.error(s"Model is not valid.")
logger.error(s"To see the trace, run: ${cmd}")
logger.error(s"Generate the trace and use to correct the algorithm.")
1
} else {
0
}
}
}

def saveTraceToFile(uppaalFile: File, traceFile: File) = {
def saveTraceToFile(uppaalFile: File, traceFile: File): Int = {
val fPath = uppaalFile.getAbsolutePath
val cmd = s"""${VERIFY} -t 1 -Y -s '${fPath}'"""
logger.info(s"Running command: ${cmd}")
val pLog = new VerifyTaProcessLogger()
val exitCode = Process(cmd).!(pLog)
if (exitCode != 0) {
logger.error(s"Command returned non zero exit code: ${exitCode}.")
logger.error(s"This is probably a syntax error.")
logger.error(s"This is probably a syntax error - no trace generated.")
2
} else {
val bw = new BufferedWriter(new FileWriter(traceFile))
val trace = pLog.output.toString.replace("State", "\nState").replace("Transitions", "\nTransitions")
.split("\n")
.drop(2).toList
val output = pLog.output.toString
if (output.contains("Formula is NOT satisfied.")) {
val bw = new BufferedWriter(new FileWriter(traceFile))
val trace = pLog.output.toString.replace("State", "\nState").replace("Transitions", "\nTransitions")
.split("\n")
.drop(2).toList

trace.drop(trace.indexWhere(_.contains("MasterA.Start"), 2))
.filterNot(_.contains("Transitions"))
.map(_.replaceAll("\\([^()]*\\)", ""))
.map(_.replaceAll("#depth=\\d+ *", ""))
.foreach(s => {
bw.write(s + "\n")
})
bw.close()
logger.info(s"Trace saved to file: ${traceFile}")
trace.drop(trace.indexWhere(_.contains("MasterA.Start"), 2))
.filterNot(s => !(s.contains("isInit=1") || s.contains("isSimulation=1")))
.map(_.replaceAll("\\([^()]*\\)", ""))
.map(_.replaceAll("#depth=\\d+ *", ""))
.foreach(s => {
bw.write(s + "\n")
})
bw.close()
1
} else {
logger.info("All Formulas are satisfied - no counter-example can be found.")
0
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/trace_analyzer/ScenarioPlotter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ object ScenarioPlotter {
state.isInitState && state.isDefinedInitInputState(fmu, port) || state.isSimulation && state.isDefinedInputState(fmu, port)
}

def plot(uppaalTrace: UppaalTrace): Unit = {
val init_movie = new File(s"example/init_${uppaalTrace.scenarioName}.mp4")
def plot(uppaalTrace: UppaalTrace, outputDirectory: String): Unit = {
val init_movie = new File(s"${outputDirectory}/init_${uppaalTrace.scenarioName}.mp4")
makeAnimation(init_movie, uppaalTrace.initStates, uppaalTrace.modelEncoding, uppaalTrace.scenarioName)

val scenario_movie = new File(s"example/simulation_${uppaalTrace.scenarioName}.mp4")
val scenario_movie = new File(s"${outputDirectory}/simulation_${uppaalTrace.scenarioName}.mp4")
makeAnimation(scenario_movie, uppaalTrace.simulationStates, uppaalTrace.modelEncoding, uppaalTrace.scenarioName)
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/trace_analyzer/TraceAnalyzer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import org.apache.logging.log4j.scala.Logging

object TraceAnalyzer extends Logging{

def AnalyseScenario(scenarioName: String, trace: Iterator[String], modelEncoding: ModelEncoding): Unit = {
def AnalyseScenario(scenarioName: String, trace: Iterator[String], modelEncoding: ModelEncoding, outputDirectory: String): Unit = {
val parser = new TraceParser(modelEncoding)
val modelStates = parser.parseScenarios(trace)
//TODO: This filtering could be avoided by changing the Uppaal-model
val tempStates = modelStates.filter(_.isInitState).dropWhile(_.action.actionNumber == 7)
val initStates = tempStates.slice(1, tempStates.indexWhere(_.action.actionNumber == 8) + 2).grouped(2).map(_.head).toList

val simulationStates = modelStates.filter(_.isSimulation).grouped(2).map(_.head).toList
ScenarioPlotter.plot(new UppaalTrace(modelEncoding, initStates, simulationStates, scenarioName))
ScenarioPlotter.plot(new UppaalTrace(modelEncoding, initStates, simulationStates, scenarioName), outputDirectory)
}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Master algorithm for MSD with algebraic loop across state variables."
name = "Master algorithm for nested loops."
scenario = {
fmus = {
msd1 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Simple master algorithm"
name = "Simple master algorithm - where connection is forgotten"
scenario = {
fmus = {
msd1 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Simple master algorithm"
name = "Simple master algorithm - wrong order of get and set"
scenario = {
fmus = {
msd1 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name = "Simple master algorithm"
name = "Simple master algorithm - step of size 0"
scenario = {
fmus = {
msd1 = {
Expand Down
2 changes: 2 additions & 0 deletions src/test/scala/ScenarioBuilderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import java.nio.file.Files
import cli.VerifyTA
import core.{MasterModel, ModelEncoding, ScenarioGenerator, ScenarioLoader}
import org.apache.commons.io.FileUtils
import org.scalatest.Ignore
import org.scalatest.flatspec._
import org.scalatest.matchers._
import synthesizer.LoopStrategy.{LoopStrategy, maximum, minimum}
import synthesizer._

import scala.collection.immutable.HashSet

@Ignore
class ScenarioBuilderTest extends AnyFlatSpec with should.Matchers {
def writeToTempFile(content: String) = {
val file = Files.createTempFile("uppaal_", ".xml").toFile
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/TraceTester.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.scalatest.flatspec._
import org.scalatest.matchers._
import trace_analyzer.TraceAnalyzer

//@Ignore
@Ignore
class TraceTester extends AnyFlatSpec with should.Matchers {
def writeToTempFile(content: String) = {
val file = Files.createTempFile("uppaal_", ".xml").toFile
Expand All @@ -34,7 +34,7 @@ class TraceTester extends AnyFlatSpec with should.Matchers {
val source = scala.io.Source.fromFile(traceFile)
try {
val lines = source.getLines()
TraceAnalyzer.AnalyseScenario(scenarioName, lines, encoding)
TraceAnalyzer.AnalyseScenario(scenarioName, lines, encoding, "example")
}
finally source.close()
FileUtils.deleteQuietly(traceFile)
Expand Down

0 comments on commit 6a6b6e7

Please sign in to comment.