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

Some examples:

A snow flake 3D example consists in replacing a triangle by a tetrahedron thanks to 2 rules described as folow (the state of ports is undefined by default. It may be either + or -):

snowFlake3DTransfo1.png
snowFlake3DTransfo2.png

The coordinates of the new nodes U,V,W,X are described as follow:

  • X=(1/3).(A+B+C)+eps.(sqrt(2)/6).AB^AC where eps=1 if state of node A is 1 or eps=-1 if the state of node A is -1
  • U=(1/2)(A+B)
  • V=(1/2)(A+C)
  • W=(1/2)(B+C)

The rules are as follow:

  • erase edges [a2,b1],[b2,c1],[a1,c2]
  • add edges [a2,u1],[u2,b1],[b2,v1],[v2,c1],[w1,c2],w2,a1]
  • modify the states of nodes A,B,C

The large graph is a tetrahedron with contains :

  • 4 nodes A(0,0,-sqrt(2)/sqrt(3)) B(1/2,sqrt(3)/6,0) C(-1/2,sqrt(3)/6,0) D(0,-sqrt(3)/3),0)
  • 12 ports (qb,qc,qd,ra,rc(-),rd(+),pa,pb(+),pd(-),ta,tb(-),tc(+))
  • 18 edges [A,qb],[A,qc],[A,qd],[B,ra],[B,rc],[B,rd],[C,pa],[C,pb],[C,pd],[D,ta],[D,tb],[D,tc], [qb,ra],[qc,pa],[qd,ta],[ra,pb],[rc,pb],[rd,tb]

The results obtain after 5 iterations is given as follow:

snowFlake3D-5.png
snow flake 3D

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

The GPM_3DSnowGraph::createPatternFunctions create the 2 functions with 2 differents patterns and with the same transformer graph with the same rules.

The rules consist in

  • removing 3 edges from mapped pattern graph,
  • adding 6 edges from mapped pattern graph to new copy of transformer graph in large graph
  • setting the group name of mapped pattern nodes
SP::GPM_Snow3DFunction GPM_3DSnowGraph::createPatternFunction(SP::GPM_PortGraph pattern,SP::GPM_PortGraph transformer,
const tVertexIID pattern_iidv[3],const tVertexIID pattern_iidp[3][3],
const tVertexIID transformer_iidcp[3][2]) const {
SP::GPM_Snow3DFunction f=GPM_Snow3DFunction::New();
f->setPatternGraph(pattern);
f->setTransformerGraph(transformer);
f->addPEdgeToRemove(pattern_iidp[0][1],pattern_iidp[1][0]);//(b1,a2)
f->addPEdgeToRemove(pattern_iidp[0][2],pattern_iidp[2][0]);//(b2,c1)
f->addPEdgeToRemove(pattern_iidp[1][2],pattern_iidp[2][1]);//(a1,c2)
f->addPTEdgeToAdd(pattern_iidp[0][1],transformer_iidcp[0][1]);//(b1,u2)
f->addPTEdgeToAdd(pattern_iidp[0][2],transformer_iidcp[1][0]);//(b2,v1)
f->addPTEdgeToAdd(pattern_iidp[1][0],transformer_iidcp[0][0]);//(a2,u1)
f->addPTEdgeToAdd(pattern_iidp[1][2],transformer_iidcp[2][1]);//(a1,w2)
f->addPTEdgeToAdd(pattern_iidp[2][0],transformer_iidcp[1][1]);//(c1,v2)
f->addPTEdgeToAdd(pattern_iidp[2][1],transformer_iidcp[2][0]);//(c2,w1)
f->setPatternVertexGroupName(pattern_iidv[0],"1");
f->setPatternVertexGroupName(pattern_iidv[1],"1");
f->setPatternVertexGroupName(pattern_iidv[2],"1");
return f;
}

To update the coordianates of the copied transformer graph is done by specializing the method GPM_PatternFunction::updateStates :

const vector<tVertexIID>& mappingP2L,
const map<tVertexIID,tVertexIID>& mappingT2L) {
tBoolean succeeds=true;
// mapping function from transformer graph to copied transformer graph in large graph
map<tVertexIID,tVertexIID>::const_iterator mappingT2LIter;
const GPM_Node *cnode=null;
// get the coordinate A of the first node of mapped pattern graph
cnode=dynamic_cast<const GPM_Node*>(largeGraph.getVertex(mappingP2L[0]).get());
if (cnode==null) return false;
const tReal *A=cnode->getCoordinates();
// get the coordinate B of the secund node of mapped pattern graph
cnode=dynamic_cast<const GPM_Node*>(largeGraph.getVertex(mappingP2L[1]).get());
if (cnode==null) return false;
const tReal *B=cnode->getCoordinates();
// get the coordinate C of the third node of mapped pattern graph
cnode=dynamic_cast<const GPM_Node*>(largeGraph.getVertex(mappingP2L[2]).get());
if (cnode==null) return false;
const tReal *C=cnode->getCoordinates();
// get the group name for node 0 of pattern
tReal eps=CORE_Real::parseReal(largeGraph.getVertex(mappingP2L[0])->getGroupName());
// get the coordinate U of the first node of copied transformer graph
tReal *U;
GPM_Node *node=null;
mappingT2LIter=mappingT2L.find(0);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_cast<GPM_Node*>(largeGraph.getVertex(mappingT2LIter->second).get());
if (node==null) return false;
U=node->getCoordinates();
}
// get the coordinate V of the secund node of copied transformer graph
tReal *V=null;
mappingT2LIter=mappingT2L.find(1);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_cast<GPM_Node*>(largeGraph.getVertex(mappingT2LIter->second).get());
if (node==null) return false;
V=node->getCoordinates();
}
// get the coordinate W of the third node of copied transformer graph
tReal *W=null;
mappingT2LIter=mappingT2L.find(2);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_cast<GPM_Node*>(largeGraph.getVertex(mappingT2LIter->second).get());
if (node==null) return false;
W=node->getCoordinates();
}
// get the coordinate X of the fourth node of copied transformer graph
tReal *X=null;
mappingT2LIter=mappingT2L.find(3);
if (mappingT2LIter!=mappingT2L.end()) {
node=dynamic_cast<GPM_Node*>(largeGraph.getVertex(mappingT2LIter->second).get());
if (node==null) return false;
X=node->getCoordinates();
}
// mapping problem
if ((U==null) || (V==null) || (W==null) || (X==null)) return false;
int k=0;
tReal ABvAC[3];
tReal AB[5];
tReal AC[5];
// compute AB & AC
for (k=0;k<3;k++) {
AB[k]=B[k]-A[k];
AC[k]=C[k]-A[k];
}
// compute AB ^ AC
AB[3]=AB[0];
AC[3]=AC[0];
AB[4]=AB[1];
AC[4]=AC[1];
for (k=0;k<3;k++) {
ABvAC[k]=AB[k+1]*AC[k+2]-AB[k+2]*AC[k+1];
}
// set the coordinates of transformer in large graph
for (k=0;k<3;k++) {
U[k]=0.5*(A[k]+B[k]);
V[k]=0.5*(A[k]+C[k]);
W[k]=0.5*(B[k]+C[k]);
X[k]=((A[k]+B[k]+C[k])/3.)+eps*(sqrt(2)/6)*ABvAC[k];
}
return succeeds;
}

Creating pattern graph (or similarly tranfsformer graph) is as follow:

SP::GPM_PortGraph GPM_3DSnowGraph::createPatternGraph(const int& eps,tVertexIID iidv[4], tVertexIID iidp[3][3] ) const {
SP::GPM_PortGraph pattern=GPM_PortGraph::New();
// create vertices of pattern
SP::GPM_Vertex v;
size_t i,j,index=0;
for (i=0;i<3;i++) {
iidv[i]=pattern->addVertex(index++);
pattern->getVertex(iidv[i])->setGroupName("0");//state 0
}
v=pattern->getVertex(iidv[0]);
// create edges of pattern
for (i=0;i<3;i++) {
for (j=i+1;j<3;j++) {
pattern->addPortEdgeFromIds(iidv[i],iidv[j],index+1,index+2,iidp[i][j],iidp[j][i]);index+=2;
}
}
if (eps>0) {
v->setGroupName("1");
pattern->getVertex(iidp[1][2])->setTag("-");//a1
pattern->getVertex(iidp[2][1])->setTag("+");//c2
} else {
v->setGroupName("-1");
pattern->getVertex(iidp[1][2])->setTag("+");//a1
pattern->getVertex(iidp[2][1])->setTag("-");//c2
}
// update the group id form morphisms search
pattern->updateGroupId();
return pattern;
}