diff --git a/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILP.ast b/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILP.ast index c40187e7b15a5072f1d717ad2ee42e115b7b69e9..03a7d83171338e92e3b8fe719ad7ef256f1eb03d 100644 --- a/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILP.ast +++ b/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILP.ast @@ -1,18 +1,19 @@ +abstract IlpElement ; ILP ::= IlpObjective IlpConstraint* IlpBound* IlpVariable* <Info:IlpVarInfo> ; TimedOutILP:ILP ::= <Reason:String> ; // objective kind is either minimize or maximize -IlpObjective ::= <Kind:IlpObjectiveKind> IlpLeftHandSide ; +IlpObjective:IlpElement ::= <Kind:IlpObjectiveKind> IlpLeftHandSide ; -IlpConstraint ::= <Name:String> IlpLeftHandSide <ClauseComparator:ClauseComparator> <RightHandSide:double> ; +IlpConstraint:IlpElement ::= <Name:String> IlpLeftHandSide <ClauseComparator:ClauseComparator> <RightHandSide:double> ; -IlpBound ::= <Ref:IlpVariable> <Type:IlpBoundType> ; +IlpBound:IlpElement ::= <Ref:IlpVariable> <Type:IlpBoundType> ; -IlpVariable ::= <Name:String> <Request:Request> <Impl:Implementation> ; +IlpVariable:IlpElement ::= <Name:String> <Request:Request> <Impl:Implementation> ; IlpAllResourcesVariable:IlpVariable ; IlpMappingVariable:IlpVariable ::= <Resource:Resource> ; // sum of terms -IlpLeftHandSide ::= IlpTerm* ; +IlpLeftHandSide:IlpElement ::= IlpTerm* ; -IlpTerm ::= <Value:double> <Ref:IlpVariable> ; +IlpTerm:IlpElement ::= <Value:double> <Ref:IlpVariable> ; diff --git a/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILPPrinting.jrag b/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILPPrinting.jrag index d8a980bc0add96f61fa466136dc116d54b0e1f58..f1b1b479fe513a8cf2c46d23676f628a16a3f6fe 100644 --- a/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILPPrinting.jrag +++ b/jastadd-mquat-base/src/main/jastadd/solvers/ilp/ILPPrinting.jrag @@ -14,7 +14,9 @@ aspect ILPPrinting { // TODO check if "Generals" is always correct result.append("Generals").lb(); for (IlpVariable v : getIlpVariableList()) { - result.append(v.getName()).append(" "); + if (v.isValid()) { + result.append(v.getName()).append(" "); + } } return result.lb().append("End").lb(); } @@ -30,7 +32,12 @@ aspect ILPPrinting { syn IlpString IlpConstraint.printIlp() { IlpString result = new IlpString(); - result.append(getName()).append(": ").append(getIlpLeftHandSide().printIlp()).append(" "); + IlpString lhs = getIlpLeftHandSide().printIlp(); + if (lhs == null) { + return result; + } + + result.append(getName()).append(": ").append(lhs).append(" "); switch (getClauseComparator()) { case LT: result.append("<"); break; case LE: result.append("<="); break; @@ -44,6 +51,9 @@ aspect ILPPrinting { syn IlpString IlpBound.printIlp() { IlpString result = new IlpString(); + if (!getRef().isValid()) { + return result; + } switch(getType()) { case BINARY: result.append("0 <= ").append(getRef().getName()).append(" <= 1"); break; case ZERO: result.append(getRef().getName()).append(" = 0"); break; @@ -53,9 +63,30 @@ aspect ILPPrinting { return result; } + inh ILP IlpElement.containingIlp(); + + eq ILP.getIlpObjective().containingIlp() = this; + eq ILP.getIlpConstraint(int i).containingIlp() = this; + eq ILP.getIlpBound(int i).containingIlp() = this; + eq ILP.getIlpVariable(int i).containingIlp() = this; + + syn boolean IlpTerm.isValid() { + return getRef().isValid(); + } + + syn boolean IlpVariable.isValid() { + return !containingIlp().getInfo().illegal.contains(this); + } + syn IlpString IlpLeftHandSide.printIlp() { IlpString result = new IlpString(); + boolean printed = false; for (IlpTerm t : getIlpTermList()) { + if (!t.isValid()) { + continue; + } else { + printed = true; + } if (t.getValue() >= 0) { result.append(" +"); } else { @@ -68,7 +99,11 @@ aspect ILPPrinting { } result.append(" ").append(t.getRef().getName()); } - return result; + if (printed) { + return result; + } else { + return null; + } } } \ No newline at end of file diff --git a/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java b/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java index b15bc10983ea3f192f24141216015ae80f7e32ca..fdf9f9d825c530d415a76ced6c8abf73c1272f96 100644 --- a/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java +++ b/jastadd-mquat-solver/src/test/java/de/tudresden/inf/st/mquat/solving/HandwrittenTestSuite.java @@ -8,8 +8,7 @@ import org.apache.logging.log4j.Logger; import org.junit.*; import org.junit.rules.ErrorCollector; -import java.io.*; -import java.net.URL; +import java.io.IOException; import java.util.Iterator; import static org.hamcrest.core.IsEqual.equalTo; @@ -18,10 +17,9 @@ import static org.junit.Assert.assertTrue; public abstract class HandwrittenTestSuite { private static Logger logger; - private Solver solver; - @Rule public ErrorCollector collector = new ErrorCollector(); + private Solver solver; @BeforeClass public static void setupClass() { @@ -35,6 +33,7 @@ public abstract class HandwrittenTestSuite { /** * Create and return the solver to use in this test suite + * * @return a solver instance */ protected abstract Solver getSolver(); @@ -80,6 +79,7 @@ public abstract class HandwrittenTestSuite { /** * Check if request, configuration and resource of the given assignments are equal + * * @param actualAssignment assignment in the computed solution * @param expectedAssignment expected assignment defined in the test case * @return <code>true</code> if both match, <code>false</code> otherwise @@ -110,7 +110,7 @@ public abstract class HandwrittenTestSuite { assertValidSolution(modelAndSolution); Assignment config_0i0m0 = assertAssignment(modelAndSolution, 0, "config_0i0m0", "r0"); Assignment config_1i0m0 = assertAssignment(modelAndSolution, 0, "config_1i0m0", "r1"); - assertComponentRequirement(config_0i0m0,"other", config_1i0m0); + assertComponentRequirement(config_0i0m0, "other", config_1i0m0); } @Test @@ -119,7 +119,7 @@ public abstract class HandwrittenTestSuite { assertValidSolution(modelAndSolution); Assignment config_0i0m0 = assertAssignment(modelAndSolution, 0, "config_0i0m0", "r0"); Assignment config_1i0m0 = assertAssignment(modelAndSolution, 0, "config_1i0m0", "r1"); - assertComponentRequirement(config_0i0m0,"other", config_1i0m0); + assertComponentRequirement(config_0i0m0, "other", config_1i0m0); } @Test @@ -129,7 +129,7 @@ public abstract class HandwrittenTestSuite { Assignment r0config_0i0m0 = assertAssignment(modelAndSolution, 0, "config_0i0m0", "r0"); Assignment r0config_1i0m0 = assertAssignment(modelAndSolution, 0, "config_1i0m0", "r1"); assertAssignment(modelAndSolution, 1, "config_1i0m0", "r2"); - assertComponentRequirement(r0config_0i0m0,"other", r0config_1i0m0); + assertComponentRequirement(r0config_0i0m0, "other", r0config_1i0m0); } @Test @@ -139,8 +139,8 @@ public abstract class HandwrittenTestSuite { Assignment config_0i0m0 = assertAssignment(modelAndSolution, 0, "config_0i0m0", "r0"); Assignment config_1i0m0 = assertAssignment(modelAndSolution, 0, "config_1i0m0", "r1"); Assignment config_2i0m0 = assertAssignment(modelAndSolution, 0, "config_2i0m0", "r2"); - assertComponentRequirement(config_0i0m0,"alpha", config_1i0m0); - assertComponentRequirement(config_0i0m0,"beta", config_2i0m0); + assertComponentRequirement(config_0i0m0, "alpha", config_1i0m0); + assertComponentRequirement(config_0i0m0, "beta", config_2i0m0); } @Test @@ -155,14 +155,21 @@ public abstract class HandwrittenTestSuite { Assignment configE = assertAssignment(modelAndSolution, 0, "configE0", "r2"); Assignment configF = assertAssignment(modelAndSolution, 0, "configF0", "r5"); Assignment configG = assertAssignment(modelAndSolution, 0, "configG0", "r6"); - assertComponentRequirement(configA,"beta", configB); - assertComponentRequirement(configA,"epsilon", configE); - assertComponentRequirement(configB,"chi", configC); - assertComponentRequirement(configB,"delta", configD); - assertComponentRequirement(configE,"phi", configF); - assertComponentRequirement(configE,"gamma", configG); + assertComponentRequirement(configA, "beta", configB); + assertComponentRequirement(configA, "epsilon", configE); + assertComponentRequirement(configB, "chi", configC); + assertComponentRequirement(configB, "delta", configD); + assertComponentRequirement(configE, "phi", configF); + assertComponentRequirement(configE, "gamma", configG); assertEquals("Objective does not fit", 21885.66, modelAndSolution.getSecondElement().computeObjective(), 0.01); } + @Test + public void test_06() throws IOException, Parser.Exception, SolvingException { + Tuple<Root, Solution> modelAndSolution = loadAndSolve("test_06.txt"); + assertValidSolution(modelAndSolution); + assertTrue(modelAndSolution.getSecondElement().isValid()); + } + } diff --git a/jastadd-mquat-solver/src/test/resources/test_06.txt b/jastadd-mquat-solver/src/test/resources/test_06.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebdd3b6347e046e7d5054ae7d3132d62175f10db --- /dev/null +++ b/jastadd-mquat-solver/src/test/resources/test_06.txt @@ -0,0 +1,181 @@ +container resource type ComputeNode { + resource type CPU { + property frequency [Hz] + property load [%] + } + resource type RAM { + using property total + using property free + } + resource type DISK { + using property total + using property free + } + resource type NETWORK { + property latency [ms] + property throughput [kB/s] + } +} + +resource resource0:ComputeNode { + resource cpu0_0:CPU { frequency = 1562.0 load = 0.0 } + resource ram0:RAM { total = 11494.0 free = 11494.0 } + resource disk0:DISK { total = 14107.0 free = 14107.0 } + resource network0:NETWORK { latency = 566.0 throughput = 70960.0 + } +} +resource resource1:ComputeNode { + resource cpu1_0:CPU { frequency = 1602.0 load = 0.0 } + resource ram1:RAM { total = 10079.0 free = 10079.0 } + resource disk1:DISK { total = 5637.0 free = 5637.0 } + resource network1:NETWORK { latency = 298.0 throughput = 45704.0 + } +} +resource resource2:ComputeNode { + resource cpu2_0:CPU { frequency = 976.0 load = 0.0 } + resource ram2:RAM { total = 3461.0 free = 3461.0 } + resource disk2:DISK { total = 7222.0 free = 7222.0 } + resource network2:NETWORK { latency = 22.0 throughput = 94130.0 } +} +property total [MB] +property free [MB] +meta size +property energy [J] +property quality [%] +component component_0 { + contract implementation_0i0 { + requires component the_component_0i0_0 of type component_0i0_0 + requires component the_component_0i0_1 of type component_0i0_1 + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring the_component_0i0_0.quality >= 100.0 + requiring the_component_0i0_1.quality >= 71.0 + requiring cpu_0.frequency >= 1858.0 + requiring ram_1.total >= 2825.0 + requiring disk_1.total >= 2707.0 + requiring network_1.throughput >= 5414.0 + providing quality = 6.0 + providing energy = ((0.87*(size^2.0))+(0.98*cpu_0.frequency)) + } + contract implementation_0i1 { + requires component the_component_0i1_0 of type component_0i1_0 + requires component the_component_0i1_1 of type component_0i1_1 + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring the_component_0i1_0.quality >= 18.0 + requiring the_component_0i1_1.quality >= 75.0 + requiring cpu_0.frequency >= 1561.0 + requiring ram_1.total >= 11493.0 + requiring disk_1.total >= 14106.0 + requiring network_1.throughput >= 70959.0 + providing quality = 45.0 + providing energy = ((0.85*(size^2.0))+(0.01*cpu_0.frequency)) + } + using property quality + using property energy +} + +component component_0i0_0 { + contract implementation_0i0_0i0 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 1715.0 + requiring ram_1.total >= 8262.0 + requiring disk_1.total >= 8706.0 + requiring network_1.throughput >= 33655.0 + providing quality = 9.0 + providing energy = ((0.31*(size^2.0))+(0.12*cpu_0.frequency)) + } + contract implementation_0i0_0i1 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 2290.0 + requiring ram_1.total >= 8914.0 + requiring disk_1.total >= 3658.0 + requiring network_1.throughput >= 61931.0 + providing quality = 65.0 + providing energy = ((0.98*(size^2.0))+(0.88*cpu_0.frequency)) + } + using property quality + using property energy +} + +component component_0i0_1 { + contract implementation_0i0_1i0 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 1718.0 + requiring ram_1.total >= 11052.0 + requiring disk_1.total >= 10535.0 + requiring network_1.throughput >= 29446.0 + providing quality = 68.0 + providing energy = ((0.15*(size^2.0))+(0.02*cpu_0.frequency)) + } + contract implementation_0i0_1i1 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 734.0 + requiring ram_1.total >= 15946.0 + requiring disk_1.total >= 7627.0 + requiring network_1.throughput >= 34065.0 + providing quality = 34.0 + providing energy = ((0.25*(size^2.0))+(0.29*cpu_0.frequency)) + } + using property quality + using property energy +} + +component component_0i1_0 { + contract implementation_0i1_0i0 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 2877.0 + requiring ram_1.total >= 885.0 + requiring disk_1.total >= 3788.0 + requiring network_1.throughput >= 65473.0 + providing quality = 15.0 + providing energy = ((0.53*(size^2.0))+(0.9*cpu_0.frequency)) + } + contract implementation_0i1_0i1 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 1601.0 + requiring ram_1.total >= 10078.0 + requiring disk_1.total >= 5636.0 + requiring network_1.throughput >= 45703.0 + providing quality = 30.0 + providing energy = ((0.31*(size^2.0))+(0.67*cpu_0.frequency)) + } + using property quality + using property energy +} + +component component_0i1_1 { + contract implementation_0i1_1i0 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 975.0 + requiring ram_1.total >= 3460.0 + requiring disk_1.total >= 7221.0 + requiring network_1.throughput >= 94129.0 + providing quality = 75.0 + providing energy = ((0.67*(size^2.0))+(0.69*cpu_0.frequency)) + } + contract implementation_0i1_1i1 { + requires resource compute_resource_0 of type ComputeNode with { cpu_0 of type CPU ram_1 of type RAM disk_1 of type DISK + network_1 of type NETWORK } + requiring cpu_0.frequency >= 2476.0 + requiring ram_1.total >= 9865.0 + requiring disk_1.total >= 11645.0 + requiring network_1.throughput >= 20249.0 + providing quality = 10.0 + providing energy = ((0.97*(size^2.0))+(0.87*cpu_0.frequency)) + } + using property quality + using property energy +} +request request0 for component_0 { + meta size = 917.0 + requiring quality >= 45.0 +} +minimize sum(energy)