aboutsummaryrefslogtreecommitdiffstats
path: root/Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend')
-rw-r--r--Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend400
1 files changed, 400 insertions, 0 deletions
diff --git a/Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend b/Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend
new file mode 100644
index 00000000..973c3d13
--- /dev/null
+++ b/Tests/hu.bme.mit.inf.dslreasoner.run/src/hu/bme/mit/inf/dslreasoner/run/script/MeasurementScriptRunner.xtend
@@ -0,0 +1,400 @@
1package hu.bme.mit.inf.dslreasoner.run.script
2
3import com.google.gson.Gson
4import hu.bme.mit.inf.dlsreasoner.alloy.reasoner.AlloySolver
5import hu.bme.mit.inf.dlsreasoner.alloy.reasoner.AlloySolverConfiguration
6import hu.bme.mit.inf.dslreasoner.ecore2logic.EClassMapper
7import hu.bme.mit.inf.dslreasoner.ecore2logic.Ecore2Logic
8import hu.bme.mit.inf.dslreasoner.ecore2logic.Ecore2LogicConfiguration
9import hu.bme.mit.inf.dslreasoner.ecore2logic.Ecore2Logic_Trace
10import hu.bme.mit.inf.dslreasoner.logic.model.builder.DocumentationLevel
11import hu.bme.mit.inf.dslreasoner.logic.model.builder.LogicSolverConfiguration
12import hu.bme.mit.inf.dslreasoner.logic.model.builder.TypeScopes
13import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.DefinedElement
14import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.IntLiteral
15import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.RealLiteral
16import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.StringLiteral
17import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.Type
18import hu.bme.mit.inf.dslreasoner.logic.model.logiclanguage.TypeDefinition
19import hu.bme.mit.inf.dslreasoner.logic.model.logicproblem.LogicProblem
20import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.IntStatisticEntry
21import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.LogicresultFactory
22import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.ModelResult
23import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.RealStatisticEntry
24import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.Statistics
25import hu.bme.mit.inf.dslreasoner.logic.model.logicresult.StringStatisticEntry
26import hu.bme.mit.inf.dslreasoner.logic2ecore.Logic2Ecore
27import hu.bme.mit.inf.dslreasoner.run.EcoreLoader
28import hu.bme.mit.inf.dslreasoner.run.FAMLoader
29import hu.bme.mit.inf.dslreasoner.run.FileSystemLoader
30import hu.bme.mit.inf.dslreasoner.run.MetamodelLoader
31import hu.bme.mit.inf.dslreasoner.run.SatelliteLoader
32import hu.bme.mit.inf.dslreasoner.run.YakinduLoader
33import hu.bme.mit.inf.dslreasoner.util.CollectionsUtil
34import hu.bme.mit.inf.dslreasoner.viatra2logic.Viatra2Logic
35import hu.bme.mit.inf.dslreasoner.viatra2logic.Viatra2LogicConfiguration
36import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedralScopePropagatorConstraints
37import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.PolyhedralScopePropagatorSolver
38import hu.bme.mit.inf.dslreasoner.viatrasolver.logic2viatra.cardinality.ScopePropagatorStrategy
39import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretation2logic.InstanceModel2Logic
40import hu.bme.mit.inf.dslreasoner.viatrasolver.partialinterpretationlanguage.partial2logicannotations.PartialModelRelation2Assertion
41import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.ViatraReasoner
42import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.ViatraReasonerConfiguration
43import hu.bme.mit.inf.dslreasoner.workspace.FileSystemWorkspace
44import hu.bme.mit.inf.dslreasoner.workspace.ReasonerWorkspace
45import java.io.FileReader
46import java.util.HashMap
47import java.util.HashSet
48import java.util.Map
49import java.util.Set
50import org.eclipse.emf.ecore.EObject
51import org.eclipse.emf.ecore.resource.Resource
52import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl
53import org.eclipse.viatra.query.patternlanguage.emf.EMFPatternLanguageStandaloneSetup
54import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions
55import org.eclipse.viatra.query.runtime.rete.matcher.ReteBackendFactory
56import org.eclipse.xtend.lib.annotations.Data
57import hu.bme.mit.inf.dlsreasoner.alloy.reasoner.AlloyBackendSolver
58
59class MeasurementScriptRunner {
60 static val MODEL_SIZE_GAP = 0
61 static val SCOPE_PROPAGATOR_TIMEOUT = 10
62 static val USEC_TO_MSEC = 1000000
63
64 static extension val LogicresultFactory = LogicresultFactory.eINSTANCE
65
66 val MeasurementScript script
67 val ReasonerWorkspace inputWorkspace
68 val ReasonerWorkspace outputWorkspace
69 val MetamodelLoader metamodelLoader
70
71 new(MeasurementScript script) {
72 this.script = script
73 inputWorkspace = new FileSystemWorkspace(script.inputPath + "/", "")
74 outputWorkspace = new FileSystemWorkspace(script.outputPath +
75 "/", '''«script.domain»_«script.solver»_«script.scope»_«script.scopePropagator ?: "na"»_«script.propagatedConstraints ?: "na"»_«script.polyhedronSolver ?: "na"»_«script.scopeHeuristic ?: "na"»_''')
76 metamodelLoader = switch (script.domain) {
77 case fs: new FileSystemLoader(inputWorkspace)
78 case ecore: new EcoreLoader(inputWorkspace)
79 case ecoreUnsat: new EcoreLoader(inputWorkspace, false)
80 case Yakindu: new YakinduLoader(inputWorkspace) => [useSynchronization = false; useComplexStates = true]
81 case YakinduUnsat: new YakinduLoader(inputWorkspace, false) => [useSynchronization = false; useComplexStates = true]
82 case FAM: new FAMLoader(inputWorkspace)
83 case satellite: new SatelliteLoader(inputWorkspace)
84 case satelliteUnsat: new SatelliteLoader(inputWorkspace, false)
85 default: throw new IllegalArgumentException("Unsupported domain: " + script.domain)
86 }
87 }
88
89 def run() {
90 if (script.sizes.empty) {
91 return
92 }
93 val start = System.currentTimeMillis
94 val warmupSize = script.sizes.head
95 for (var int i = 0; i < script.warmupIterations; i++) {
96 System.err.println('''Warmup «i + 1»/«script.warmupIterations»...''')
97 runExperiment(warmupSize)
98 }
99 val warmupEnd = System.currentTimeMillis
100 System.err.println('''Warmup completed in «(warmupEnd - start) / 1000» seconds''')
101 for (size : script.sizes) {
102 var int failures = 0
103 for (var int i = 0; i < script.iterations; i++) {
104 System.err.println("Running GC...")
105 runGc()
106 System.err.println('''Iteration «i + 1»/«script.iterations» of size «size»...''')
107 val startTime = System.currentTimeMillis
108 val result = runExperiment(size)
109 val headerPrefix = '''«script.toCsvHeader»,«size»,«i + 1»,«result.resultName»'''
110 println('''«headerPrefix»,startTime,«startTime»''')
111 println('''«headerPrefix»,logic2SolverTransformationTime,«result.statistics.transformationTime»''')
112 println('''«headerPrefix»,solverTime,«result.statistics.solverTime»''')
113 for (statistic : result.statistics.entries) {
114 val valueString = switch (statistic) {
115 IntStatisticEntry: statistic.value.toString
116 RealStatisticEntry: statistic.value.toString
117 StringStatisticEntry: statistic.value.toString
118 default: statistic.toString
119 }
120 println('''«headerPrefix»,«statistic.name»,«valueString»''')
121 }
122 if (script.saveModels && result.model !== null) {
123 outputWorkspace.writeModel(result.model, '''«size»_«i + 1».xmi''')
124 }
125 if (result.resultName === "InsuficientResourcesResultImpl") {
126 failures++
127 }
128 System.out.flush
129 }
130 if (failures == script.iterations) {
131 System.err.println("All measurements failed")
132 return
133 }
134 }
135 val end = System.currentTimeMillis
136 System.err.println('''Measurement completed in «(end - start) / 1000» seconds''')
137 }
138
139 private static def void runGc() {
140 System.gc
141 Thread.sleep(100)
142 System.gc
143 Thread.sleep(100)
144 System.gc
145 Thread.sleep(800)
146 }
147
148 private def createViatraConfig() {
149 val config = new ViatraReasonerConfiguration
150 config.debugConfiguration.partialInterpretatioVisualiser = null
151 config.searchSpaceConstraints.additionalGlobalConstraints += metamodelLoader.additionalConstraints
152 config.scopePropagatorStrategy = switch (script.scopePropagator) {
153 case none:
154 ScopePropagatorStrategy.None
155 case basic:
156 switch (script.propagatedConstraints) {
157 case none:
158 ScopePropagatorStrategy.Basic
159 case typeHierarchy:
160 ScopePropagatorStrategy.BasicTypeHierarchy
161 case relations,
162 case hints:
163 throw new IllegalArgumentException(
164 "Basic scope propagator does not support relational and hint constraints")
165 default:
166 throw new IllegalArgumentException("Unknown scope constraints: " + script.propagatedConstraints)
167 }
168 case polyhedral: {
169 val constraints = switch (script.propagatedConstraints) {
170 case none:
171 throw new IllegalArgumentException(
172 "Polyhedral scope propagator needs at least type hierarchy constraints")
173 case typeHierarchy:
174 PolyhedralScopePropagatorConstraints.TypeHierarchy
175 case relations,
176 case hints:
177 PolyhedralScopePropagatorConstraints.Relational
178 default:
179 throw new IllegalArgumentException("Unknown scope constraints: " + script.propagatedConstraints)
180 }
181 val polyhedronSolver = switch (script.polyhedronSolver) {
182 case Z3Integer: PolyhedralScopePropagatorSolver.Z3Integer
183 case Z3Real: PolyhedralScopePropagatorSolver.Z3Real
184 case Cbc: PolyhedralScopePropagatorSolver.Cbc
185 case Clp: PolyhedralScopePropagatorSolver.Clp
186 default: throw new IllegalArgumentException("Unknown polyhedron solver: " + script.polyhedronSolver)
187 }
188 val updateHeuristic = script.scopeHeuristic != ScopeHeuristic.basic
189 new ScopePropagatorStrategy.Polyhedral(constraints, polyhedronSolver, updateHeuristic,
190 SCOPE_PROPAGATOR_TIMEOUT)
191 }
192 default:
193 throw new IllegalArgumentException("Unknown scope propagator: " + script.scopePropagator)
194 }
195 config
196 }
197
198 private def createAlloyConfig(AlloyBackendSolver backendSolver) {
199 val config = new AlloySolverConfiguration
200 config.solver = backendSolver
201 config
202 }
203
204 private def createConfig(int modelSize) {
205 val config = switch (solver : script.solver) {
206 case ViatraSolver: createViatraConfig()
207 case AlloySolver: createAlloyConfig(AlloyBackendSolver.SAT4J)
208 case AlloyMiniSat: createAlloyConfig(AlloyBackendSolver.MiniSatJNI)
209 default: throw new IllegalArgumentException("Unknown solver: " + solver)
210 }
211 config.solutionScope.numberOfRequiredSolutions = 1
212 config.runtimeLimit = script.timeout
213 config.documentationLevel = if(script.saveTemporaryFiles) DocumentationLevel.NORMAL else DocumentationLevel.NONE
214 config
215 }
216
217 private def runExperiment(int modelSize) {
218 val config = createConfig(modelSize)
219 val modelLoadingStart = System.nanoTime
220 val metamodelDescriptor = metamodelLoader.loadMetamodel
221 val partialModelDescriptor = metamodelLoader.loadPartialModel
222 val queryDescriptor = metamodelLoader.loadQueries(metamodelDescriptor)
223 val modelLoadingTime = System.nanoTime - modelLoadingStart
224
225 val domain2LogicTransformationStart = System.nanoTime
226 val Ecore2Logic ecore2Logic = new Ecore2Logic
227 val Viatra2Logic viatra2Logic = new Viatra2Logic(ecore2Logic)
228 val InstanceModel2Logic instanceModel2Logic = new InstanceModel2Logic
229 var modelGeneration = ecore2Logic.transformMetamodel(metamodelDescriptor, new Ecore2LogicConfiguration())
230 var problem = modelGeneration.output
231 problem = instanceModel2Logic.transform(
232 modelGeneration,
233 partialModelDescriptor
234 ).output
235 problem = viatra2Logic.transformQueries(
236 queryDescriptor,
237 modelGeneration,
238 new Viatra2LogicConfiguration
239 ).output
240 initializeScope(config, modelSize, problem, ecore2Logic, modelGeneration.trace)
241 if (config instanceof ViatraReasonerConfiguration && script.propagatedConstraints == ScopeConstraints.hints) {
242 (config as ViatraReasonerConfiguration).hints = metamodelLoader.getHints(ecore2Logic, modelGeneration.trace)
243 }
244 val domain2LogicTransformationTime = System.nanoTime - domain2LogicTransformationStart
245
246 if (config.documentationLevel != DocumentationLevel.NONE) {
247 outputWorkspace.writeModel(problem, "initial.logicproblem")
248 }
249
250 val solver = switch (solver : script.solver) {
251 case ViatraSolver: new ViatraReasoner
252 case AlloySolver,
253 case AlloyMiniSat: new AlloySolver
254 default: throw new IllegalArgumentException("Unknown solver: " + solver)
255 }
256 val result = solver.solve(problem, config, outputWorkspace)
257 val statistics = result.statistics
258 statistics.entries += createIntStatisticEntry => [
259 name = "modelLoadingTime"
260 value = (modelLoadingTime / USEC_TO_MSEC) as int
261 ]
262 statistics.entries += createIntStatisticEntry => [
263 name = "domain2LogicTransformationTime"
264 value = (domain2LogicTransformationTime / USEC_TO_MSEC) as int
265 ]
266 var EObject modelResult = null
267 if (result instanceof ModelResult) {
268 val intepretations = solver.getInterpretations(result)
269 if (intepretations.size != 1) {
270 throw new IllegalStateException("Expected 1 interpretation, got " + intepretations.size)
271 }
272 var resultTransformationStart = System.nanoTime
273 val logic2Ecore = new Logic2Ecore(ecore2Logic)
274 modelResult = logic2Ecore.transformInterpretation(intepretations.head, modelGeneration.trace)
275 val resultTransformationTime = System.nanoTime - resultTransformationStart
276 statistics.entries += createIntStatisticEntry => [
277 name = "ecore2LogicTransformationTime"
278 value = (resultTransformationTime / USEC_TO_MSEC) as int
279 ]
280 }
281
282 new ExperimentResult(result.class.simpleName, statistics, modelResult)
283 }
284
285 private def initializeScope(LogicSolverConfiguration config, int modelSize, LogicProblem problem,
286 EClassMapper eClassMapper, Ecore2Logic_Trace trace) {
287 val knownElements = initializeKnownElements(problem, config.typeScopes)
288 if (modelSize < 0) {
289 config.typeScopes.minNewElements = 0
290 config.typeScopes.maxNewElements = TypeScopes.Unlimited
291 } else {
292 val numberOfKnownElements = knownElements.values.flatten.toSet.size
293 val newElementCount = modelSize - numberOfKnownElements
294 switch (script.scope) {
295 case upperOnly:
296 config.typeScopes.maxNewElements = newElementCount + MODEL_SIZE_GAP
297 case exactly: {
298 config.typeScopes.minNewElements = newElementCount
299 config.typeScopes.maxNewElements = newElementCount
300 }
301 default: {
302 config.typeScopes.minNewElements = newElementCount
303 config.typeScopes.maxNewElements = newElementCount + MODEL_SIZE_GAP
304 }
305 }
306 }
307 switch (scope : script.scope) {
308 case none,
309 case exactly:
310 return
311 case quantiles,
312 case unsat,
313 case upperOnly: {
314 val quantiles = if (scope == Scope.unsat) {
315 metamodelLoader.unsatTypeQuantiles
316 } else {
317 metamodelLoader.typeQuantiles
318 }
319 for (eClassInScope : eClassMapper.allClassesInScope(trace)) {
320 val quantile = quantiles.get(eClassInScope.name)
321 if (quantile !== null) {
322 val type = eClassMapper.TypeofEClass(trace, eClassInScope)
323 val knownInstances = knownElements.get(type)
324 val currentCount = if(knownInstances === null) 0 else knownInstances.size
325 val lowCount = Math.floor(modelSize * quantile.low) as int
326 val highCount = Math.ceil((modelSize + MODEL_SIZE_GAP) * quantile.high) as int
327// println('''«type.name» «lowCount» «highCount»''')
328 if (script.scope != Scope.upperOnly) {
329 config.typeScopes.minNewElementsByType.put(type, Math.max(lowCount - currentCount, 0))
330 }
331 config.typeScopes.maxNewElementsByType.put(type, highCount - currentCount)
332 }
333 }
334 }
335 default:
336 throw new IllegalArgumentException("Unknown scope: " + script.scope)
337 }
338 }
339
340 /*
341 * Copied from hu.bme.mit.inf.dslreasoner.application.execution.ScopeLoader.initialiseknownElements(LogicProblem, TypeScopes)
342 */
343 private static def initializeKnownElements(LogicProblem p, TypeScopes s) {
344 val Map<Type, Set<DefinedElement>> res = new HashMap
345
346 // 1. fill map with every types
347 for (t : p.types) {
348 res.put(t, new HashSet)
349 }
350
351 // 2. fill map with every objects
352 for (definedType : p.types.filter(TypeDefinition)) {
353 val supertypes = CollectionsUtil.<Type>transitiveClosureStar(definedType)[supertypes]
354 for (supertype : supertypes) {
355 for (element : definedType.elements) {
356 res.get(supertype).add(element)
357 }
358 }
359 }
360 val partialModelContents = p.annotations.filter(PartialModelRelation2Assertion).map[target].toList.map [
361 eAllContents.toIterable
362 ].flatten.toList
363 s.knownIntegers += partialModelContents.filter(IntLiteral).map[it.value]
364 s.knownReals += partialModelContents.filter(RealLiteral).map[it.value]
365 s.knownStrings += partialModelContents.filter(StringLiteral).map[it.value]
366
367 res
368 }
369
370 public static def void main(String[] args) {
371 if (args.length != 1) {
372 System.err.println("Missing measurement script name.")
373 System.exit(-1)
374 }
375 EMFPatternLanguageStandaloneSetup.doSetup
376 ViatraQueryEngineOptions.setSystemDefaultBackends(ReteBackendFactory.INSTANCE, ReteBackendFactory.INSTANCE,
377 ReteBackendFactory.INSTANCE)
378 Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl)
379 val config = readConfig(args.get(0))
380 val runnner = new MeasurementScriptRunner(config)
381 runnner.run()
382 }
383
384 static def readConfig(String scriptPath) {
385 val gson = new Gson
386 val reader = new FileReader(scriptPath)
387 try {
388 gson.fromJson(reader, MeasurementScript)
389 } finally {
390 reader.close
391 }
392 }
393
394 @Data
395 private static class ExperimentResult {
396 String resultName
397 Statistics statistics
398 EObject model
399 }
400}