private Value encodeValue(Object value) { if (value instanceof Actor) { Actor actor = (Actor) value; return new Term(REF, new Int(actor.getId())); } if (value instanceof Closure) { Closure fun = (Closure) value; return new Term(Key.getKey("Closure"), new Str(fun.getName()), new Int(fun.getArity())); } if (value instanceof Integer) return new Int((int) value); if (value instanceof String) return new Str((String) value); if (value instanceof Boolean) { Boolean b = (Boolean) value; if (b.booleanValue()) return new Term(Key.getKey("True")); else return new Term(Key.getKey("False")); } if (value instanceof actors.Term) { actors.Term t = (actors.Term) value; Term term = new Term(Key.getKey(t.getName().getString())); Value[] values = new Value[t.getValues().length]; for (int i = 0; i < values.length; i++) values[i] = encodeValue(t.getValues()[i]); term.setValues(values); return term; } return new Str("Encode value error: " + value); }
public History getSnapshot(int time) { // Create a snapshot of the receiver at the supplied time... History snapshot = new History(); snapshot.startOfTime = time; snapshot.endOfTime = time; snapshot.behaviourChangedEvents = new Vector<BehaviourChanged>(); snapshot.consumeEvents = new Vector<Consume>(); snapshot.newActorEvents = new Vector<NewActor>(); snapshot.sendEvents = new Vector<Send>(); snapshot.stateEvents = new Hashtable<Integer, Hashtable<Key, Stack<State>>>(); for (NewActor newActor : newActorEvents) { if (newActor.getTime() <= time) { BehaviourChanged b = null; for (BehaviourChanged b1 : behaviourChangedEvents) { if (b1.getId() == newActor.getId() && b1.getTime() <= time && b1.getTime() > newActor.getTime() && (b == null || b1.getTime() > b.getTime())) b = b1; } if (b == null) snapshot.newActorEvents.add( new NewActor(newActor.getId(), newActor.getBehaviour(), time)); else snapshot.newActorEvents.add(new NewActor(newActor.getId(), b.getNewBehaviour(), time)); } } for (Consume consume : consumeEvents) { if (consume.getTime() == time) snapshot.consumeEvents.add(consume); } for (Send send : sendEvents) { if (send.getTime() == time) snapshot.sendEvents.add(send); } for (int id : stateEvents.keySet()) { for (Key field : stateEvents.get(id).keySet()) { Stack<State> stack = stateEvents.get(id).get(field); if (!stack.isEmpty()) { State state = stack.peek(); if (state.getTime() <= time) snapshot.state(id, field.getString(), state.getValue(), time); } } } return snapshot; }
static { defRule( Key.getKey("state"), 4, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfyState( history, time, endOfTime, values[0], values[1], values[2], values[3], succ, fail)); defRule( Key.getKey("actor"), 3, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfyActor( history, 0, time, endOfTime, values[0], values[1], values[2], succ, fail)); defRule( Key.getKey("send"), 4, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfySend( history, 0, time, endOfTime, values[0], values[1], values[2], values[3], succ, fail)); }
public void state(int id, String name, Value value, int time) { if (!stateEvents.containsKey(id)) stateEvents.put(id, new Hashtable<Key, Stack<State>>()); Hashtable<Key, Stack<State>> table = stateEvents.get(id); Key key = Key.getKey(name); if (!table.containsKey(key)) table.put(key, new Stack<State>()); Stack<State> stack = table.get(key); if (stack.isEmpty()) stack.push(new State(id, key, value, time)); else { State state = stack.peek(); boolean changed = false; if (value == null && state.getValue() != null) changed = true; if (state.getValue() == null && value != null) changed = true; if (state.getValue() != null && value != null && !state.getValue().equals(value)) changed = true; if (changed) { stack.push(new State(id, key, value, time)); } } }
private Key[] toKeys(String[] exports) { Key[] keys = new Key[exports.length]; for (int i = 0; i < exports.length; i++) if (exports[i] != null) keys[i] = Key.getKey(exports[i]); return keys; }
public class History implements Serializable { public static final Hashtable<Key, RuleHandler> handlers = new Hashtable<Key, RuleHandler>(); public static final Hashtable<Key, Integer> arity = new Hashtable<Key, Integer>(); public static Key REF = Key.getKey("Ref"); static { defRule( Key.getKey("state"), 4, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfyState( history, time, endOfTime, values[0], values[1], values[2], values[3], succ, fail)); defRule( Key.getKey("actor"), 3, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfyActor( history, 0, time, endOfTime, values[0], values[1], values[2], succ, fail)); defRule( Key.getKey("send"), 4, (history, time, endOfTime, values, succ, fail) -> HistoryPredicates.satisfySend( history, 0, time, endOfTime, values[0], values[1], values[2], values[3], succ, fail)); } public static void defRule(Key name, int args, RuleHandler handler) { handlers.put(name, handler); arity.put(name, args); } public static History inflate(String path) { FileInputStream fin; try { fin = new FileInputStream(path); ObjectInputStream in = new ObjectInputStream(fin); Object o = in.readObject(); in.close(); if (o != null && o instanceof History) { History history = (History) o; int b = history.behaviourChangedEvents.size(); int c = history.consumeEvents.size(); int a = history.newActorEvents.size(); int s = history.sendEvents.size(); int u = history.stateEvents.size(); System.out.println( "[History " + path + " become=" + b + " consume=" + c + " actor=" + a + " send=" + s + " state=" + u + " time=[" + history.getStartOfTime() + "," + history.endOfTime + "]]"); return history; } else throw new Error("expecting a history " + o); } catch (IOException | ClassNotFoundException e) { throw new Error(e.toString()); } } int startOfTime; int endOfTime; Vector<BehaviourChanged> behaviourChangedEvents = new Vector<BehaviourChanged>(); Vector<Consume> consumeEvents = new Vector<Consume>(); Vector<NewActor> newActorEvents = new Vector<NewActor>(); Vector<Send> sendEvents = new Vector<Send>(); Hashtable<Integer, Hashtable<Key, Stack<State>>> stateEvents = new Hashtable<Integer, Hashtable<Key, Stack<State>>>(); public History() {} public void behaviourChanged( Actor actor, Behaviour oldBehaviour, Behaviour newBehaviour, int time) { behaviourChangedEvents.add( new BehaviourChanged(actor.getId(), oldBehaviour.getName(), newBehaviour.getName(), time)); } public void consume(Actor actor, Message message) { consumeEvents.add(new Consume(actor.getId(), encodeValue(message), Actor.getTime())); } private Value encodeValue(Object value) { if (value instanceof Actor) { Actor actor = (Actor) value; return new Term(REF, new Int(actor.getId())); } if (value instanceof Closure) { Closure fun = (Closure) value; return new Term(Key.getKey("Closure"), new Str(fun.getName()), new Int(fun.getArity())); } if (value instanceof Integer) return new Int((int) value); if (value instanceof String) return new Str((String) value); if (value instanceof Boolean) { Boolean b = (Boolean) value; if (b.booleanValue()) return new Term(Key.getKey("True")); else return new Term(Key.getKey("False")); } if (value instanceof actors.Term) { actors.Term t = (actors.Term) value; Term term = new Term(Key.getKey(t.getName().getString())); Value[] values = new Value[t.getValues().length]; for (int i = 0; i < values.length; i++) values[i] = encodeValue(t.getValues()[i]); term.setValues(values); return term; } return new Str("Encode value error: " + value); } public Vector<BehaviourChanged> getBehaviourChangedEvents() { return behaviourChangedEvents; } public Vector<Consume> getConsumeEvents() { return consumeEvents; } public int getEndOfTime() { return endOfTime; } public int getStartOfTime() { return startOfTime; } public void setStartOfTime(int startOfTime) { this.startOfTime = startOfTime; } public Vector<NewActor> getNewActorEvents() { return newActorEvents; } public Vector<Send> getSendEvents() { return sendEvents; } public boolean maybeFact(Key name, Value[] values) { return (handlers.containsKey(name) && arity.get(name) == values.length); } public void newActor(Actor actor, int time) { newActorEvents.add(new NewActor(actor.getId(), actor.getBehaviour().getName(), time)); } public void reset() { behaviourChangedEvents.clear(); consumeEvents.clear(); newActorEvents.clear(); sendEvents.clear(); stateEvents.clear(); } public void satisfy( int time, int endOfTime, Key name, Value[] values, Consumer<Fail> succ, Fail fail) { if (handlers.containsKey(name) && arity.get(name) == values.length) handlers.get(name).satisfy(this, time, endOfTime, values, succ, fail); else fail.fail(); } public void send(Actor source, Actor target, Message message, int time) { sendEvents.add(new Send(source.getId(), target.getId(), encodeValue(message.getValue()), time)); } public void serialize(String path) { File file = new File(path); OutputStream fout; try { fout = new FileOutputStream(file); ObjectOutputStream out = new ObjectOutputStream(fout); out.writeObject(this); out.close(); } catch (IOException e) { e.printStackTrace(); } } public void setBehaviourChangedEvents(Vector<BehaviourChanged> behaviourChangedEvents) { this.behaviourChangedEvents = behaviourChangedEvents; } public void setConsumeEvents(Vector<Consume> consumeEvents) { this.consumeEvents = consumeEvents; } public void setEndOfTime(int endOfTime) { this.endOfTime = endOfTime; } public void setNewActorEvents(Vector<NewActor> newActorEvents) { this.newActorEvents = newActorEvents; } public void setSendEvents(Vector<Send> sendEvents) { this.sendEvents = sendEvents; } public Hashtable<Integer, Hashtable<Key, Stack<State>>> getStateEvents() { return stateEvents; } public void state(Actor a, String name, Object o, int time) { // Record the state of the actor in the history. Note that there are // state values that cannot be encoded in a history. These are returned // as null from encodeValue... Value value = encodeValue(o); if (value != null) state(a.getId(), name, value, time); } public void state(int id, String name, Value value, int time) { if (!stateEvents.containsKey(id)) stateEvents.put(id, new Hashtable<Key, Stack<State>>()); Hashtable<Key, Stack<State>> table = stateEvents.get(id); Key key = Key.getKey(name); if (!table.containsKey(key)) table.put(key, new Stack<State>()); Stack<State> stack = table.get(key); if (stack.isEmpty()) stack.push(new State(id, key, value, time)); else { State state = stack.peek(); boolean changed = false; if (value == null && state.getValue() != null) changed = true; if (state.getValue() == null && value != null) changed = true; if (state.getValue() != null && value != null && !state.getValue().equals(value)) changed = true; if (changed) { stack.push(new State(id, key, value, time)); } } } public History getSnapshot(int time) { // Create a snapshot of the receiver at the supplied time... History snapshot = new History(); snapshot.startOfTime = time; snapshot.endOfTime = time; snapshot.behaviourChangedEvents = new Vector<BehaviourChanged>(); snapshot.consumeEvents = new Vector<Consume>(); snapshot.newActorEvents = new Vector<NewActor>(); snapshot.sendEvents = new Vector<Send>(); snapshot.stateEvents = new Hashtable<Integer, Hashtable<Key, Stack<State>>>(); for (NewActor newActor : newActorEvents) { if (newActor.getTime() <= time) { BehaviourChanged b = null; for (BehaviourChanged b1 : behaviourChangedEvents) { if (b1.getId() == newActor.getId() && b1.getTime() <= time && b1.getTime() > newActor.getTime() && (b == null || b1.getTime() > b.getTime())) b = b1; } if (b == null) snapshot.newActorEvents.add( new NewActor(newActor.getId(), newActor.getBehaviour(), time)); else snapshot.newActorEvents.add(new NewActor(newActor.getId(), b.getNewBehaviour(), time)); } } for (Consume consume : consumeEvents) { if (consume.getTime() == time) snapshot.consumeEvents.add(consume); } for (Send send : sendEvents) { if (send.getTime() == time) snapshot.sendEvents.add(send); } for (int id : stateEvents.keySet()) { for (Key field : stateEvents.get(id).keySet()) { Stack<State> stack = stateEvents.get(id).get(field); if (!stack.isEmpty()) { State state = stack.peek(); if (state.getTime() <= time) snapshot.state(id, field.getString(), state.getValue(), time); } } } return snapshot; } }