| author | desharna | 
| Tue, 28 Sep 2021 10:47:18 +0200 | |
| changeset 74370 | d8dc8fdc46fc | 
| parent 74306 | a117c076aa22 | 
| child 74486 | 74a36aae067a | 
| permissions | -rw-r--r-- | 
| 72176 | 1 | /* Title: HOL/Tools/Nitpick/kodkod.scala | 
| 2 | Author: Makarius | |
| 3 | ||
| 4 | Scala interface for Kodkod. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle.nitpick | |
| 8 | ||
| 9 | import isabelle._ | |
| 10 | ||
| 72336 | 11 | import java.util.concurrent.{TimeUnit, LinkedBlockingQueue, ThreadPoolExecutor}
 | 
| 72177 | 12 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 13 | import org.antlr.runtime.{ANTLRInputStream, RecognitionException}
 | 
| 72177 | 14 | import de.tum.in.isabelle.Kodkodi.{Context, KodkodiLexer, KodkodiParser}
 | 
| 72176 | 15 | |
| 16 | ||
| 17 | object Kodkod | |
| 18 | {
 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 19 | /** result **/ | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 20 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 21 | sealed case class Result(rc: Int, out: String, err: String) | 
| 72179 | 22 |   {
 | 
| 74306 | 23 | def ok: Boolean = rc == Process_Result.RC.ok | 
| 72179 | 24 | def check: String = | 
| 25 | if (ok) out else error(if (err.isEmpty) "Error" else err) | |
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 26 | |
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 27 | def encode: XML.Body = | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 28 |     {
 | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 29 | import XML.Encode._ | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 30 | triple(int, string, string)((rc, out, err)) | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 31 | } | 
| 72179 | 32 | } | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 33 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 34 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 35 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 36 | /** execute **/ | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 37 | |
| 72179 | 38 | def execute(source: String, | 
| 72176 | 39 | solve_all: Boolean = false, | 
| 40 | prove: Boolean = false, | |
| 41 | max_solutions: Int = Integer.MAX_VALUE, | |
| 42 | cleanup_inst: Boolean = false, | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 43 | timeout: Time = Time.zero, | 
| 72199 | 44 | max_threads: Int = 0): Result = | 
| 72176 | 45 |   {
 | 
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 46 | /* executor */ | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 47 | |
| 72201 | 48 | val pool_size = if (max_threads == 0) Isabelle_Thread.max_threads() else max_threads | 
| 72336 | 49 | val executor: ThreadPoolExecutor = | 
| 50 | new ThreadPoolExecutor(pool_size, pool_size, 0L, TimeUnit.MILLISECONDS, | |
| 51 | new LinkedBlockingQueue[Runnable], new ThreadPoolExecutor.CallerRunsPolicy) | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 52 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 53 | val executor_killed = Synchronized(false) | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 54 | def executor_kill(): Unit = | 
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 55 | executor_killed.change(b => | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 56 |         if (b) b else { Isabelle_Thread.fork() { executor.shutdownNow() }; true })
 | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 57 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 58 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 59 | /* system context */ | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 60 | |
| 72203 | 61 |     class Exit extends Exception("EXIT")
 | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 62 | |
| 73338 | 63 | class Exec_Context extends Context | 
| 64 |     {
 | |
| 74306 | 65 | private var rc = Process_Result.RC.ok | 
| 73338 | 66 | private val out = new StringBuilder | 
| 67 | private val err = new StringBuilder | |
| 68 | ||
| 69 |       def return_code(i: Int): Unit = synchronized { rc = rc max i}
 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 70 | |
| 73338 | 71 |       override def output(s: String): Unit = synchronized {
 | 
| 72 | Exn.Interrupt.expose() | |
| 73 | out ++= s | |
| 74 | out += '\n' | |
| 75 | } | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 76 | |
| 73338 | 77 |       override def error(s: String): Unit = synchronized {
 | 
| 78 | Exn.Interrupt.expose() | |
| 79 | err ++= s | |
| 80 | err += '\n' | |
| 81 | } | |
| 82 | ||
| 83 | override def exit(i: Int): Unit = | |
| 84 |         synchronized {
 | |
| 85 | return_code(i) | |
| 86 | executor_kill() | |
| 87 | throw new Exit | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 88 | } | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 89 | |
| 73338 | 90 |       def result(): Result = synchronized { Result(rc, out.toString, err.toString) }
 | 
| 91 | } | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 92 | |
| 73338 | 93 | val context = new Exec_Context | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 94 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 95 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 96 | /* main */ | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 97 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 98 |     try {
 | 
| 73367 | 99 | val lexer = new KodkodiLexer(new ANTLRInputStream(Bytes(source).stream())) | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 100 | val parser = | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 101 | KodkodiParser.create(context, executor, | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 102 | false, solve_all, prove, max_solutions, cleanup_inst, lexer) | 
| 72176 | 103 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 104 | val timeout_request = | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 105 | if (timeout.is_zero) None | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 106 |         else {
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 107 |           Some(Event_Timer.request(Time.now() + timeout) {
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 108 |             context.error("Ran out of time")
 | 
| 74306 | 109 | context.return_code(Process_Result.RC.failure) | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 110 | executor_kill() | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 111 | }) | 
| 72177 | 112 | } | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 113 | |
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 114 |       try { parser.problems() }
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 115 |       catch { case exn: RecognitionException => parser.reportError(exn) }
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 116 | |
| 73367 | 117 | timeout_request.foreach(_.cancel()) | 
| 72177 | 118 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 119 |       if (parser.getTokenStream.LA(1) != KodkodiParser.EOF) {
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 120 |         context.error("Error: trailing tokens")
 | 
| 74306 | 121 | context.exit(Process_Result.RC.error) | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 122 | } | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 123 |       if (lexer.getNumberOfSyntaxErrors + parser.getNumberOfSyntaxErrors > 0) {
 | 
| 74306 | 124 | context.exit(Process_Result.RC.error) | 
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 125 | } | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 126 | } | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 127 |     catch {
 | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 128 | case _: Exit => | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 129 | case exn: Throwable => | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 130 | val message = exn.getMessage | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 131 | context.error(if (message.isEmpty) exn.toString else "Error: " + message) | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 132 | context.return_code(1) | 
| 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 133 | } | 
| 72177 | 134 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 135 | executor.shutdownNow() | 
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 136 | |
| 72178 
2481cdb84832
more realistic kodkod invocation, imitating command-line tool;
 wenzelm parents: 
72177diff
changeset | 137 | context.result() | 
| 72176 | 138 | } | 
| 72179 | 139 | |
| 72218 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 140 | |
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 141 | /** protocol handler **/ | 
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 142 | |
| 72179 | 143 | def warmup(): String = | 
| 72181 | 144 | execute( | 
| 72199 | 145 | "solver: \"MiniSat\"\n" + | 
| 72181 | 146 |       File.read(Path.explode("$KODKODI/examples/weber3.kki"))).check
 | 
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 147 | |
| 72218 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 148 | class Handler extends Session.Protocol_Handler | 
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 149 |   {
 | 
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 150 | override def init(session: Session): Unit = warmup() | 
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 151 | } | 
| 
a51736641843
initial Kodkod.warmup: preloading and basic integrity test;
 wenzelm parents: 
72204diff
changeset | 152 | |
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 153 | |
| 72204 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 154 | |
| 
cb746b19e1d7
more robust treatment of execution with interrupts;
 wenzelm parents: 
72203diff
changeset | 155 | /** scala function **/ | 
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 156 | |
| 73565 | 157 |   object Fun extends Scala.Fun_String("kodkod", thread = true)
 | 
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 158 |   {
 | 
| 72756 | 159 | val here = Scala_Project.here | 
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 160 | def apply(args: String): String = | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 161 |     {
 | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 162 | val (timeout, (solve_all, (max_solutions, (max_threads, kki)))) = | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 163 |       {
 | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 164 | import XML.Decode._ | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 165 | pair(int, pair(bool, pair(int, pair(int, string))))(YXML.parse_body(args)) | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 166 | } | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 167 | val result = | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 168 | execute(kki, | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 169 | solve_all = solve_all, | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 170 | max_solutions = max_solutions, | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 171 | timeout = Time.ms(timeout), | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 172 | max_threads = max_threads) | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 173 | YXML.string_of_body(result.encode) | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 174 | } | 
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 175 | } | 
| 72176 | 176 | } | 
| 72196 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 177 | |
| 
6dba090358d2
invoke Nitpick/Kodkod via Isabelle/Scala (instead of external process);
 wenzelm parents: 
72181diff
changeset | 178 | class Scala_Functions extends Scala.Functions(Kodkod.Fun) |