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