package esl.cuenet.generative.structs;
import java.io.IOException;
import java.io.PrintStream;
import java.util.*;
public class ContextNetwork {
protected List<IndexedSubeventTree> eventTrees = new ArrayList<IndexedSubeventTree>();
public void addAtomic(Instance inst) {
IndexedSubeventTree tree = new IndexedSubeventTree();
tree.root = inst;
HashSet<Instance> instances = new HashSet<Instance>();
instances.add(inst);
tree.instanceMap.put(inst.id, inst);
tree.typeIndex.put(inst.id.eventId, instances);
eventTrees.add(tree);
}
public void addSubeventEdge(Instance root, Instance parent, Instance subevent) {
//find root in eventTrees list
IndexedSubeventTree subtree = null;
for (IndexedSubeventTree i: eventTrees)
if (i.root == root) subtree = i; //instance comparison
if (subtree == null) throw new RuntimeException("No corresponding subtree for event " + root);
//find parent instance
if (subtree.typeIndex.containsKey(parent.id.eventId)) {
HashSet<Instance> instances = subtree.typeIndex.get(parent.id.eventId);
instances.add(parent);
Instance temp = subtree.instanceMap.get(parent.id);
//for (Instance i: instances) {
// if (i.equals(parent)) temp = i;
//}
if (temp == null) throw new RuntimeException("Could not find instance " + parent);
if ( !temp.immediateSubevents.contains(subevent.id) ) temp.immediateSubevents.add(subevent.id);
} else {
HashSet<Instance> instances = new HashSet<Instance>();
subtree.typeIndex.put(parent.id.eventId, instances);
instances.add(parent);
parent.immediateSubevents.add(subevent.id);
}
//all new subevents must be added to typeindex
HashSet<Instance> subeventInstances;
if (subtree.typeIndex.containsKey(subevent.id.eventId))
subeventInstances = subtree.typeIndex.get(subevent.id.eventId);
else {
subeventInstances = new HashSet<Instance>();
subtree.typeIndex.put(subevent.id.eventId, subeventInstances);
}
if (subeventInstances.contains(subevent)) {
// System.out.println("subevent already exists: " + current + " " + subevent);
}
else {
subeventInstances.add(subevent);
}
if ( !subtree.instanceMap.containsKey(parent.id) ) subtree.instanceMap.put(parent.id, parent);
if ( !subtree.instanceMap.containsKey(subevent.id) ) subtree.instanceMap.put(subevent.id, subevent);
}
public int count() {
return eventTrees.size();
}
public int nodeCount() {
int count = 0;
for (IndexedSubeventTree e: eventTrees)
count += e.nodeCount();
return count;
}
protected Instance lookup(IndexedSubeventTree root, InstanceId id) {
if ( !root.instanceMap.containsKey(id) )
throw new NoSuchElementException(root.toString() + " " + id.toString());
return root.instanceMap.get(id);
// HashSet<Instance> instances = root.typeIndex.get(id.eventId);
// if (instances == null) throw new NullPointerException(id.toString());
// for (Instance i: instances) {
// if (i.id.equals(id)) return i;
// }
// throw new NoSuchElementException(root.toString() + " " + id.toString());
}
public void merge (ContextNetwork other) {
if (this.eventTrees.size() == 0) {
this.eventTrees.addAll(other.eventTrees);
return;
}
for (IndexedSubeventTree thisSub: this.eventTrees)
for (IndexedSubeventTree otherTree: other.eventTrees)
descendAndMerge(thisSub, otherTree);
// for (IndexedSubeventTree otherTree: other.eventTrees) merge(otherTree);
}
private void descendAndMerge(IndexedSubeventTree subtree, IndexedSubeventTree other) {
if (!STHelper.lequals(subtree.root, other.root)) return;
if (STHelper.tequals(subtree.root, other.root)) {
mergeInformation(subtree.root, other.root);
for (InstanceId oSubeventId: other.root.immediateSubevents) {
Instance s = lookup(other, oSubeventId);
recursiveMerge(subtree, subtree.root, other, s);
}
}
else if (STHelper.contains(subtree.root, other.root)) {
recursiveMerge(subtree, subtree.root, other, other.root);
} else if (STHelper.contains(other.root, subtree.root)) {
Instance new_root = other.root.attributeClone();
Instance old_root = subtree.root;
subtree.root = new_root;
if ( !subtree.instanceMap.containsKey(new_root.id) ) subtree.instanceMap.put(new_root.id, new_root);
addSubeventEdge(subtree.root, subtree.root, old_root);
// System.out.println("new root " + other.root + " " + subtree.root);
for (InstanceId oSubeventId: other.root.immediateSubevents) {
Instance s = lookup(other, oSubeventId);
recursiveMerge(subtree, subtree.root, other, s);
}
}
}
//the parent is guranteed to contain instance. RM will decide to either
// (a) add as a subevent to parent
// (b) push instance down to one of its immediate subevents.
// (c) insert between parent and one of its immediate subevents.
private void recursiveMerge(IndexedSubeventTree subtree, Instance parent,
IndexedSubeventTree other, Instance instance) {
boolean addAsSubevent = true;
if ( !STHelper.lequals(parent, instance) ) return;
List<Instance> containedSubevents = new ArrayList<Instance>();
//check if any of the immediate subevents accepts instance
for (InstanceId subs: parent.immediateSubevents) {
Instance subevent = lookup(subtree, subs);
if (STHelper.tequals(subevent, instance)) {
addAsSubevent = false;
mergeInformation(subevent, instance);
for (InstanceId osubs: instance.immediateSubevents) {
Instance s = lookup(other, osubs);
recursiveMerge(subtree, subevent, other, s);
}
break;
}
else if (STHelper.contains(subevent, instance)) {
addAsSubevent = false;
recursiveMerge(subtree, subevent, other, instance);
break;
}
else if (STHelper.contains(instance, subevent)) {
addAsSubevent = false;
containedSubevents.add(subevent);
// Instance new_i = instance.attributeClone();
//
// parent.immediateSubevents.remove(subevent.id);
//
// addSubeventEdge(subtree.root, parent, new_i);
// addSubeventEdge(subtree.root, new_i, subevent);
//
// for (InstanceId osubs: instance.immediateSubevents) {
// Instance s = lookup(other, osubs);
// recursiveMerge(subtree, new_i, other, s);
// }
// break;
}
}
if (containedSubevents.size() > 0) {
Instance new_i = instance.attributeClone();
addSubeventEdge(subtree.root, parent, new_i);
for (Instance c_subevent: containedSubevents) {
parent.immediateSubevents.remove(c_subevent.id);
addSubeventEdge(subtree.root, new_i, c_subevent);
}
for (InstanceId osubs: instance.immediateSubevents) {
Instance s = lookup(other, osubs);
recursiveMerge(subtree, new_i, other, s);
}
}
if (addAsSubevent) {
Instance new_i = instance.attributeClone();
addSubeventEdge(subtree.root, parent, new_i);
for (InstanceId osubs: instance.immediateSubevents) {
Instance s = lookup(other, osubs);
recursiveMerge(subtree, new_i, other, s);
}
}
}
private void mergeInformation(Instance thisSubevent, Instance otherInstance) {
//System.out.println("[merge_info] " + thisSubevent + " " + otherInstance);
if ( !thisSubevent.id.equals(otherInstance.id) ) {
return;
}
}
public void printTree() {
printTree(false);
}
public void printTree(boolean printEntities) {
for (IndexedSubeventTree etree: eventTrees)
etree.print(System.out, printEntities);
}
public void printTree(int root_eventid, int root_instanceid) {
for (IndexedSubeventTree etree: eventTrees)
if (etree.root.id.eventId == root_eventid && etree.root.id.instanceId == root_instanceid)
etree.print(System.out, true);
}
public boolean compareNetwork(ContextNetwork other) {
for (IndexedSubeventTree tree: eventTrees) {
boolean flag = false;
for (IndexedSubeventTree otherTree: other.eventTrees) {
if (otherTree.compareTree(tree)) {
flag = true;
break;
}
}
if ( !flag )
return false;
}
return true;
}
public void pruneUp() {
for (IndexedSubeventTree e: eventTrees) pruneUp(e, e.root);
}
private Set<Entity> pruneUp(IndexedSubeventTree e, Instance parent) {
Set<Entity> entities = new HashSet<Entity>();
List<Entity> participants = parent.participants;
for (InstanceId sub: parent.immediateSubevents) {
Instance is = lookup(e, sub);
Set<Entity> entitiesSeenSoFar = pruneUp(e, is);
for (Entity es: entitiesSeenSoFar) {
if (participants.contains(es)) participants.remove(es);
}
entities.addAll(entitiesSeenSoFar);
}
entities.addAll(parent.participants);
return entities;
}
public class IndexedSubeventTree {
public Instance root;
public HashMap<Integer, HashSet<Instance>> typeIndex = new HashMap<Integer, HashSet<Instance>>();
public HashMap<InstanceId, Instance> instanceMap = new HashMap<InstanceId, Instance>();
@Override
public String toString() {
return root.toString();
}
public void print(PrintStream out, boolean printEntities) {
try {
out.write(("ROOT " + root + "\n").getBytes());
Stack<InstanceId> stack = new Stack<InstanceId>();
stack.add(root.id);
while (!stack.isEmpty()) {
InstanceId i = stack.pop();
Instance inst = lookup(this, i);
if ( printEntities ) {
inst.print(out);
}
for (InstanceId subids: inst.immediateSubevents) {
out.write(i.toString().getBytes());
out.write(" -> ".getBytes());
out.write(subids.toString().getBytes());
out.write("\n".getBytes());
stack.add(subids);
}
}
out.write(".\n".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public int nodeCount() {
int count = 0;
for (int i: this.typeIndex.keySet())
count += this.typeIndex.get(i).size();
return count;
}
public boolean compareTree(IndexedSubeventTree other) {
if ( !this.root.equals(other.root) ) {
return false;
}
if ( this.typeIndex.size() != other.typeIndex.size()) {
return false;
}
if ( !this.typeIndex.keySet().containsAll(other.typeIndex.keySet()) ) {
return false;
}
for (Integer thiskey: this.typeIndex.keySet()) {
HashSet<Instance> thisvalues = this.typeIndex.get(thiskey);
for (Instance thisinstance: thisvalues) {
if ( !other.instanceMap.containsKey(thisinstance.id) )
return false;
if ( !thisinstance.compareInstance(other.instanceMap.get(thisinstance.id)) )
return false;
Instance thatinstance = other.instanceMap.get(thisinstance.id);
if ( thisinstance.immediateSubevents.size() != thatinstance.immediateSubevents.size())
return false;
if ( !thisinstance.immediateSubevents.containsAll(thatinstance.immediateSubevents))
return false;
}
// HashSet<Instance> othervalues = other.typeIndex.get(thiskey);
// if ( !thisvalues.containsAll(othervalues) ) {
// System.out.println("thisvalues");
// return false;
// }
//
// for (Instance thisinstance: thisvalues) {
// boolean flag = true;
// for (Instance thatinstance: othervalues) {
// if (thatinstance.equals(thisinstance)) {
// flag = false;
// if ( !thatinstance.immediateSubevents.containsAll(thisinstance.immediateSubevents) ) {
// System.out.println("thatvalues");
// return false;
// }
//
// break;
// }
// }
// if ( flag ) {
// System.out.println("just flag");
// return false;
// }
// }
}
return true;
}
}
public static class Instance {
protected final InstanceId id;
public List<InstanceId> immediateSubevents;
protected List<Entity> participants;
protected long intervalStart, intervalEnd;
protected String location;
public Instance(int eventId, int instanceId) {
this.id = new InstanceId(eventId, instanceId);
this.immediateSubevents = new ArrayList<InstanceId>();
this.participants = new ArrayList<Entity>();
}
public void setLocation(String location) {
this.location = location;
}
public void setInterval(long start, long end) {
this.intervalStart = start;
this.intervalEnd = end;
}
// create a clone of this instance without the immediate subevents.
public Instance attributeClone() {
Instance instance = this;
Instance new_i = new Instance(instance.id.eventId, instance.id.instanceId);
new_i.setInterval(instance.intervalStart, instance.intervalEnd);
new_i.setLocation(instance.location);
return new_i;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Instance that = (Instance)o;
return this.id.equals(that.id);
}
@Override
public int hashCode() {
return id.hashCode();
}
@Override
public String toString() {
return id.toString();
}
public boolean compareInstance(Instance other) {
if (this.intervalStart != other.intervalStart)
return false;
if (this.intervalEnd != other.intervalEnd)
return false;
if ( !this.location.equals(other.location) )
return false;
return true;
}
public void print(PrintStream out) throws IOException {
out.write(this.toString().getBytes());
out.write(" : ".getBytes());
out.write(Arrays.toString(this.participants.toArray()).getBytes());
out.write("\n".getBytes());
}
}
public static class InstanceId {
public int eventId;
public int instanceId;
public InstanceId(int eventId, int instanceId) {
this.instanceId = instanceId;
this.eventId = eventId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceId that = (InstanceId) o;
return eventId == that.eventId && instanceId == that.instanceId;
}
@Override
public int hashCode() {
int result = eventId;
result = 31 * result + instanceId;
return result;
}
@Override
public String toString() {
return eventId + "_" + instanceId;
}
}
public static class Entity {
protected final String type; //person, organization, company or place
protected final String id; //arjun, uci, starbucks corp or "Mason Park"
public Entity(String type, String id) {
this.id = id;
this.type = type;
}
@Override
public int hashCode() {
int result = type != null ? type.hashCode() : 0;
result = 31 * result + (id != null ? id.hashCode() : 0);
return result;
}
@Override
public String toString() {
return type + "_" + id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Entity that = (Entity) o;
return id.equals(that.id) && type.equals(that.type);
}
}
}