Commit 09bb9854 authored by Jonathan Shahen's avatar Jonathan Shahen
Browse files

Merge branch 'ReduceToCNFSAT'

parents 21bab8d7 ed572862
......@@ -6,9 +6,9 @@
<classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
<classpathentry kind="lib" path="lib/junit-4.12.jar"/>
<classpathentry kind="lib" path="lib/hamcrest-core-1.3.jar"/>
<classpathentry kind="lib" path="lib/circuit.jar"/>
<classpathentry kind="lib" path="lib/oplall.jar"/>
<classpathentry kind="lib" path="lib/commons-csv-1.3/commons-csv-1.3.jar"/>
<classpathentry kind="lib" path="lib/commons-math3-3.6.1/commons-math3-3.6.1.jar"/>
<classpathentry kind="lib" path="lib/circuit.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
......@@ -2,6 +2,7 @@ package vagabond.pieces;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.*;
import vagabond.enums.PlacementMapDisplayStyle;
......@@ -250,6 +251,33 @@ public class PlacementMap {
m.writeOut(writer, displayStyle);
}
}
/**
* Get the VMs of a client on this machine. Return's null if no such machine exists.
*
* @param mID the machine's ID
* @param cID the client's ID
* @return a list of VMs
*/
public List<VM> getClientVMsOnMachine(Integer mID, Integer cID) {
Machine theMachine = null;
for(Iterator<Machine> i = _machines.iterator(); i.hasNext(); ) {
Machine m = i.next();
if(m._machineID.equals(mID)) {
theMachine = m; break;
}
}
if(theMachine == null) return null;
List<VM> ret = new LinkedList<VM>();
for(Iterator<VM> i = theMachine._vms.iterator(); i.hasNext(); ) {
VM avm = i.next();
if(avm._clientID.equals(cID)) ret.add(avm);
}
return ret;
}
/**
* Returns the maximum number of VMs any Client has
......
package vagabond.reduction.cnfsat;
import vagabond.pieces.PlacementMap;
import java.util.*;
import vagabond.pieces.*;
import vagabond.singleton.VagabondSettings;
/**
* Takes as input the result from the CNF-SAT solver and converts that into a PlacementMap
......@@ -8,6 +11,77 @@ import vagabond.pieces.PlacementMap;
*
*/
public class PlacementMapFromCNFSATSolver {
/**
*
* @param cnfcert
* @param nc
* @param ns
* @param nv
* @return
*/
public static List<List<Integer>> getNcvmspermachine(List<String> cnfcert, int nc, int ns, List<Integer> nv) {
List<Integer> vars = new ArrayList<Integer>();
int varshouldbe = 1;
for (int i = cnfcert.indexOf("s SATISFIABLE") + 1; i < cnfcert.size(); i++) {
String line = cnfcert.get(i);
if (line.charAt(0) != 'v')
break;
String[] strvars = line.split("\\s+");
for (int j = 0; j < strvars.length; j++) {
try {
int var = Integer.parseInt(strvars[j]);
if (var != 0) {
vars.add(new Integer(var));
assert Math.abs(var) == varshouldbe++;
}
} catch (Exception e) {
// continue quietly
}
}
}
List<List<Integer>> ret = new ArrayList<List<Integer>>();
int var = 0;
for (int client = 0; client < nc; client++) {
List<Integer> thisclientnvm = new ArrayList<Integer>();
for (int machine = 0; machine < ns; machine++) {
int nvbits;
try {
nvbits = ReduceToCNFSAT.nbits(nv.get(client));
} catch (Exception e) {
e.printStackTrace();
return null;
}
int nvmsthismachine = 0;
for (int i = 0; i < nvbits; i++) {
if (vars.get(var++) > 0) {
nvmsthismachine += (1 << i);
}
}
thisclientnvm.add(new Integer(nvmsthismachine));
}
ret.add(thisclientnvm);
}
return ret;
}
public static void sortMachines(List<Machine> l) {
// Quick insertion sort of machines by ID
int nmachines = l.size();
for (int i = 1; i < nmachines; i++) {
Machine curr = l.remove(i);
for (int j = i; j >= 0; j--) {
if (j == 0)
l.add(0, curr);
else if (l.get(j - 1)._machineID.intValue() <= curr._machineID.intValue()) {
l.add(j, curr);
break;
}
}
}
}
/**
* Creates a PlacementMap by deciphering the raw output from the CNF-SAT Solver and using whatever internal
......@@ -16,8 +90,100 @@ public class PlacementMapFromCNFSATSolver {
* @param rawOutputFromCNFSATSolver the textual output from the CNF-SAT solver
* @return PlacementMap that has the same Client, VM, and machine IDs as past the input to the reduction had
*/
public static PlacementMap getPlacementMap(ReduceToCNFSAT reduction, String rawOutputFromCNFSATSolver) {
return null;
public static PlacementMap getPlacementMap(ReduceToCNFSAT reduction, List<String> rawOutputFromCNFSATSolver) {
List<List<Integer>> ncvmspermachine = getNcvmspermachine(rawOutputFromCNFSATSolver, reduction.nc, reduction.ns,
reduction.nv);
// System.out.println(ncvmspermachine);
SumOfClientVMsPerMachine curr = new SumOfClientVMsPerMachine(reduction._eh._latestPlacementMap);
PlacementMap pm = new PlacementMap(reduction.ns, VagabondSettings.getInstance().numberOfMachineSlots);
List<Integer> clientIDs = new ArrayList<Integer>(reduction._eh._latestPlacementMap._clients.keySet());
Collections.sort(clientIDs);
assert clientIDs.size() == reduction.nc;
ArrayList<Machine> allmachines = new ArrayList<Machine>();
allmachines.addAll(reduction._eh._latestPlacementMap._machines);
sortMachines(allmachines);
List<List<VM>> clientpool = new ArrayList<List<VM>>(); // A pool for VMs per client to dole out to needy
// machines
for (int client = 0; client < reduction.nc; client++) {
Integer cid = clientIDs.get(client);
List<VM> tothisclientpool = new ArrayList<VM>(); // need this to be concrete VMs, not just a number of them
List<Integer> futurenvmspermachine = ncvmspermachine.get(client);
assert futurenvmspermachine.size() == reduction.ns;
for (int machine = 0; machine < reduction.ns; machine++) {
// System.out.println("curr.get("+machine+","+cid+") = "+curr.get(machine,cid));
// System.out.println("futurenvmspermachine.get("+machine+") = "+futurenvmspermachine.get(machine));
if (futurenvmspermachine.get(machine) < curr.get(machine, cid)) {
// We can grab some VMs from this machine for the pool.
int ngrab = curr.get(machine, cid) - futurenvmspermachine.get(machine);
Machine themachine = allmachines.get(machine);
for (Iterator<VM> it = themachine._vms.iterator(); it.hasNext() && ngrab > 0;) {
VM v = it.next();
if (clientIDs.indexOf(v._clientID) != client)
continue;
tothisclientpool.add(v);
ngrab--;
// System.out.println("Adding to pool for client "+v._clientID+" the VM "+v._globalID);
}
}
}
clientpool.add(tothisclientpool);
}
List<Machine> newmachines = pm._machines; // new machine config
sortMachines(newmachines);
for (int client = 0; client < reduction.nc; client++) {
Integer cid = clientIDs.get(client);
List<Integer> futurenvmspermachine = ncvmspermachine.get(client);
for (int machine = 0; machine < reduction.ns; machine++) {
Machine oldmachine = allmachines.get(machine);
if (futurenvmspermachine.get(machine) >= curr.get(machine, cid)) {
// First add all the ones it keeps
for (Iterator<VM> it = oldmachine._vms.iterator(); it.hasNext();) {
VM v = it.next();
if (clientIDs.indexOf(v._clientID) != client)
continue;
pm.addNewVMToMachine(v, oldmachine._machineID);
}
// Then give some more
int ngive = futurenvmspermachine.get(machine) - curr.get(machine, cid);
List<VM> thisclientpool = clientpool.get(client);
while (ngive-- > 0) {
assert thisclientpool.size() > 0;
VM v = thisclientpool.remove(0);
pm.addNewVMToMachine(v, oldmachine._machineID);
// System.out.println("Added VM "+v._globalID+" to machine "+oldmachine._machineID);
}
} else {
// You don't get to keep all of the old VMs for this client
int ntake = curr.get(machine, cid) - futurenvmspermachine.get(machine);
for (Iterator<VM> it = oldmachine._vms.iterator(); it.hasNext();) {
// IMPORTANT NOTE: we leverage the fact that the _vms are maintained as a **list**
// and not a **set**. So we assume that the iterator returns them in order!!
VM thevm = it.next();
if (clientIDs.indexOf(thevm._clientID) != client)
continue;
if (--ntake < 0) {
pm.addNewVMToMachine(thevm, oldmachine._machineID);
// System.out.println("Added VM "+thevm._globalID+" to machine "+oldmachine._machineID);
}
}
}
}
}
return pm;
}
}
package vagabond.reduction.cnfsat;
import vagabond.pieces.EpochHistory;
import java.util.*;
import vagabond.circuit.*;
import vagabond.pieces.*;
import vagabond.reduction.ReduceTo;
import vagabond.singleton.VagabondSettings;
public class ReduceToCNFSAT implements ReduceTo {
public String tp = "Epoch_Unknown";
......@@ -11,22 +15,487 @@ public class ReduceToCNFSAT implements ReduceTo {
tp = keyPrefix;
}
EpochHistory _eh = null; // Input epoch history; package private
public Circuit _circ = null; // Circuit with 3 of the 4 constraints. The optimization objective is added as part of
// the binary search in RunSolver...run().
int nc = -1;
int ns = -1; // # servers
List<Integer> nv = null; // #VMs per client
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ReduceToSAT {");
// TODO Auto-generated method stub
if (_circ != null) {
sb.append(_circ.toString());
}
sb.append("}");
return sb.toString();
}
public void setEh(EpochHistory e) {
_eh = e;
nc = _eh._latestPlacementMap._clients.size();
ns = _eh._latestPlacementMap._machines.size();
List<Integer> cids = new LinkedList<Integer>(_eh._latestPlacementMap._clients.keySet());
Collections.sort(cids);
nv = new LinkedList<Integer>();
for (int i = 0; i < cids.size(); i++) {
Client c = _eh._latestPlacementMap._clients.get(cids.get(i));
nv.add(c._vms.size());
}
}
public EpochHistory getEh() {
return _eh;
}
public void setNc(int c) {
nc = c;
}
public int getNc() {
return nc;
}
public void setNs(int s) {
ns = s;
}
public int getNs() {
return ns;
}
public void setNv(List<Integer> v) {
nv = v;
}
public List<Integer> getNv() {
return nv;
}
public void setCirc(Circuit c) {
_circ = c;
}
public Circuit getCirc() {
return _circ;
}
/**
* Add the constraint to the circuit, that for each client, its total # VMs should be exactly
* what we expect.
*
* @param c the circuit to which we add this constraint
* @param nc the number of clients
* @param nv list of integers; #VMs per client
* @param ns the number of servers (machines)
* @throws Exception bad things may happen
*/
public void constraintTotalNumberOfClientVMs(Circuit c, int nc, List<Integer> nv, int ns) throws Exception {
int nvBitsPrevClients = 0; // convenience variable -- total #VM bits of all prior clients
for (int i = 0; i < nc; i++) {
int nvbits = nbits(nv.get(i)); // convenience variable -- #VM bits for this client
// For each client, a Sum circuit
List<Integer> li = new LinkedList<Integer>();
for (int j = 0; j < ns; j++) {
li.add(nvbits);
}
Sum s = new Sum(li);
c.union(s);
for (int j = 0; j < nvbits * ns; j++) {
c.fuse(c.getInputs().get(nvBitsPrevClients * ns + j), s.getInputs().get(j));
}
// Then two LessThanEquals circuits
// The first one:
LessEquals le = new LessEquals(s.getOutputs().size(), nvbits);
c.union(le);
for (int j = 0; j < s.getOutputs().size(); j++) {
c.fuse(s.getOutputs().get(j), le.getInputs().get(j));
c.removeAsOutput(s.getOutputs().get(j));
}
IntegerAsCircuit iac = new IntegerAsCircuit(nv.get(i));
assert iac.getOutputs().size() == nvbits;
c.union(iac);
for (int j = 0; j < iac.getOutputs().size(); j++) {
c.fuse(iac.getOutputs().get(j), le.getInputs().get(j + s.getOutputs().size()));
c.removeAsOutput(iac.getOutputs().get(j));
}
/*
if(iac.getOutputs().size() < nvbits) {
// Hmm....should this ever happen? -- see assert above
for(int j = s.getOutputs().size() + iac.getOutputs().size(); j < s.getOutputs().size() + nvbits; j++) {
ZeroOne z = ZeroOne.getZero();
c.union(z);
c.fuse(z.getOutputs().get(0), le.getInputs().get(j));
c.removeAsOutput(z.getOutputs().get(0));
}
}
*/
// The second LessEquals circuit:
le = new LessEquals(nvbits, s.getOutputs().size());
c.union(le);
for (int j = 0; j < iac.getOutputs().size(); j++) {
c.fuse(iac.getOutputs().get(j), le.getInputs().get(j));
c.removeAsOutput(iac.getOutputs().get(j)); // Redundant
}
/*
if(iac.getOutputs().size() < nvbits) {
// Hmm....should this ever happen? -- see assert above
for(int j = iac.getOutputs().size(); j < nvbits; j++) {
ZeroOne z = ZeroOne.getZero();
c.union(z);
c.fuse(z.getOutputs().get(0), le.getInputs().get(j));
c.removeAsOutput(z.getOutputs().get(0));
}
}
*/
for (int j = 0; j < s.getOutputs().size(); j++) {
c.fuse(s.getOutputs().get(j), le.getInputs().get(j + nvbits));
}
// At this point, the only two outputs of c should be the outputs of the le circuits above
// Assume that those are AND-ed later
assert c.getOutputs().size() == 2 * (i + 1);
nvBitsPrevClients += nvbits;
}
}
/**
* Add the constraint to the circuit that the server's capacity should not be exceed.
*
* @param c the circuit to which we add this constraint
* @param nc the number of clients
* @param nv list of integers; #VMs per client
* @param ns number of servers (machines)
* @param scapa the capacity of each server
* @throws Exception bad things may happen
*/
public void constraintServerCapacity(Circuit c, int nc, List<Integer> nv, int ns, int scapa) throws Exception {
for (int i = 0; i < ns; i++) {
// For each server, a Sum circuit
List<Integer> li = new LinkedList<Integer>();
for (int j = 0; j < nc; j++) {
li.add(new Integer(nbits(nv.get(j))));
}
Sum s = new Sum(li);
c.union(s);
for (int j = 0; j < s.getOutputs().size(); j++) {
c.removeAsOutput(s.getOutputs().get(j));
}
// Now hook the input wires of c to the input wires of s
int nvbitsprevclients = 0;
for (int j = 0; j < nc; j++) {
int nvbits = nbits(nv.get(j));
// Wires for this client start at nvbitsprevclients*ns
// So, wires for this server for this client start at nvbitsprevclients*ns + i*nvbits
for (int k = 0; k < nvbits; k++) {
c.fuse(c.getInputs().get(k + nvbitsprevclients * ns + i * nvbits),
s.getInputs().get(nvbitsprevclients + k));
}
nvbitsprevclients += nvbits;
}
// Now an le circuit
Circuit le = new LessEquals(s.getOutputs().size(), nbits(scapa));
c.union(le);
for (int j = 0; j < s.getOutputs().size(); j++) {
c.fuse(s.getOutputs().get(j), le.getInputs().get(j));
}
IntegerAsCircuit iac = new IntegerAsCircuit(scapa);
assert iac.getOutputs().size() == nbits(scapa);
c.union(iac);
for (int j = 0; j < iac.getOutputs().size(); j++) {
c.removeAsOutput(iac.getOutputs().get(j));
}
for (int j = 0; j < nbits(scapa); j++) {
c.fuse(iac.getOutputs().get(j), le.getInputs().get(j + s.getOutputs().size()));
}
}
}
/**
* Constructs and return a circuit that is the absolute value of the input.
* The input is interpreted as representing an integer in two's complement. I.e., the
* leading bit is the sign bit. Note that this matches the output of the DiffTwo circuit.
*
* @param n the # input wires
* @return a circuit which outputs the absolute value. It's # output wires should be n-1
* @throws Exception bad things can happen
*/
public static Circuit absCirc(int n) throws Exception {
if (n < 2) { throw new Exception("n must be > 1"); }
Circuit c = new Circuit(); // result
for (int i = 0; i < n; i++) {
c.addNewInput();
}
int x = 1 << (n - 1);
IntegerAsCircuit xc = new IntegerAsCircuit(x);
c.union(xc);
DiffTwo d = new DiffTwo(xc.getOutputs().size(), n - 1);
c.union(d);
for (int i = 0; i < xc.getOutputs().size(); i++) {
c.fuse(xc.getOutputs().get(i), d.getInputs().get(i));
}
for (int i = 0; i < n - 1; i++) {
c.fuse(c.getInputs().get(i), d.getInputs().get(i + xc.getOutputs().size()));
}
// Need two Choose circuits
Choose ch1 = new Choose(n - 1);
c.union(ch1);
c.fuse(c.getInputs().get(n - 1), ch1.getInputs().get(0));
for (int i = 0; i < n - 1; i++) {
c.fuse(d.getOutputs().get(i), ch1.getInputs().get(i + 1));
}
Choose ch2 = new Choose(n - 1);
c.union(ch2);
Circuit.Gate g = c.addNewGate(Circuit.GateType.NOT);
Circuit.Wire twow[] = new Circuit.Wire[2];
twow[0] = c.getInputs().get(n - 1);
twow[1] = null;
Circuit.Wire outwire = c.addNewWire();
c.connect(g, twow, outwire);
c.fuse(outwire, ch2.getInputs().get(0));
for (int i = 0; i < n - 1; i++) {
c.fuse(c.getInputs().get(i), ch2.getInputs().get(i + 1));
}
// Remove all of c's outputs
while (!c.getOutputs().isEmpty()) {
c.removeAsOutput(c.getOutputs().get(0));
}
// Finally a sum circuit
List<Integer> li = new LinkedList<Integer>();
li.add(new Integer(n - 1));
li.add(new Integer(n - 1));
Sum s = new Sum(li);
c.union(s);
for (int i = 0; i < n - 1; i++) {
c.fuse(ch1.getOutputs().get(i), s.getInputs().get(i));
}
for (int i = 0; i < n - 1; i++) {
c.fuse(ch2.getOutputs().get(i), s.getInputs().get(i + n - 1));
}
/* We know that any wires above n-1 are 0 */
while (c.getOutputs().size() > n - 1) {
c.removeAsOutput(c.getOutputs().get(n - 1));
}
return c;
}
/**
* Add the constraint of migration budget to the circuit.
* @param r the circuit to which we add this constraint
* @param nc number of clients
* @param nv list of integers; #VMs per client
* @param ns number of servers (machines)
* @param currp current placement (# of vms per client on each machine)
* @param mig migration budget
* @throws Exception bad things may happen
*/
public void constraintMigrationBudget(Circuit r, int nc, List<Integer> nv, int ns,
SumOfClientVMsPerMachine currp, int mig) throws Exception {
List<Integer> il = new LinkedList<Integer>(); // This is the input list for the big sum circuit after the
// following nested loop
List<Circuit.Wire> wirestosum = new LinkedList<Circuit.Wire>();
for (int k = 0; k < ns; k++) {