The following examples will show how to use the library for rewriting port graphs:

Some examples:

A snow flake example consists in replacing an edge by a multi-edge as follow:

snowFlakeTransfo.png

The translation in port graph module is has follow:

snowFlakeTransfoPG.png

The pattern graph to search in the large graph contains :

  • 2 nodes a,b
  • 2 ports qa, qb with tag {+} port qa port and with tag {-} for qb port
  • 3 edges [a,qa] [qa,qb] [qb,b]

The replacment transformer graph contains:

  • 3 nodes i,j,k
  • 6 ports pi,qi,qj,qj,pk,qk with respectivly tags +,-,+,-,+,-,+,-
  • 8 edges [pi,i],[i,qi],[qi,pj],[pj,j],[j,qj],[qj,pk],[pk,k],[k,qk]

The coordinates of the new nodes i,j,k has defined has follow:

  • I=(2/3)A+(1/3)B
  • K=(1/3)A+(2/3)B
  • J=(1/2)(A+B)+(sqrt(3)/6)(-Arot+Brot) where Arot=(-Y,X,Z) when A=(x,y,z)

The rules are as follow:

  • erase edge [qa,qb] from pattern graph
  • add edges [qa,pi] [qb,qk] between pattern & transformer graph

The large graph is a triangle which contains:

  • 3 nodes A(0,sqrt(2),0),B(1,0,0),C(-1,0,0)
  • 6 associated ports qA,qB,rb,rc,pc,pa with tags +,-,+,-,+,-

The results obtains after 8 iterations is given as follow:

snowFlake-8.png

To simulate this example, 2 classes have to been created:

The GPM_2DSnowGraph::createPatternsFunctions which create a patterns functions has to be sepcialized: it creates pattern graph, transformer graph, GPM_Snow2DFunction. The code is like this:

tBoolean GPM_2DSnowGraph::createPatternFunctions(SV::GPM_PatternFunction& patternFunctions) const {
tVertexIID pA,pB;
SP::GPM_PortGraph patternGraph=createPatternGraph(pA,pB);
tVertexIID tA,tB;
SP::GPM_PortGraph transformerGraph=createTransformerGraph(tA,tB);
// create the mapping
SP::GPM_PatternFunction patternF=GPM_Snow2DFunction::New();
patternF->setPatternGraph(patternGraph);
patternF->setTransformerGraph(transformerGraph);
patternF->addPEdgeToRemove(pA,pB);
patternF->addPTEdgeToAdd(pA,tA);
patternF->addPTEdgeToAdd(pB,tB);
patternFunctions.clear();
patternFunctions.add(patternF);
return true;
}

The method GPM_PatternFunction::addPEdgeToRemove adds a marker to remove the mapped pattern edge in the large graph

The method GPM_PatternFunction::addPTEdgeToAdd adds an edge in the large graph between mapped pattern graph and the copied transformer graph in the large graph

The method GPM_2DSnowGraph::createTransformerGraph (similarly GPM_2DSnowGraph::createPatternGraph) creates a graph

SP::GPM_PortGraph GPM_2DSnowGraph::createTransformerGraph(tVertexIID& tA,tVertexIID& tB) const {
// create the transformed pattern
SP::GPM_PortGraph patternTransformed=GPM_PortGraph::New();
int index=-1;
iid=patternTransformed->addPort("-",++index);tA=iid;
iid=patternTransformed->addVertex(++index);
iid=patternTransformed->addPort("+",++index);
iid=patternTransformed->addPort("-",++index);
iid=patternTransformed->addVertex(++index);
iid=patternTransformed->addPort("+",++index);
iid=patternTransformed->addPort("-",++index);
iid=patternTransformed->addVertex(++index);
iid=patternTransformed->addPort("+",++index);tB=iid;
index=0;
patternTransformed->addEdgeFromIds(0,1);
patternTransformed->addEdgeFromIds(1,2);
patternTransformed->addEdgeFromIds(2,3);
patternTransformed->addEdgeFromIds(3,4);
patternTransformed->addEdgeFromIds(4,5);
patternTransformed->addEdgeFromIds(5,6);
patternTransformed->addEdgeFromIds(6,7);
patternTransformed->addEdgeFromIds(7,8);
return patternTransformed;
}

To define the new position of nodes, the methode GPM_PatternFunction::updateStates has to be specialized. it defined the new coordinates of the copied transformer graph

const vector<tVertexIID>& mappingP2L,
const map<tVertexIID,tVertexIID>& mappingT2L) {
tBoolean succeeds=true;
SP::GPM_Node node;
// get the pattern graph
const GPM_Graph& patternGraph=getPatternGraph();
// get the tranformer graph
const GPM_Graph& transformerGraph=getTransformerGraph();
// get the mapping transformer graph -> copied tranformer graph in large graph
map<tVertexIID,tVertexIID>::const_iterator mappingT2LIter;
// get the coordinate of the first node of pattern graph
node=dynamic_sp_cast<GPM_Node>(largeGraph.getVertex(mappingP2L[patternGraph.getVertexIID(0)])*);
if (node.get()==null) return false;
const tReal *X=node->getCoordinates();
// Xrot is the rotation of axe Z and angle PI/2 of X
tReal Xrot[]={-X[1],X[0],X[2]};
// get the coordinate of the last node of pattern graph
node=dynamic_sp_cast<GPM_Node>(largeGraph.getVertex(mappingP2L[patternGraph.getVertexIID(3)])*);
if (node.get()==null) return false;
const tReal *Y=node->getCoordinates();
// Yrot is the rotation of axe Z and angle PI/2 of Y
tReal Yrot[]={-Y[1],Y[0],Y[2]};
int k=0;
tReal coord[3];
//cout << "X("<<X[0]<<","<<X[1]<<","<<X[2]<<") Y("<<Y[0]<<","<<Y[1]<<","<<Y[2]<<")\n";
// set the coordinate of the first node of transformed graph
iid=transformerGraph.getVertexIID(1);
for (k=0;k<3;k++) coord[k]=(2./3.)*X[k]+(1./3.)*Y[k];
mappingT2LIter=mappingT2L.find(iid);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_sp_cast<GPM_Node>( largeGraph.getVertex(mappingT2LIter->second));
if (node.get()!=null) node->setCoordinates(coord);
}
//cout << "\t A("<<coord[0]<<","<<coord[1]<<","<<coord[2]<<")\n";
// set the coordinate of the 2nd node of transformed graph
iid=transformerGraph.getVertexIID(4);
for (k=0;k<3;k++) {
coord[k]=0.5*(X[k]+Y[k]);
coord[k]+=(sqrt(3.)/6.)*(-Xrot[k]+Yrot[k]);
}
mappingT2LIter=mappingT2L.find(iid);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_sp_cast<GPM_Node>( largeGraph.getVertex(mappingT2LIter->second));
if (node.get()!=null) node->setCoordinates(coord);
}
//cout << "\t B("<<coord[0]<<","<<coord[1]<<","<<coord[2]<<")\n";
// set the coordinate of the 3th node of transformed graph
iid=transformerGraph.getVertexIID(7);
for (k=0;k<3;k++) coord[k]=(1./3.)*X[k]+(2./3.)*Y[k];
mappingT2LIter=mappingT2L.find(iid);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_sp_cast<GPM_Node>( largeGraph.getVertex(mappingT2LIter->second));
if (node.get()!=null) node->setCoordinates(coord);
}
//cout << "\t C("<<coord[0]<<","<<coord[1]<<","<<coord[2]<<")\n";
return succeeds;
}

Note that the nodes & ports are vertices so a special care needs to take the nodes at the right index.