org.sdmlib.models.pattern.ReachabilityGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SDMLib Show documentation
Show all versions of SDMLib Show documentation
SDMLib is a light weight modeling library. SDMLib intentionally comes without any tool or editor.
/*
Copyright (c) 2013 zuendorf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
and associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sdmlib.models.pattern;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.TreeMap;
import org.sdmlib.doc.GraphFactory;
import org.sdmlib.doc.interfaze.Adapter.GuiAdapter;
import org.sdmlib.models.SDMLibIdMap;
import org.sdmlib.models.pattern.util.PatternSet;
import org.sdmlib.models.pattern.util.ReachableStateSet;
import org.sdmlib.serialization.PropertyChangeInterface;
import de.uniks.networkparser.Filter;
import de.uniks.networkparser.IdMap;
import de.uniks.networkparser.interfaces.SendableEntity;
import de.uniks.networkparser.interfaces.UpdateListener;
import de.uniks.networkparser.json.JsonArray;
import de.uniks.networkparser.json.JsonObject;
import de.uniks.networkparser.json.JsonTokener;
/**
*
* @see
* PatternModelCodeGen.java
*/
public class ReachabilityGraph implements PropertyChangeInterface, SendableEntity
{
// ==========================================================================
private final class OmitRootCondition implements UpdateListener
{
private Object root;
public OmitRootCondition(Object root)
{
this.root = root;
}
@Override
public boolean update(Object event)
{
PropertyChangeEvent evt = (PropertyChangeEvent) event;
return evt.getNewValue() != root;
}
}
public String dumpDiagram(String name)
{
OmitRootCondition conditionMap = new OmitRootCondition(this);
Filter filter = new Filter().withFull(true).withPropertyRegard(conditionMap);
JsonArray jsonArray = masterMap.toJsonArray(this, filter);
String imgLink = getAdapter().toImg(name, jsonArray);
// also add images for all graph roots
for (Object graphRoot : getStates().getGraphRoot())
{
JsonArray graphRootArray = masterMap.toJsonArray(graphRoot);
String rootId = masterMap.getId(graphRoot);
String imgName = name + "/" + rootId;
String subLink = getAdapter().toImg(imgName, graphRootArray);
}
return imgLink;
}
private Metric metric = null;
public void setMetric(Metric metric)
{
this.metric = metric;
}
private GuiAdapter adapter;
public GuiAdapter getAdapter()
{
if (adapter == null)
{
adapter = GraphFactory.getAdapter();
}
return adapter;
}
// ==========================================================================
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
@Override
public PropertyChangeSupport getPropertyChangeSupport()
{
return listeners;
}
public boolean addPropertyChangeListener(PropertyChangeListener listener)
{
getPropertyChangeSupport().addPropertyChangeListener(listener);
return true;
}
public boolean addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
{
getPropertyChangeSupport().addPropertyChangeListener(propertyName, listener);
return true;
}
public boolean removePropertyChangeListener(PropertyChangeListener listener)
{
getPropertyChangeSupport().removePropertyChangeListener(listener);
return true;
}
// ==========================================================================
public void removeYou()
{
removeAllFromStates();
removeAllFromTodo();
removeAllFromRules();
withoutStates(this.getStates().toArray(new ReachableState[this.getStates().size()]));
withoutTodo(this.getTodo().toArray(new ReachableState[this.getTodo().size()]));
withoutRules(this.getRules().toArray(new Pattern[this.getRules().size()]));
getPropertyChangeSupport().firePropertyChange("REMOVE_YOU", this, null);
}
/********************************************************************
*
* one many
* ReachabilityGraph ----------------------------------- ReachableState
* parent states
*
*/
public static final String PROPERTY_STATES = "states";
private TreeMap stateMap = new TreeMap();
public ReachabilityGraph withStateMap(String certificate, ReachableState newState)
{
Object oldEntry = stateMap.get(certificate);
if (oldEntry == null)
{
stateMap.put(certificate, newState);
}
else if (oldEntry instanceof ReachableState && oldEntry != newState)
{
ReachableStateSet newStateSet = new ReachableStateSet()
.with((ReachableState) oldEntry).with(newState);
stateMap.put(certificate, newStateSet);
}
else
{
ReachableStateSet oldStateSet = (ReachableStateSet) oldEntry;
oldStateSet.with(newState);
}
return this;
}
private static ReachableStateSet emptyStatesSet = new ReachableStateSet();
private ReachableStateSet oneElemSet = new ReachableStateSet();
public ReachableStateSet getStateMap(String certificate)
{
Object oldEntry = stateMap.get(certificate);
if (oldEntry == null)
{
return emptyStatesSet;
}
else if (oldEntry instanceof ReachableState)
{
oneElemSet.clear();
oneElemSet.add((ReachableState) oldEntry);
return oneElemSet;
}
else
{
return (ReachableStateSet) oldEntry;
}
}
private ReachableStateSet states = null;
public ReachableStateSet getStates()
{
if (this.states == null)
{
return ReachableState.EMPTY_SET;
}
return this.states;
}
public boolean addToStates(ReachableState value)
{
boolean changed = false;
if (value != null)
{
if (this.states == null)
{
this.states = new ReachableStateSet();
}
changed = this.states.add(value);
if (changed)
{
value.withParent(this);
getPropertyChangeSupport().firePropertyChange(PROPERTY_STATES, null, value);
}
}
return changed;
}
public boolean removeFromStates(ReachableState value)
{
boolean changed = false;
if ((this.states != null) && (value != null))
{
changed = this.states.remove(value);
if (changed)
{
value.setParent(null);
getPropertyChangeSupport().firePropertyChange(PROPERTY_STATES, value, null);
}
}
return changed;
}
public ReachabilityGraph withStates(ReachableState value)
{
addToStates(value);
return this;
}
public ReachabilityGraph withoutStates(ReachableState value)
{
removeFromStates(value);
return this;
}
public void removeAllFromStates()
{
LinkedHashSet tmpSet = new LinkedHashSet(this.getStates());
for (ReachableState value : tmpSet)
{
this.removeFromStates(value);
}
}
public ReachableState createStates()
{
ReachableState value = new ReachableState();
withStates(value);
return value;
}
/********************************************************************
*
* one many
* ReachabilityGraph ----------------------------------- ReachableState
* master todo
*
*/
public static final String PROPERTY_TODO = "todo";
private ArrayList todo = null;
public ArrayList getTodo()
{
if (this.todo == null)
{
this.todo = new ArrayList();
}
return this.todo;
}
public boolean addToTodo(ReachableState value)
{
boolean changed = false;
if (value != null)
{
if (this.todo == null)
{
this.todo = new ArrayList();
}
changed = this.todo.add(value);
getPropertyChangeSupport().firePropertyChange(PROPERTY_TODO, null, value);
}
return changed;
}
public boolean removeFromTodo(ReachableState value)
{
boolean changed = false;
if ((this.todo != null) && (value != null))
{
changed = this.todo.remove(value);
getPropertyChangeSupport().firePropertyChange(PROPERTY_TODO, value, null);
}
return changed;
}
public ReachabilityGraph withTodo(ReachableState value)
{
addToTodo(value);
return this;
}
public ReachabilityGraph withoutTodo(ReachableState value)
{
removeFromTodo(value);
return this;
}
public void removeAllFromTodo()
{
LinkedHashSet tmpSet = new LinkedHashSet(this.getTodo());
for (ReachableState value : tmpSet)
{
this.removeFromTodo(value);
}
}
public ReachableState createTodo()
{
ReachableState value = new ReachableState();
withTodo(value);
return value;
}
/********************************************************************
*
* one many
* ReachabilityGraph ----------------------------------- Pattern
* rgraph rules
*
*/
public static final String PROPERTY_RULES = "rules";
private PatternSet rules = null;
public PatternSet getRules()
{
if (this.rules == null)
{
return Pattern.EMPTY_SET;
}
return this.rules;
}
public boolean addToRules(Pattern value)
{
boolean changed = false;
if (value != null)
{
if (this.rules == null)
{
this.rules = new PatternSet();
}
changed = this.rules.add(value);
if (changed)
{
value.withRgraph(this);
getPropertyChangeSupport().firePropertyChange(PROPERTY_RULES, null, value);
}
}
return changed;
}
public boolean removeFromRules(Pattern value)
{
boolean changed = false;
if ((this.rules != null) && (value != null))
{
changed = this.rules.remove(value);
if (changed)
{
value.setRgraph(null);
getPropertyChangeSupport().firePropertyChange(PROPERTY_RULES, value, null);
}
}
return changed;
}
public ReachabilityGraph withRules(Pattern value)
{
addToRules(value);
return this;
}
public ReachabilityGraph withoutRules(Pattern value)
{
removeFromRules(value);
return this;
}
public void removeAllFromRules()
{
LinkedHashSet tmpSet = new LinkedHashSet(this.getRules());
for (Pattern value : tmpSet)
{
this.removeFromRules(value);
}
}
public Pattern createRules()
{
Pattern value = new Pattern();
withRules(value);
return value;
}
public long explore()
{
return explore(Long.MAX_VALUE, Searchmode.DEFAULT);
}
public enum Searchmode
{
DEFAULT, DEPTH, IGNORE
}
public long explore(long maxNoOfNewStates, Searchmode mode)
{
long currentStateNum = 1;
long bestMetricYet = Long.MIN_VALUE;
int ignoredStates = 0;
IdMap newJsonIdMap = (IdMap) new SDMLibIdMap("s");
// inital states get certificates
for (ReachableState s : this.getStates())
{
String newCertificate = s.computeCertificate(newJsonIdMap);
this.withStateMap(newCertificate, s);
if (metric != null)
{
double smetric = metric.compute(s.getGraphRoot());
s.setMetricValue(smetric);
bestMetricYet = (long) Math.max(bestMetricYet, smetric);
}
}
// take a todo state and apply all rules at all places until
// maxNoOfNewStates
// is reached
doToDo: while (!getTodo().isEmpty() && this.getStates().size() + ignoredStates <= maxNoOfNewStates)
{
if (metric != null)
{
// sort todo list
Collections.sort(getTodo(), (s1, s2) -> Double.compare(s2.getMetricValue(), s1.getMetricValue()));
}
ReachableState first = getTodo().get(0);
if (first.getNumber() == 0)
{
first.withNumber((int) currentStateNum);
}
currentStateNum++;
long alreadyKnownMatches = first.noOfRuleMatchesDone;
first.noOfRuleMatchesDone = 0;
this.withoutTodo(first);
for (Pattern rule : getRules())
{
PatternObject firstPO = (PatternObject) rule.getElements().first();
rule.resetSearch();
((PatternObject) firstPO.withModifier(Pattern.BOUND)).setCurrentMatch(first.getGraphRoot());
while (rule.findMatch())
{
// count matches found on this graph
first.noOfRuleMatchesDone++;
if (first.noOfRuleMatchesDone <= alreadyKnownMatches)
{
// has been considered in previous expansions of this state.
// Those previous expansions have been aborted in order to
// expand more promising state.
// Now it is reconsidered. But we do not need to go through
// the already done expansions.
continue;
}
// for each match get the new reachable state and add it to the
// reachability graph
Object newGraphRoot = firstPO.getCurrentMatch();
ReachableState newReachableState = new ReachableState().withGraphRoot(newGraphRoot);
// is the new graph already known?
newJsonIdMap = (IdMap) new SDMLibIdMap("r").with(rule.getIdMap());
newJsonIdMap.withSessionId("s");
String newCertificate = newReachableState.computeCertificate(newJsonIdMap);
ReachableStateSet candidateStates = this.getStateMap(newCertificate);
LinkedHashMap match = null;
for (ReachableState oldState : candidateStates)
{
match = match(oldState, newReachableState);
if (match != null)
{
// newReachableState is isomorphic to oldState. Just add a
// link from first to oldState
first.createRuleapplications().withDescription("" + rule.getName()).withTgt(oldState);
break;
}
}
if (match == null)
{
// no isomorphic old state, add new state
if (metric != null)
{
double newMetricValue = metric.compute(newReachableState.getGraphRoot());
newReachableState.setMetricValue(newMetricValue);
if (mode == Searchmode.IGNORE && newMetricValue < bestMetricYet)
{
if (++ignoredStates % 500 == 0)
{
System.out.print("*");
}
// ignore rules with a bad metric
// continue;
}
else
{
bestMetricYet = (long) Math.max(bestMetricYet, newMetricValue);
}
}
this.withStates(newReachableState).withTodo(newReachableState).withStateMap(newCertificate,
newReachableState);
first.createRuleapplications().withDescription("" + rule.getName()).withTgt(newReachableState);
int size = this.getStates().size();
if (size % 50 == 0)
{
System.out.print(".");
}
if (mode == Searchmode.DEPTH && newReachableState.getMetricValue() > first.getMetricValue())
{
// new state is more interesting than current state,
// abort current state and continue with new state
this.withTodo(first);
continue doToDo;
}
}
}
}
}
System.out.println(" Ignored: " + ignoredStates + " states due to applied metric.");
return currentStateNum;
}
public LinkedHashMap match(ReachableState s1, ReachableState s2)
{
IdMap map1 = (IdMap) new IdMap().with(masterMap);
IdMap map2 = (IdMap) new IdMap().with(masterMap);
map1.withSessionId("s");
map2.withSessionId("s");
LinkedHashMap fwdmapping = new LinkedHashMap();
LinkedHashMap bwdmapping = new LinkedHashMap();
String key1 = map1.getId(s1.getGraphRoot());
String key2 = map2.getId(s2.getGraphRoot());
fwdmapping.put(key1, key2);
bwdmapping.put(key2, key1);
JsonArray ja1 = map1.toJsonArray(s1.getGraphRoot());
JsonArray ja2 = map2.toJsonArray(s2.getGraphRoot());
LinkedHashMap joMap1 = null;
LinkedHashMap joMap2 = null;
joMap1 = new LinkedHashMap();
for (Object object : ja1)
{
JsonObject jo = (JsonObject) object;
String key = jo.getString(IdMap.ID);
joMap1.put(key, jo);
}
joMap2 = new LinkedHashMap();
for (Object object : ja2)
{
JsonObject jo = (JsonObject) object;
String key = jo.getString(IdMap.ID);
joMap2.put(key, jo);
}
boolean match = match(s1, ja1, joMap1, s2, ja2, joMap2, key1, fwdmapping, bwdmapping);
return match ? fwdmapping : null;
}
public boolean match(ReachableState s1, JsonArray ja1, LinkedHashMap joMap1,
ReachableState s2, JsonArray ja2, LinkedHashMap joMap2,
String cn1, LinkedHashMap fwdmapping, LinkedHashMap bwdmapping)
{
String cn2 = fwdmapping.get(cn1);
// a mapping for currentNode has just been added. Validate it and compute
// mappings for neighbors
JsonObject currentJo1 = joMap1.get(cn1);
JsonObject currentJo2 = joMap2.get(cn2);
// certificates are equal, only check refs
// go through properties
JsonObject currentProps1 = currentJo1.getJsonObject(JsonTokener.PROPS);
JsonObject currentProps2 = currentJo2.getJsonObject(JsonTokener.PROPS);
for (Iterator iter = currentProps1.keyIterator(); iter.hasNext();)
{
String key = iter.next();
Object value = currentProps1.get(key);
if (value instanceof JsonObject)
{
JsonObject ref = (JsonObject) value;
String tgt1 = ref.getString(IdMap.ID);
String tgt2 = currentProps2.getJsonObject(key).getString(IdMap.ID);
String mappingOfTgt1 = fwdmapping.get(tgt1);
if (mappingOfTgt1 != null)
{
// already mapped. consistent?
if (!tgt2.equals(mappingOfTgt1))
{
// inconsistent mapping
return false;
}
}
else
{
// not yet mapped, thus add mapping and check it.
fwdmapping.put(tgt1, tgt2);
bwdmapping.put(tgt2, tgt1);
boolean match = match(s1, ja1, joMap1, s2, ja2, joMap2, tgt1, fwdmapping, bwdmapping);
if (!match)
{
// did not work
fwdmapping.remove(tgt1);
bwdmapping.remove(tgt2);
}
}
}
else if (value instanceof JsonArray)
{
// many refs loop through them, match each
obj1RefLoop: for (Object object : (JsonArray) value)
{
JsonObject ref = (JsonObject) object;
String tgt1 = ref.getString(IdMap.ID);
// might already have been matched
String tgt1Map = fwdmapping.get(tgt1);
if (tgt1Map != null)
{
// consistent?
for (Object o : currentProps2.getJsonArray(key))
{
ref = (JsonObject) o;
String tgt2 = ref.getString(IdMap.ID);
if (tgt2.equals(tgt1Map))
{
continue obj1RefLoop; // <==================== this ref
// has a match, handle next ref in
// outer loop
}
}
// inconsistent
return false; // <========================== did not work out
}
// loop through the refs of the other object
for (Object o : currentProps2.getJsonArray(key))
{
ref = (JsonObject) o;
String tgt2 = ref.getString(IdMap.ID);
// already used for other match?
if (bwdmapping.get(tgt2) != null)
{
continue; // <=========================== this one is not a
// match candidate, try another
}
// does the certificate match?
String cert1 = s1.getNode2certificates().get(tgt1);
String cert2 = s2.getNode2certificates().get(tgt2);
if (cert1.equals(cert2))
{
// might be a candidate, match it
fwdmapping.put(tgt1, tgt2);
bwdmapping.put(tgt2, tgt1);
boolean match = match(s1, ja1, joMap1, s2, ja2, joMap2, tgt1, fwdmapping, bwdmapping);
if (!match)
{
// did not work
fwdmapping.remove(tgt1);
bwdmapping.remove(tgt2);
}
else
{
continue obj1RefLoop; // <==================== this ref
// has a match, handle next ref in
// outer loop
}
}
}
// did not find a match for current ref
return false;
}
}
}
return true;
}
private IdMap masterMap = null;
public IdMap getMasterMap()
{
return masterMap;
}
public void setMasterMap(IdMap newMasterMap)
{
masterMap = newMasterMap;
}
public ReachabilityGraph withMasterMap(IdMap map)
{
setMasterMap(map);
return this;
}
public ReachabilityGraph withStates(ReachableState... value)
{
if (value == null)
{
return this;
}
for (ReachableState item : value)
{
addToStates(item);
}
return this;
}
public ReachabilityGraph withoutStates(ReachableState... value)
{
for (ReachableState item : value)
{
removeFromStates(item);
}
return this;
}
public ReachabilityGraph withTodo(ReachableState... value)
{
if (value == null)
{
return this;
}
for (ReachableState item : value)
{
addToTodo(item);
}
return this;
}
public ReachabilityGraph withoutTodo(ReachableState... value)
{
for (ReachableState item : value)
{
removeFromTodo(item);
}
return this;
}
public ReachabilityGraph withRules(Pattern... value)
{
if (value == null)
{
return this;
}
for (Pattern item : value)
{
addToRules(item);
}
return this;
}
public ReachabilityGraph withoutRules(Pattern... value)
{
for (Pattern item : value)
{
removeFromRules(item);
}
return this;
}
public Pattern createRulesNegativeApplicationCondition()
{
Pattern value = new NegativeApplicationCondition();
withRules(value);
return value;
}
public Pattern createRulesOptionalSubPattern()
{
Pattern value = new OptionalSubPattern();
withRules(value);
return value;
}
public NegativeApplicationCondition createNegativeApplicationCondition()
{
NegativeApplicationCondition value = new NegativeApplicationCondition();
withRules(value);
return value;
}
public OptionalSubPattern createOptionalSubPattern()
{
OptionalSubPattern value = new OptionalSubPattern();
withRules(value);
return value;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy