/* Copyright 2014 MITRE Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mitre.provenance.simulate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import org.mitre.provenance.Metadata;
import org.mitre.provenance.client.AbstractProvenanceClient;
import org.mitre.provenance.client.LocalProvenanceClient;
import org.mitre.provenance.dag.LineageDAG;
import org.mitre.provenance.dag.TraversalSettings;
import org.mitre.provenance.db.neo4j.Neo4JPLUSObjectFactory;
import org.mitre.provenance.db.neo4j.Neo4JStorage;
import org.mitre.provenance.plusobject.PLUSActor;
import org.mitre.provenance.plusobject.PLUSEdge;
import org.mitre.provenance.plusobject.PLUSObject;
import org.mitre.provenance.plusobject.PLUSWorkflow;
import org.mitre.provenance.plusobject.ProvenanceCollection;
import org.mitre.provenance.surrogate.SurrogateGeneratingFunction;
import org.mitre.provenance.user.PrivilegeClass;
public class ArtificialDAG {
DAGComponent [] comps;
int componentCount;
float connectivity;
PLUSWorkflow wf;
public static final float RANDOMIZE_SGF_ASSIGNMENT = (float)0.15;
public static final int MAX_OUTPUTS_PER_COMPONENT = 5;
public static final int CONFIGURABLE_DEPTH = 3;
public static Random randGen = new Random();
public SurrogateGeneratingFunction SGF = null;
public AbstractProvenanceClient client = new LocalProvenanceClient();
public ArtificialDAG(PLUSWorkflow wf, int components, float connectivity, SurrogateGeneratingFunction SGF) throws Exception {
componentCount = components;
this.connectivity = connectivity;
this.wf = wf;
this.SGF = SGF;
generateComponents();
connectComponents();
} // End AritificialDAG
private void connectComponents() throws Exception {
ArrayList <PLUSEdge> edges = new ArrayList <PLUSEdge> ();
for(int x=0; x<componentCount; x++) {
for(int y=0; y<comps[x].outputs.length; y++) {
DAGComponent c = comps[x];
PLUSObject obj = c.outputs[y];
if(x < (componentCount-1) && randGen.nextDouble() < connectivity) {
int choice = -1;
while(choice <= 0 || (x+choice) >= componentCount)
choice = randGen.nextInt() % CONFIGURABLE_DEPTH;
DAGComponent other = comps[x+choice];
other.invocation.addInput(obj.getName(), obj.getId());
System.out.println("CONNECTIVITY: C" + x + "/" + y + " => C" + (x+choice));
PLUSEdge e = new PLUSEdge(obj, other.invocation, wf, "used by");
edges.add(e);
}
} // End for
}
// Guarantee full connectivity.
for(int x=1; x<componentCount; x++) {
if(comps[x].invocation.getInputCount() <= 0) {
int other = randGen.nextInt();
if(other < 0) other *= -1;
other = other % x;
DAGComponent connectMeTo = comps[other];
int rint = randGen.nextInt() % connectMeTo.outputs.length;
if(rint < 0) rint *= -1;
PLUSObject robj = connectMeTo.outputs[rint];
if(SGF != null) robj.useSurrogateComputation(SGF);
comps[x].invocation.addInput(robj.getName(), robj.getId());
System.out.println("FULL CONNECTIVITY: C" + other + "/" + rint + " => C" + x);
PLUSEdge e = new PLUSEdge(robj, comps[x].invocation,
wf, "used by");
edges.add(e);
} // End if
} // End for
System.out.println("Writing invocations and edges...");
for(int x=0; x<componentCount; x++) client.report(comps[x]);
//for(int x=0; x<edges.size(); x++) client.report(ProvenanceCollection.collect(edges.get(x)));
client.report(ProvenanceCollection.collect(edges.toArray(new PLUSEdge[]{})));
System.out.println("Done!");
} // End connectComponents
public PLUSObject getEntryPoint() {
return comps[0].invocation;
}
private void generateComponents() throws Exception {
comps = new DAGComponent[componentCount];
int aCount = (int)Math.sqrt((double)componentCount);
PLUSActor [] actors = new PLUSActor [aCount];
for(int x=0; x<aCount; x++) {
actors[x] = new PLUSActor("Group " + (x+1));
Neo4JStorage.store(actors[x]);
} // End for
for(int x=0; x<componentCount; x++) {
int oCount = randGen.nextInt() % MAX_OUTPUTS_PER_COMPONENT;
if(oCount < 0) oCount *= -1;
oCount++; // So it can't be 0.
int r = randGen.nextInt();
if(r < 0) r *= -1;
r = r % aCount;
PLUSActor owner = actors[r];
comps[x] = new DAGComponent(wf, "Component " + x,
owner,
oCount, SGF, RANDOMIZE_SGF_ASSIGNMENT);
} // End for
} // End generateComponents
/*********************************************************************************/
private static ArrayList <String> results = new ArrayList <String> ();
public static final void runLiftExperiment(int nodes, float connectivity, SurrogateGeneratingFunction SGF) throws Exception {
PLUSWorkflow wf = new PLUSWorkflow();
wf.setName("Artificial DAG: " + new Date());
wf.setWhenStart(new Date().toString());
wf.setWhenEnd(new Date().toString());
Neo4JStorage.store(wf);
ArtificialDAG ad = new ArtificialDAG(wf, nodes, connectivity, SGF);
Neo4JPLUSObjectFactory.newDAG(ad.getEntryPoint().getId(), org.mitre.provenance.user.User.DEFAULT_USER_GOD, TraversalSettings.UNLIMITED);
} // End runLiftExperiment
public static final ArtificialDAG runTest(int nodes, float connectivity, SurrogateGeneratingFunction SGF, boolean surrogateTimings) throws Exception {
PLUSWorkflow wf = new PLUSWorkflow();
wf.setName("Artificial DAG: " + new Date());
wf.setWhenStart(new Date().toString());
wf.setWhenEnd(new Date().toString());
wf.getPrivileges().addPrivilege(new PrivilegeClass(10));
Neo4JStorage.store(wf);
ArtificialDAG ad = new ArtificialDAG(wf, nodes, connectivity, SGF);
LineageDAG dag = null;
org.mitre.provenance.user.User u = null;
if(!surrogateTimings)
u = org.mitre.provenance.user.User.DEFAULT_USER_GOD;
else
u = org.mitre.provenance.user.User.PUBLIC;
dag = Neo4JPLUSObjectFactory.newDAG(ad.getEntryPoint().getId(), u, TraversalSettings.UNLIMITED);
Metadata md = dag.getMetadata();
results.add((surrogateTimings ? "Surrogates" : "Base") + "," +
dag.countNodes() + "," +
dag.countEdges() + "," +
nodes + "," + connectivity + "," + SGF + "," +
md.get("BuildDAG") + "," +
md.get("EdgeVoting") + "," +
md.get("NewEdgeComputing") + "," +
md.get("AddComputedEdges") + "," +
md.get("inferredEdges") + "," +
md.get("Votes-Infer") + "," +
md.get("Votes-Hide") + "," +
md.get("Votes-Show") + "," +
md.get("EstDBAccessTime") + "," +
md.get("PrunedDisconnectedNodes"));
System.out.println("Finished.");
return ad;
} // End runTest
public static void main(String [] args) throws Exception {
int components = 0;
float connectivity = 0;
SurrogateGeneratingFunction SGF = null;
try {
components = Integer.parseInt(args[0]);
connectivity = Float.parseFloat(args[1]);
SGF = null;
if(args.length > 2)
SGF = (SurrogateGeneratingFunction)Class.forName(args[2]).newInstance();
} catch(Exception e) {
//PLUSUtils.log.error("Exception: " + e);
//e.printStackTrace();
//PLUSUtils.log.error("Usage: foo components connectivity SGF");
//System.exit(0);
components = 50;
connectivity = (float)0.50;
}
int runXTimes = 1;
try {
for(int x=0; x<runXTimes; x++) {
boolean val = false;
if(SGF != null) val = true;
runTest(components, connectivity, SGF, val);
}
} catch(Exception e) {
System.out.println("Exception: " + e);
e.printStackTrace();
}
System.out.println("Type,Nodes,Edges,Components,Connectivity,SGF,BuildDAG," +
"EdgeVoting,NewEdgeComputing,AddComputedEdges,inferredEdges,Votes-Infer," +
"Votes-Hide,Votes-Show,EstDBAccessTime,PrunedDisconnectedNodes");
for(int x=0; x<results.size(); x++) {
System.out.println(results.get(x));
}
System.exit(0);
} // End main
} // End ArtificialDAG