bool FeasibleUpwardPlanarSubgraph::constructMergeGraph(
	GraphCopy &M,
	adjEntry adj_orig,
	const List<edge> &orig_edges)
{
	CombinatorialEmbedding Beta(M);

	//set ext. face of Beta
	adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource();
	Beta.setExternalFace(Beta.rightFace(ext_adj));

	FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode()));
	SList<node> aug_nodes;
	SList<edge> aug_edges;
	SList<face> fList;
	fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest()
	node v_ext = fsg.faceNodeOf(Beta.externalFace());

	OGDF_ASSERT(v_ext != 0);

	fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges);

	//add the deleted edges
	for(edge eOrig: orig_edges) {
		node a = M.copy(eOrig->source());
		node b = M.copy(eOrig->target());
		M.newEdge(a, b);
	}
	return (isAcyclic(M));
}
Esempio n. 2
0
UpwardPlanRep::UpwardPlanRep(const GraphCopy &GC, ogdf::adjEntry adj_ext) :
	GraphCopy(GC),
	isAugmented(false),
	t_hat(nullptr),
	extFaceHandle(nullptr),
	crossings(0)
{
	OGDF_ASSERT(adj_ext != nullptr);
	OGDF_ASSERT(hasSingleSource(*this));

	m_isSourceArc.init(*this, false);
	m_isSinkArc.init(*this, false);
	hasSingleSource(*this, s_hat);
	m_Gamma.init(*this);

	//compute the ext. face;
	node v = copy(GC.original(adj_ext->theNode()));
	extFaceHandle = copy(GC.original(adj_ext->theEdge()))->adjSource();
	if (extFaceHandle->theNode() != v)
		extFaceHandle = extFaceHandle->twin();
	m_Gamma.setExternalFace(m_Gamma.rightFace(extFaceHandle));

	for(adjEntry adj : s_hat->adjEntries)
		m_isSourceArc[adj->theEdge()] = true;

	computeSinkSwitches();
}
Esempio n. 3
0
void SubgraphUpwardPlanarizer::constructComponentGraphs(BCTree &BC, NodeArray<GraphCopy> &biComps)
{
	NodeArray<int> constructed(BC.originalGraph(), -1);
	const Graph &bcTree = BC.bcTree();
	int i = 0; // comp. number
	for(node v : bcTree.nodes) {

		if (BC.typeOfBNode(v) == BCTree::CComp)
			continue;

		const SList<edge> &edges_comp = BC.hEdges(v); //bicomp edges
		List<edge> edges_orig;
		for(edge e : edges_comp)
			edges_orig.pushBack(BC.original(e));

		GraphCopy GC;
		GC.createEmpty(BC.originalGraph());
		// construct i-th component graph
		for(edge eOrig : edges_orig) {
			node srcOrig = eOrig->source();
			node tgtOrig = eOrig->target();
			if (constructed[srcOrig] != i) {
				constructed[srcOrig] = i;
				GC.newNode(srcOrig);
			}
			if (constructed[tgtOrig] != i) {
				constructed[tgtOrig] = i;
				GC.newNode(tgtOrig);
			}
			GC.newEdge(eOrig);
		}
		biComps[v] = GC;
		i++;
	}
}
Esempio n. 4
0
//use the layout information in the umlgraph to find nodes in
//unconnected active parts of a CC that can be connected without
//crossings in the given embedding
void PlanRepInc::getExtAdjs(List<adjEntry> & /* extAdjs */)
{
	//in order not to change the current CC initialization,
	//we construct a copy of the active parts (one by one)
	//and use the layout information to compute a external
	//face for that part. An (original) adjEntry on this face
	//is then inserted into the extAdjs list.

	//derive the unconnected parts by a run through the current
	//copy
	//compute connected component of current CC

	NodeArray<int> component(*this);
	int numPartialCC = connectedComponents(*this, component);
	EdgeArray<edge> copyEdge;//copy edges in partial CC copy
	//now we compute a copy for every CC
	//initialize an array of lists of nodes contained in a CC
	Array<List<node> >  nodesInPartialCC;
	nodesInPartialCC.init(numPartialCC);

	for(node v : nodes)
		nodesInPartialCC[component[v]].pushBack(v);

	int i = 0;
	for (i = 0; i < numPartialCC; i++)
	{
		List<node> &theNodes = nodesInPartialCC[i];
		GraphCopy GC;
		GC.createEmpty(*this);
		GC.initByNodes(theNodes, copyEdge);
		//now we derive an outer face of GC by using the
		//layout information on it's original


		//TODO: Insert the bend points into the copy


		//CombinatorialEmbedding E(GC);

		//run through the faces and compute angles to
		//derive outer face
		//we dont care about the original structure of
		//the graph, i.e., if crossings are inserted aso
		//we only take the given partial CC and its layout
		//adjEntry extAdj = getExtAdj(GC, E);

		//for(node v : GC.nodes)
		//{
		//
		//}
	}//for


}//getextadj
Esempio n. 5
0
File: Layout.cpp Progetto: ogdf/ogdf
void Layout::computePolyline(GraphCopy &GC, edge eOrig, DPolyline &dpl) const
{
	dpl.clear();

	const List<edge> &edgePath = GC.chain(eOrig);

	// The corresponding edge path in the copy must contain at least 1 edge!
	OGDF_ASSERT(edgePath.size() >= 1);

	// iterate over all edges in the corresponding edge path in the copy
	bool firstTime = true;
	for (edge e : edgePath) {
		node v = e->source();

		// append point of source node of e ...
		if (!firstTime)
			dpl.pushBack(DPoint(m_x[v], m_y[v]));
		else
			firstTime = false;

		// ... and polyline of e
		const DPolyline &segment = m_bends[e];

		for (const DPoint &dp : segment)
			dpl.pushBack(dp);
	}
}
Module::ReturnType FeasibleUpwardPlanarSubgraph::call(
	Graph &G,
	GraphCopy &FUPS,
	adjEntry &extFaceHandle,
	List<edge> &delEdges,
	bool multisources,
	int runs)
{

#ifdef OGDF_DEBUG
	OGDF_ASSERT(!UpwardPlanarity::isUpwardPlanar_singleSource(G));
#endif

	delEdges.clear();

	//current fups, its embedding and the removed edges
	GraphCopy FUPS_cur;
	List<edge> delEdges_cur;

	call(G, FUPS, extFaceHandle, delEdges, multisources);

	for (int i = 1; i < runs; ++i) {
		adjEntry extFaceHandle_cur;
		call(G, FUPS_cur, extFaceHandle_cur, delEdges_cur, multisources);

		// use new result??
		if (delEdges_cur.size() < delEdges.size()) {
			FUPS = FUPS_cur;
			extFaceHandle = FUPS.copy(FUPS_cur.original(extFaceHandle_cur->theEdge()))->adjSource();
			delEdges = delEdges_cur;
		}
	}
	return Module::retFeasible;
}
void UpwardPlanarSubgraphModule::callAndDelete(
	GraphCopy &GC,
	List<edge> &delOrigEdges)
{
	List<edge> delEdges;

	call(GC, delEdges);

	ListConstIterator<edge> it;
	for(it = delEdges.begin(); it.valid(); ++it) {
		edge eCopy = *it;

		delOrigEdges.pushBack(GC.original(eCopy));
		GC.delEdge(eCopy);
	}
}
Esempio n. 8
0
void FUPSSimple::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random)
{
	if (GC.numberOfNodes() == 1)
		return; // nothing to do

	node s;
	hasSingleSource(GC, s);
	NodeArray<bool> visited(GC, false);
	EdgeArray<bool> isTreeEdge(GC,false);
	List<node> toDo;

	//mark the incident edges e1..e_i of super source s and the incident edges of the target node of the edge e1.._e_i as tree edge.
	visited[s] = true;
	for(adjEntry adj : s->adjEdges) {
		isTreeEdge[adj] = true;
		visited[adj->theEdge()->target()];
		for(adjEntry adjTmp : adj->theEdge()->target()->adjEdges) {
			isTreeEdge[adjTmp] = true;
			node tgt = adjTmp->theEdge()->target();
			if (!visited[tgt]) {
				toDo.pushBack(tgt);
				visited[tgt] = true;
			}
		}
	}

	//traversing with dfs
	for(node start : toDo) {
		for(adjEntry adj : start->adjEdges) {
			node v = adj->theEdge()->target();
			if (!visited[v])
				dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random);
		}
	}

	// delete all non tree edgesEdges to obtain a span tree
	List<edge> l;
	for(edge e : GC.edges) {
		if (!isTreeEdge[e])
			l.pushBack(e);
	}
	while (!l.empty()) {
		edge e = l.popFrontRet();
		delEdges.pushBack(GC.original(e));
		GC.delEdge(e);
	}
}
void FeasibleUpwardPlanarSubgraph::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random, bool multisource)
{
	delEdges.clear();
	if (GC.numberOfNodes() == 1)
		return; // nothing to do
	node s;
	hasSingleSource(GC, s);
	NodeArray<bool> visited(GC, false);
	EdgeArray<bool> isTreeEdge(GC,false);
	List<node> toDo;

	// the original graph is a multisource graph. The sources are connected with the super source s.
	// so do not delete the incident edges of s
	if (multisource){
		// put all incident edges of the source to treeEdges
		for(adjEntry adj : s->adjEdges) {
			isTreeEdge[adj->theEdge()] = true;
			visited[adj->theEdge()->target()];
			toDo.pushBack(adj->theEdge()->target());
		}
	}
	else
		toDo.pushBack(s);


	//traversing with dfs
	for(node start : toDo) {
		for(adjEntry adj : start->adjEdges) {
			node v = adj->theEdge()->target();
			if (!visited[v])
				dfs_visit(GC, adj->theEdge(), visited, isTreeEdge, random);
		}
	}

	// delete all non tree edgesEdges to obtain a span tree
	List<edge> l;
	for(edge e : GC.edges) {
		if (!isTreeEdge[e])
			l.pushBack(e);
	}
	while (!l.empty()) {
		edge e = l.popFrontRet();
		delEdges.pushBack(GC.original(e));
		GC.delEdge(e);
	}
}
Esempio n. 10
0
void GEMLayout::updateNode(GraphCopy &G, GraphCopyAttributes &AG,node v) {
	//const Graph &G = AG.constGraph();
	int n = G.numberOfNodes();
	double impulseLength;

	impulseLength = length(m_newImpulseX,m_newImpulseY);
	if(OGDF_GEOM_ET.greater(impulseLength,0.0)) {

		// scale impulse by node temperature
		m_newImpulseX *= m_localTemperature[v] / impulseLength;
		m_newImpulseY *= m_localTemperature[v] / impulseLength;

		// move node
		AG.x(v) += m_newImpulseX;
		AG.y(v) += m_newImpulseY;

		// adjust barycenter
		m_barycenterX += weight(v) * m_newImpulseX;
		m_barycenterY += weight(v) * m_newImpulseY;

		impulseLength = length(m_newImpulseX,m_newImpulseY)
						* length(m_impulseX[v],m_impulseY[v]);
		if(OGDF_GEOM_ET.greater(impulseLength,0.0)) {

			m_globalTemperature -= m_localTemperature[v] / n;

			// compute sine and cosine of angle between old and new impulse
			double sinBeta,cosBeta;
			sinBeta = (m_newImpulseX * m_impulseX[v]
				- m_newImpulseY * m_impulseY[v])
					/ impulseLength;
			cosBeta = (m_newImpulseX * m_impulseX[v]
				+ m_newImpulseY * m_impulseY[v])
					/ impulseLength;

			// check for rotation
			if(OGDF_GEOM_ET.greater(sinBeta,m_sin))
				m_skewGauge[v] += m_rotationSensitivity;

			// check for oscillation
			if(OGDF_GEOM_ET.greater(length(cosBeta),m_cos))
				m_localTemperature[v] *=
					(1 + cosBeta * m_oscillationSensitivity);

			// cool down according to skew gauge
			m_localTemperature[v] *= (1.0 - length(m_skewGauge[v]));
			if(OGDF_GEOM_ET.geq(m_localTemperature[v],m_initialTemperature))
				m_localTemperature[v] = m_initialTemperature;

			// adjust global temperature
			m_globalTemperature += m_localTemperature[v] / n;
		}

		// save impulse
		m_impulseX[v] = m_newImpulseX;
		m_impulseY[v] = m_newImpulseY;
	}
}
Module::ReturnType FeasibleUpwardPlanarSubgraph::call(
	const Graph &G,
	GraphCopy &FUPS,
	adjEntry &extFaceHandle,
	List<edge> &delEdges,
	bool multisources)
{
	FUPS = GraphCopy(G);
	delEdges.clear();
	node s_orig;
	hasSingleSource(G, s_orig);
	List<edge> nonTreeEdges_orig;
	getSpanTree(FUPS, nonTreeEdges_orig, true, multisources);
	CombinatorialEmbedding Gamma(FUPS);
	nonTreeEdges_orig.permute(); // random order

	//insert nonTreeEdges
	while (!nonTreeEdges_orig.empty()) {
		// make identical copy GC of Fups
		//and insert e_orig in GC
		GraphCopy GC = FUPS;
		edge e_orig = nonTreeEdges_orig.popFrontRet();
		//node a = GC.copy(e_orig->source());
		//node b = GC.copy(e_orig->target());
		GC.newEdge(e_orig);

		if (UpwardPlanarity::upwardPlanarEmbed_singleSource(GC)) { //upward embedded the fups and check feasibility
			CombinatorialEmbedding Beta(GC);

			//choose a arbitrary feasibel ext. face
			FaceSinkGraph fsg(Beta, GC.copy(s_orig));
			SList<face> ext_faces;
			fsg.possibleExternalFaces(ext_faces);
			OGDF_ASSERT(!ext_faces.empty());
			Beta.setExternalFace(ext_faces.front());

			GraphCopy M = GC; // use a identical copy of GC to constrcut the merge graph of GC
			adjEntry extFaceHandle_cur = getAdjEntry(Beta, GC.copy(s_orig), Beta.externalFace());
			adjEntry adj_orig = GC.original(extFaceHandle_cur->theEdge())->adjSource();

			if (constructMergeGraph(M, adj_orig, nonTreeEdges_orig)) {
				FUPS = GC;
				extFaceHandle = FUPS.copy(GC.original(extFaceHandle_cur->theEdge()))->adjSource();
				continue;
			}
			else {
				//Beta is not feasible
				delEdges.pushBack(e_orig);
			}
		}
		else {
			// not ok, GC is not feasible
			delEdges.pushBack(e_orig);
		}
	}

	return Module::retFeasible;
}
void ComponentSplitterLayout::call(GraphAttributes &GA)
{
	// Only do preparations and call if layout is valid
	if (m_secondaryLayout.valid())
	{
		//first we split the graph into its components
		const Graph& G = GA.constGraph();

		NodeArray<int> componentNumber(G);
		m_numberOfComponents = connectedComponents(G, componentNumber);
		if (m_numberOfComponents == 0) {
			return;
		}

		//std::vector< std::vector<node> > componentArray;
		//componentArray.resize(numComponents);
		//Array<GraphAttributes *> components(numComponents);
		//

		// intialize the array of lists of nodes contained in a CC
		nodesInCC.init(m_numberOfComponents);

		node v;
		forall_nodes(v,G)
			nodesInCC[componentNumber[v]].pushBack(v);

		 // Create copies of the connected components and corresponding
		 // GraphAttributes
		 GraphCopy GC;
		 GC.createEmpty(G);

		 EdgeArray<edge> auxCopy(G);

		 for (int i = 0; i < m_numberOfComponents; i++)
		 {
			 GC.initByNodes(nodesInCC[i],auxCopy);
			 GraphAttributes cGA(GC);
			 //copy information into copy GA
			 forall_nodes(v, GC)
			 {
				cGA.width(v) = GA.width(GC.original(v));
				cGA.height(v) = GA.height(GC.original(v));
				cGA.x(v) = GA.x(GC.original(v));
				cGA.y(v) = GA.y(GC.original(v));
			 }
			 m_secondaryLayout.get().call(cGA);

			 //copy layout information back into GA
			 forall_nodes(v, GC)
			 {
				 node w = GC.original(v);
				 if (w != 0)
					 GA.x(w) = cGA.x(v);
				 GA.y(w) = cGA.y(v);
			 }
		 }
Esempio n. 13
0
void GEMLayout::computeImpulse(GraphCopy &G, GraphCopyAttributes &AG,node v) {
	//const Graph &G = AG.constGraph();
	int n = G.numberOfNodes();

	double deltaX,deltaY,delta,deltaSqu;
	double desiredLength,desiredSqu;

	// add double node radius to desired edge length
	desiredLength = m_desiredLength + length(AG.getHeight(v),AG.getWidth(v));
	desiredSqu = desiredLength * desiredLength;

	// compute attraction to center of gravity
	m_newImpulseX = (m_barycenterX / n - AG.x(v)) * m_gravitationalConstant;
	m_newImpulseY = (m_barycenterY / n - AG.y(v)) * m_gravitationalConstant;

	// disturb randomly
	int maxIntDisturbance = (int)(m_maximalDisturbance * 10000);
	std::uniform_int_distribution<> dist(-maxIntDisturbance,maxIntDisturbance);
	m_newImpulseX += (dist(m_rng) / 10000.0);
	m_newImpulseY += (dist(m_rng) / 10000.0);

	// compute repulsive forces
	for(node u : G.nodes)
		if(u != v ) {
			deltaX = AG.x(v) - AG.x(u);
			deltaY = AG.y(v) - AG.y(u);
			delta = length(deltaX,deltaY);
			if(OGDF_GEOM_ET.greater(delta,0.0)) {
				deltaSqu = delta * delta;
				m_newImpulseX += deltaX * desiredSqu / deltaSqu;
				m_newImpulseY += deltaY * desiredSqu / deltaSqu;
			}
	}

	// compute attractive forces
	for(adjEntry adj : v->adjEntries) {
		node u = adj->twinNode();
		deltaX = AG.x(v) - AG.x(u);
		deltaY = AG.y(v) - AG.y(u);
		delta = length(deltaX,deltaY);
		if(m_attractionFormula == 1) {
			m_newImpulseX -= deltaX * delta / (desiredLength * weight(v));
			m_newImpulseY -= deltaY * delta / (desiredLength * weight(v));
		}
		else {
			deltaSqu = delta * delta;
			m_newImpulseX -= deltaX * deltaSqu / (desiredSqu * weight(v));
			m_newImpulseY -= deltaY * deltaSqu / (desiredSqu * weight(v));
		}
	}

}
Esempio n. 14
0
Module::ReturnType PlanarSubgraphModule::callAndDelete(
	GraphCopy &PG,
	const List<edge> &preferedEdges,
	List<edge> &delOrigEdges,
	bool preferedImplyPlanar)
{
	List<edge> delEdges;

	ReturnType retValue = call(PG, preferedEdges, delEdges, preferedImplyPlanar);

	if(isSolution(retValue))
	{
		ListConstIterator<edge> it;
		for(it = delEdges.begin(); it.valid(); ++it) {
			edge eCopy = *it;
	
			delOrigEdges.pushBack(PG.original(eCopy));
			PG.delCopy(eCopy);
		}
	}
		
	return retValue;
}
Esempio n. 15
0
void GraphCopy::initGC(const GraphCopy &GC,
	NodeArray<node> &vCopy,
	EdgeArray<edge> &eCopy)
{
	createEmpty(*GC.m_pGraph);

	for(node v : GC.nodes)
		m_vOrig[vCopy[v]] = GC.original(v);

	for(edge e : GC.edges)
		m_eOrig[eCopy[e]] = GC.original(e);

	for (node v : nodes) {
		node w = m_vOrig[v];
		if (w != nullptr)
			m_vCopy[w] = v;
	}

	for(edge e : m_pGraph->edges) {
		ListConstIterator<edge> it;
		for (edge ei : GC.m_eCopy[e])
			m_eIterator[eCopy[ei]] = m_eCopy[e].pushBack(eCopy[ei]);
	}
}
Esempio n. 16
0
void FPPLayout::computeCoordinates(const GraphCopy &G, IPoint &boundingBox, GridLayout &gridLayout, NodeArray<int> &num,
									NodeArray<adjEntry> &e_wp, NodeArray<adjEntry> &e_wq) {
	NodeArray<int> &x = gridLayout.x();
	NodeArray<int> &y = gridLayout.y();

	const int n = G.numberOfNodes();
	NodeArray<int>  x_rel(G);
	NodeArray<node> upper(G);
	NodeArray<node> next(G);
	Array<node, int> v(1, n);
	node w, vk, wp, wq;
	int k, xq, dx;

	forall_nodes(w, G) {
		v[num[w]] = (node) w;
	}
void FeasibleUpwardPlanarSubgraph::getSpanTree(GraphCopy &GC, List<edge> &delEdges, bool random, bool multisource)
{
	delEdges.clear();
	if (GC.numberOfNodes() == 1)
		return; // nothing to do
	node s;
	hasSingleSource(GC, s);
	NodeArray<bool> visited(GC, false);
	EdgeArray<bool> isTreeEdge(GC,false);
	List<node> toDo;

	// the original graph is a multisource graph. The sources are connected with the super source s.
	// so do not delete the incident edges of s
	if (multisource){
		// put all incident edges of the source to treeEdges
		adjEntry adj;
		forall_adj(adj, s) {
			isTreeEdge[adj->theEdge()] = true;
			visited[adj->theEdge()->target()];
			toDo.pushBack(adj->theEdge()->target());
		}
	}
void ExpandedGraph2::constructDual(node s, node t,
                                   GraphCopy &GC, const EdgeArray<bool> *forbiddenEdgeOrig)
{
    m_dual.clear();

    FaceArray<node> faceNode(m_E);

    // constructs nodes (for faces in exp)
    face f;
    forall_faces(f,m_E) {
        faceNode[f] = m_dual.newNode();
    }

    // construct dual edges (for primal edges in exp)
    node v;
    forall_nodes(v,m_exp)
    {
        adjEntry adj;
        forall_adj(adj,v)
        {
            // cannot cross edges that does not correspond to real edges
            adjEntry adjG = m_expToG[adj];
            if(adjG == 0)
                continue;

            // Do not insert edges into dual if crossing the original edge
            // is forbidden
            if(forbiddenEdgeOrig &&
                    (*forbiddenEdgeOrig)[GC.original(m_BC.dynamicSPQRForest().original(m_expToG[adj]->theEdge()))] == true)
                continue;

            node vLeft  = faceNode[m_E.leftFace (adj)];
            node vRight = faceNode[m_E.rightFace(adj)];

            m_primalEdge[m_dual.newEdge(vLeft,vRight)] = adj;
        }
Esempio n. 19
0
void UpwardPlanarSubgraphSimple::call(GraphCopy &GC, List<edge> &delEdges)
{
	const Graph &G = GC.original();
	delEdges.clear();

	// We construct an auxiliary graph H which represents the current upward
	// planar subgraph.
	Graph H;
	NodeArray<node> mapToH(G,nullptr);
	NodeArray<node> mapToG(H,nullptr);

	for(node v : G.nodes)
		mapToG[ mapToH[v] = H.newNode() ] = v;


	// We currently support only single-source acyclic digraphs ...
	node s;
	hasSingleSource(G,s);

	OGDF_ASSERT(s != 0);
	OGDF_ASSERT(isAcyclic(G));

	// We start with a spanning tree of G rooted at the single source.
	NodeArray<bool> visitedNode(G,false);
	SListPure<edge> treeEdges;
	dfsBuildSpanningTree(s,treeEdges,visitedNode);


	// Mark all edges in the spanning tree so they can be skipped in the
	// loop below and add (copies of) them to H.
	EdgeArray<bool> visitedEdge(G,false);
	SListConstIterator<edge> it;
	for(it = treeEdges.begin(); it.valid(); ++it) {
		edge eG = *it;
		visitedEdge[eG] = true;
		H.newEdge(mapToH[eG->source()],mapToH[eG->target()]);
	}


	// Add subsequently the remaining edges to H and test if the resulting
	// graph is still upward planar. If not, remove the edge again from H
	// and add it to delEdges.

	SList<Tuple2<node,node> > augmented;
	GraphCopySimple graphAcyclicTest(G);

	for(edge eG : G.edges)
	{
		// already treated ?
		if(visitedEdge[eG] == true)
			continue;

		// insert edge into H
		edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]);

		node superSink;
		SList<edge> augmentedEdges;
		if (UpwardPlanarity::upwardPlanarAugment_singleSource(H,superSink,augmentedEdges) == false) {
			// if H is no longer upward planar, remove eG from subgraph
			H.delEdge(eH);
			delEdges.pushBack(eG);

		} else {
			// add augmented edges as node-pair to tmpAugmented and remove
			// all augmented edges from H again
			SList<Tuple2<node,node> > tmpAugmented;
			SListConstIterator<edge> it;
			for(it = augmentedEdges.begin(); it.valid(); ++it) {
				node v = mapToG[(*it)->source()];
				node w = mapToG[(*it)->target()];

				if (v && w)
					tmpAugmented.pushBack(Tuple2<node,node>(v,w));

				H.delEdge(*it);
			}

			if (mapToG[superSink] == nullptr)
				H.delNode(superSink);

			//****************************************************************
			// The following is a simple workaround to assure the following
			// property of the upward planar subgraph:
			//   The st-augmented upward planar subgraph plus the edges not
			//   in the subgraph must be acyclic. (This is a special property
			//   of the embedding, not the augmentation.)
			// The upward-planar embedding function gives us ANY upward-planar
			// embedding. We check if the property above holds with this
			// embedding. If it doesn't, we have actually no idea if another
			// embedding would do.
			// The better solution would be to incorporate the acyclicity
			// property into the upward-planarity test, but this is compicated.
			//****************************************************************

			// test if original graph plus augmented edges is still acyclic
			if(checkAcyclic(graphAcyclicTest,tmpAugmented) == true) {
				augmented = tmpAugmented;

			} else {
				// if not, remove eG from subgraph
				H.delEdge(eH);
				delEdges.pushBack(eG);
			}
		}

	}

	// remove edges not in the subgraph from GC
	ListConstIterator<edge> itE;
	for(itE = delEdges.begin(); itE.valid(); ++itE)
		GC.delEdge(GC.copy(*itE));

	// add augmented edges to GC
	SListConstIterator<Tuple2<node,node> > itP;
	for(itP = augmented.begin(); itP.valid(); ++itP) {
		node v = (*itP).x1();
		node w = (*itP).x2();

		GC.newEdge(GC.copy(v),GC.copy(w));
	}

	// add super sink to GC
	node sGC = nullptr;
	SList<node> sinks;
	for(node v : GC.nodes) {
		if(v->indeg() == 0)
			sGC = v;
		if(v->outdeg() == 0)
			sinks.pushBack(v);
	}

	node superSinkGC = GC.newNode();
	SListConstIterator<node> itV;
	for(itV = sinks.begin(); itV.valid(); ++itV)
		GC.newEdge(*itV,superSinkGC);

	// add st-edge to GC, so that we now have a planar st-digraph
	GC.newEdge(sGC,superSinkGC);

	OGDF_ASSERT(isAcyclic(GC));
	OGDF_ASSERT(isPlanar(GC));
}
Esempio n. 20
0
/*
 * Construct the realiszer and the Tree T
 * rValues = realizer value
 * T = Tree
 */
void SchnyderLayout::realizer(
	GraphCopy& G,
	const List<node>& L,
	node a,
	node b,
	node c,
	EdgeArray<int>& rValues,
	GraphCopy& T)
{
	int  i = 0;
	edge e;
	NodeArray<int> ord(G, 0);

	// ordering: b,c,L,a
	ord[b] = i++;
	ord[c] = i++;

	for(node v : L) {
		ord[v] = i++;				// enumerate V(G)
	}
	ord[a] = i++;

	// remove all edges (they will be re-added later with different orientation)
	while (T.numberOfEdges() > 0) {
		e = T.firstEdge();
		T.delEdge(e);
	}

	for(node v : L) {
		node u = T.copy(G.original(v));   // u is copy of v in T

		adjEntry adj = nullptr;
		for(adjEntry adjRun : v->adjEdges) {
			if (ord[adjRun->twinNode()] > ord[v]) {
				adj = adjRun;
				break;
			}
		}

		adjEntry adj1 = adj;
		while (ord[adj1->twinNode()] > ord[v]) {
			adj1 = adj1->cyclicSucc();
		}
		e = T.newEdge(T.copy(G.original(adj1->twinNode())), u);
		rValues[e] = 2;

		adjEntry adj2 = adj;
		while (ord[adj2->twinNode()] > ord[v]) {
			adj2 = adj2->cyclicPred();
		}
		e = T.newEdge(T.copy(G.original(adj2->twinNode())), u);
		rValues[e] = 3;

		for (adj = adj1->cyclicSucc(); adj != adj2; adj = adj->cyclicSucc()) {
			e =  T.newEdge(u, T.copy(G.original(adj->twinNode())));
			rValues[e] = 1;
		}
	}

	// special treatement of a,b,c
	node a_in_T = T.copy(G.original(a));
	node b_in_T = T.copy(G.original(b));
	node c_in_T = T.copy(G.original(c));

	// all edges to node a get realizer value 1
	for(adjEntry adj : a->adjEdges) {
		e = T.newEdge(a_in_T, T.copy(G.original(adj->twinNode())));
		rValues[e] = 1;
	}

	// rest of outer triangle (reciprocal linked, realizer values 2 and 3)
	e = T.newEdge(b_in_T, a_in_T);
	rValues[e] = 2;
	e = T.newEdge(b_in_T, c_in_T);
	rValues[e] = 2;

	e = T.newEdge(c_in_T, a_in_T);
	rValues[e] = 3;
	e = T.newEdge(c_in_T, b_in_T);
	rValues[e] = 3;
}
void GEMLayout::call(GraphAttributes &AG) 
{
	const Graph &G = AG.constGraph();
	if(G.empty())
		return;

	OGDF_ASSERT(m_numberOfRounds >= 0);
	OGDF_ASSERT(DIsGreaterEqual(m_minimalTemperature,0));
	OGDF_ASSERT(DIsGreaterEqual(m_initialTemperature,m_minimalTemperature));
	OGDF_ASSERT(DIsGreaterEqual(m_gravitationalConstant,0));
	OGDF_ASSERT(DIsGreaterEqual(m_desiredLength,0));
	OGDF_ASSERT(DIsGreaterEqual(m_maximalDisturbance,0));
	OGDF_ASSERT(DIsGreaterEqual(m_rotationAngle,0));
	OGDF_ASSERT(DIsLessEqual(m_rotationAngle,pi / 2));
	OGDF_ASSERT(DIsGreaterEqual(m_oscillationAngle,0));
	OGDF_ASSERT(DIsLessEqual(m_oscillationAngle,pi / 2));
	OGDF_ASSERT(DIsGreaterEqual(m_rotationSensitivity,0));
	OGDF_ASSERT(DIsLessEqual(m_rotationSensitivity,1));
	OGDF_ASSERT(DIsGreaterEqual(m_oscillationSensitivity,0));
	OGDF_ASSERT(DIsLessEqual(m_oscillationSensitivity,1));
	OGDF_ASSERT(m_attractionFormula == 1 || m_attractionFormula == 2);
	
	// all edges straight-line
	AG.clearAllBends();

	GraphCopy GC;
	GC.createEmpty(G);

	// compute connected component of G
	NodeArray<int> component(G);
	int numCC = connectedComponents(G,component);

	// intialize the array of lists of nodes contained in a CC
	Array<List<node> > nodesInCC(numCC);

	node v;
	forall_nodes(v,G)
		nodesInCC[component[v]].pushBack(v);

	EdgeArray<edge> auxCopy(G);
	Array<DPoint> boundingBox(numCC);

	int i;
	for(i = 0; i < numCC; ++i)
	{
		GC.initByNodes(nodesInCC[i],auxCopy);

		GraphCopyAttributes AGC(GC,AG);
		node vCopy;
		forall_nodes(vCopy, GC) {
			node vOrig = GC.original(vCopy);
			AGC.x(vCopy) = AG.x(vOrig);
			AGC.y(vCopy) = AG.y(vOrig);
		}

		SList<node> permutation;
		node v;

		// initialize node data
		m_impulseX.init(GC,0);
		m_impulseY.init(GC,0);
		m_skewGauge.init(GC,0);
		m_localTemperature.init(GC,m_initialTemperature);

		// initialize other data
		m_globalTemperature = m_initialTemperature;
		m_barycenterX = 0;
		m_barycenterY = 0;
		forall_nodes(v,GC) {
			m_barycenterX += weight(v) * AGC.x(v);
			m_barycenterY += weight(v) * AGC.y(v);
		}
Esempio n. 22
0
//outputs the set of feasible solutions
void ClusterPlanarity::writeFeasible(const char *filename,
	CP_MasterBase &master,
	Master::STATUS &status)
{
	const ClusterGraph& CG = *(master.getClusterGraph());
	const Graph& G = CG.constGraph();
	//first compute the nodepairs that are potential candidates to connect
	//chunks in a cluster
	//potential connection edges
	NodeArray< NodeArray<bool> > potConn(G);
	for(node v : G.nodes)
	{
		potConn[v].init(G, false);
	}
	//we perform a bottom up cluster tree traversal
	List< cluster > clist;
	getBottomUpClusterList(CG.rootCluster(), clist);
	//could use postordertraversal instead

	List< nodePair > connPairs; //holds all connection node pairs
	//counts the number of potential connectivity edges
	//int potCount = 0; //equal to number of true values in potConn

	//we run through the clusters and check connected components
	//we consider all possible edges connecting CCs in a cluster,
	//even if they may be connected by edges in a child cluster
	//(to get the set of all feasible solutions)

	for(cluster c : clist)
	{
		//we compute the subgraph induced by vertices in c
		GraphCopy gcopy;
		gcopy.createEmpty(G);
		List<node> clusterNodes;
		//would be more efficient if we would just merge the childrens' vertices
		//and add c's
		c->getClusterNodes(clusterNodes);
		NodeArray<bool> activeNodes(G, false); //true for all cluster nodes
		EdgeArray<edge> copyEdge(G); //holds the edge copy

		for(node v : clusterNodes)
			activeNodes[v] = true;

		gcopy.initByActiveNodes(clusterNodes, activeNodes, copyEdge);
		//gcopy now represents the cluster induced subgraph

		//we compute the connected components and store all nodepairs
		//that connect two of them
		NodeArray<int> component(gcopy);
		connectedComponents(gcopy, component);
		//now we run over all vertices and compare the component
		//number of adjacent vertices. If they differ, we found a
		//potential connection edge. We do not care if we find them twice.
		for(node v : gcopy.nodes)
		{
			for(node w : gcopy.nodes)
			{
				if (component[v] != component[w])
				{
					cout <<"Indizes: "<<v->index()<<":"<<w->index()<<"\n";
					node vg = gcopy.original(v);
					node wg = gcopy.original(w);
					bool newConn = !((vg->index() < wg->index()) ? potConn[vg][wg] : potConn[wg][vg]);
					if (newConn)
					{
						nodePair np; np.v1 = vg; np.v2 = wg;
						connPairs.pushBack(np);
						if (vg->index() < wg->index())
							potConn[vg][wg] = true;
						else
							potConn[wg][vg] = true;
					}
				}
			}//nodes
		}//nodes
	}

	cout << "Number of potential connection edges: "<< connPairs.size()<<"\n";

	//we run through our candidates and save them in an array
	//that can be used for dynamic graph updates
	int i = 0;
	connStruct *cons = new connStruct[connPairs.size()];
	for(const nodePair &np : connPairs)
	{
		connStruct cs;
		cs.connected = false;
		cs.v1 = np.v1;
		cs.v2 = np.v2;
		cs.e  = nullptr;

		cons[i] = cs;
		i++;
	}

	//-------------------------------------------------------------------------
	// WARNING: this is extremely slow for graphs with a large number of cluster
	// chunks now we test all possible connection edge combinations for c-planarity
	Graph G2;

	NodeArray<node> origNodes(CG.constGraph());
	ClusterArray<cluster> origCluster(CG);
	EdgeArray<edge> origEdges(CG.constGraph());
	ClusterGraph testCopy(CG, G2, origCluster, origNodes, origEdges);

	ofstream os(filename);

	// Output dimension of the LP (number of variables)
	os << "DIM = " << connPairs.size() << "\n";
	os << "COMMENT\n";

	switch (status) {
		case Master::Optimal:
			os << "Optimal \n\n"; break;
		case Master::Error:
			os << "Error \n\n"; break;
		default:
			os << "unknown \n\n";
	}

	for (i = 0; i < connPairs.size(); i++)
	{
		os << "Var " << i << ": " << origNodes[cons[i].v1]->index() << "->" << origNodes[cons[i].v2] << "\n";
	}

	os << "CONV_SECTION\n";

#ifdef writefeasiblegraphs
	int j = 0; //debug
#endif

	if (connPairs.size() > 0)
	while (true)
	{
		//we create the next test configuration by incrementing the edge selection array
		//we create the corresponding graph dynamically on the fly
		i = 0;
		while ( (i < connPairs.size()) && (cons[i].connected == true) )
		{
			cons[i].connected = false;
			OGDF_ASSERT(cons[i].e != 0);
			G2.delEdge(cons[i].e);
			i++;
		}//while
		if (i >= connPairs.size()) break;
		//cout<<"v1graph: "<<&(*(cons[i].v1->graphOf()))<<"\n";
		//cout<<"origNodesgraph: "<<&(*(origNodes.graphOf()))<<"\n";
		cons[i].connected = true; //i.e., (false) will never be a feasible solution
		cons[i].e = G2.newEdge(origNodes[cons[i].v1], origNodes[cons[i].v2]);


		//and test it for c-planarity
		CconnectClusterPlanar CCCP;
		bool cplanar = CCCP.call(testCopy);

		//c-planar graphs define a feasible solution
		if (cplanar)
		{
#ifdef OGDF_DEBUG
			cout << "Feasible solution found\n";
#endif
			for (int j = 0; j < connPairs.size(); j++)
			{
				char ch = (cons[j].connected ? '1' : '0');
				cout << ch;
				os << ch << " ";
			}
			cout << "\n";
			os << "\n";
#ifdef writefeasiblegraphs
			string fn = "cGraph";
			fn += to_string(j++) + ".gml";
			GraphIO::writeGML(testCopy, fn);
#endif
		}
	}//while counting

	delete[] cons;

	os << "\nEND" <<"\n";
	os.close();

	//return;

	os.open(getIeqFileName());
	os << "DIM = " << m_numVars << "\n";
	// Output the status as a comment
	os << "COMMENT\n";

	switch (status) {
		case Master::Optimal:
			os << "Optimal \n\n"; break;
		case Master::Error:
			os << "Error \n\n"; break;
		default:
			os << "unknown \n\n";
	}

	// In case 0 is not a valid solution, some PORTA functions need
	//a valid solution in the ieq file
	os << "VALID\n";

	os << "\nLOWER_BOUNDS\n";

	for (i = 0; i < m_numVars; i++) os << "0 ";
	os << "\n";

	os << "\nHIGHER_BOUNDS\n";
	for (i = 0; i < m_numVars; i++) os << "1 ";
	os << "\n";

	os << "\nINEQUALITIES_SECTION\n";
	//we first read the standard constraint that are written
	//into a text file by the optimization master
	ifstream isf(master.getStdConstraintsFileName());
	if (!isf)
	{
		cerr << "Could not open optimization master's standard constraint file\n";
		os << "#No standard constraints read\n";
	}
	else
	{
		char* fileLine = new char[maxConLength()];
		while (isf.getline(fileLine, maxConLength()))
		{
			//skip commment lines
			if (fileLine[0] == '#') continue;
			int count = 1;
			std::istringstream iss(fileLine);
			char d;
			bool rhs = false;
			while (iss >> d)
			{
				if ( rhs || ( (d == '<') || (d == '>') || (d == '=') ) )
				{
					os << d;
					rhs = true;
				}
				else
				{
					if (d != '0')
					{
						os <<"+"<< d <<"x"<<count;
					}
					count++;
				}
			}//while chars
			os <<"\n";
		}
		delete[] fileLine;
	}//ifstream
	//now we read the cut pools from the master
	if (master.useDefaultCutPool())
	{
		os << "#No cut constraints read from master\n";
		//StandardPool<Constraint, Variable> *connCon = master.cutPool();
	}
	else
	{
		StandardPool<Constraint, Variable> *connCon = master.getCutConnPool();
		StandardPool<Constraint, Variable> *kuraCon = master.getCutKuraPool();
		StandardPool<Variable, Constraint> *stdVar = master.varPool();
		OGDF_ASSERT(connCon != 0);
		OGDF_ASSERT(kuraCon != 0);
		cout << connCon->number() << " Constraints im MasterConnpool \n";
		cout << kuraCon->number() << " Constraints im MasterKurapool \n";
		cout << connCon->size() << " Größe ConnPool"<<"\n";
		outputCons(os, connCon, stdVar);
		outputCons(os, kuraCon, stdVar);
	}//else
	os << "\nEND" <<"\n";
	os.close();
	cout << "Cutting is set: "<<master.cutting()<<"\n";
	//cout <<"Bounds for the variables:\n";
	//Sub &theSub = *(master.firstSub());
	//for ( i = 0; i < theSub.nVar(); i++)
	//{
	//	cout << i << ": " << theSub.lBound(i) << " - " << theSub.uBound(i) << "\n";
	//}
	/*// OLD CRAP
	cout << "Constraints: \n";
	StandardPool< Constraint, Variable > *spool = master.conPool();
	StandardPool< Constraint, Variable > *cpool = master.cutPool();

	cout << spool->size() << " Constraints im Masterpool \n";
	cout << cpool->size() << " Constraints im Mastercutpool \n";

	cout << "ConPool Constraints \n";
	for ( i = 0; i < spool->size(); i++)
	{
		PoolSlot< Constraint, Variable > * sloty = spool->slot(i);
		Constraint *mycon = sloty->conVar();
		switch (mycon->sense()->sense())
		{
			case CSense::Less: cout << "<" << "\n"; break;
			case CSense::Greater: cout << ">" << "\n"; break;
			case CSense::Equal: cout << "=" << "\n"; break;
			default: cout << "Inequality sense doesn't make any sense \n"; break;
		}//switch
	}
	cout << "CutPool Constraints \n";
	for ( i = 0; i < cpool->size(); i++)
	{
		PoolSlot< Constraint, Variable > * sloty = cpool->slot(i);
		Constraint *mycon = sloty->conVar();
		switch (mycon->sense()->sense())
		{
			case CSense::Less: cout << "<" << "\n"; break;
			case CSense::Greater: cout << ">" << "\n"; break;
			case CSense::Equal: cout << "=" << "\n"; break;
			default: cout << "Inequality sense doesn't make any sense \n"; break;
		}//switch
	}
	*/
	/*
	for ( i = 0; i < theSub.nCon(); i++)
	{
		Constraint &theCon = *(theSub.constraint(i));

		for ( i = 0; i < theSub.nVar(); i++)
		{
			double c = theCon.coeff(theSub.variable(i));
			if (c != 0)
				cout << c;
			else cout << "  ";
		}
		switch (theCon.sense()->sense())
		{
			case CSense::Less: cout << "<" << "\n"; break;
			case CSense::Greater: cout << ">" << "\n"; break;
			case CSense::Equal: cout << "=" << "\n"; break;
			default: cout << "doesn't make any sense \n"; break;
		}//switch
		float fl;
		while(!(std::cin >> fl))
		{
			std::cin.clear();
			std::cin.ignore(numeric_limits<streamsize>::max(),'\n');
		}
	}*/
}//writeportaieq
Esempio n. 23
0
void SubgraphUpwardPlanarizer::merge(
	const GraphCopy &GC,
	UpwardPlanRep &UPR_res,
	const GraphCopy &block,
	UpwardPlanRep &UPR)
{
	node startUPR = UPR.getSuperSource()->firstAdj()->theEdge()->target();
	node startRes;

	node startG = GC.original(block.original(UPR.original(startUPR)));

	bool empty = UPR_res.empty();

	if (empty) {

		OGDF_ASSERT(startG == 0);

		// contruct a node in UPR_res assocciated with startUPR
		startRes = UPR_res.newNode();
		UPR_res.m_isSinkArc.init(UPR_res, false);
		UPR_res.m_isSourceArc.init(UPR_res, false);
		UPR_res.s_hat = startRes;
	}
	else {
		startRes = UPR_res.copy(startG);
	}

	OGDF_ASSERT(startRes != 0);

	// compute the adjEntry position (in UPR_res) of the cutvertex startRes
	adjEntry pos = nullptr;
	if (!empty) {
		adjEntry adj_ext = nullptr, adj_int = nullptr;
		for(adjEntry run : startRes->adjEntries) {
			if (UPR_res.getEmbedding().rightFace(run) == UPR_res.getEmbedding().externalFace()) {
				adj_ext = run;
				break;
			}
			if (run->theEdge()->source() == startRes)
				adj_int = run;
		}
		// cutvertex is a sink in UPR_res
		if (adj_ext == nullptr && adj_int == nullptr) {
			pos = UPR_res.sinkSwitchOf(startRes);
		}
		else {
			if (adj_ext == nullptr)
				pos = adj_int;
			else
				pos = adj_ext;
		}
		OGDF_ASSERT(pos != 0);
	}

	// construct for each node (except the two super sink and the super source) of UPR a associated of UPR to UPR_res
	NodeArray<node> nodeUPR2UPR_res(UPR, nullptr);
	nodeUPR2UPR_res[startUPR] = startRes;
	for(node v : UPR.nodes) {

		// allready constructed or is super sink or super source
		if (v == startUPR || v == UPR.getSuperSink() || v == UPR.getSuperSink()->firstAdj()->theEdge()->source() || v == UPR.getSuperSource())
			continue;

		node vNew;
		if (UPR.original(v) != nullptr ) {
			node vG = GC.original(block.original((UPR.original(v))));
			if (vG != nullptr)
				vNew = UPR_res.newNode(vG);
			else
				vNew = UPR_res.newNode(); //vG is the super source
		}
		else // crossing dummy, no original node
			vNew = UPR_res.newNode();
		nodeUPR2UPR_res[v] = vNew;
	}

	//add edges of UPR to UPR_res
	EdgeArray<edge> edgeUPR2UPR_res(UPR, nullptr);
	for(edge e : block.edges) {

		if (e->source()->indeg()==0) // the artificial edge with the super source
			continue;

		List<edge> chains = UPR.chain(e);
		edge eG = nullptr, eGC = block.original(e);
		eG = GC.original(eGC);

		OGDF_ASSERT(!chains.empty());

		//construct new edges in UPR_res
		for(edge eChain : chains) {
			node tgt = nodeUPR2UPR_res[eChain->target()];
			node src = nodeUPR2UPR_res[eChain->source()];
			edge eNew = UPR_res.newEdge(src, tgt);
			edgeUPR2UPR_res[eChain] = eNew;

			if (UPR.isSinkArc(UPR.copy(e)))
				UPR_res.m_isSinkArc[eNew] = true;
			if (UPR.isSourceArc(UPR.copy(e)))
				UPR_res.m_isSourceArc[eNew] = true;

			if (eG == nullptr) { // edge is associated with a sink arc
				UPR_res.m_eOrig[eNew] = nullptr;
				continue;
			}

			UPR_res.m_eOrig[eNew] = eG;
			if (chains.size() == 1) { // e is not split
				UPR_res.m_eCopy[eG].pushBack(eNew);
				UPR_res.m_eIterator[eNew] = UPR_res.m_eCopy[eG].begin();
				break;
			}
			UPR_res.m_eCopy[eG].pushBack(eNew);
			UPR_res.m_eIterator[eNew] = UPR_res.m_eCopy[eG].rbegin();
		}
	}


	///*
	//* embed the new component in UPR_res with respect to the embedding of UPR
	//*/

	// for the cut vertex
	if (!empty) {
		adjEntry run = UPR.getAdjEntry(UPR.getEmbedding(), startUPR, UPR.getEmbedding().externalFace());
		run = run->cyclicSucc();
		adjEntry adjStart = run;
		do {
			if (edgeUPR2UPR_res[run->theEdge()] != nullptr) {
				adjEntry adj_UPR_res = edgeUPR2UPR_res[run->theEdge()]->adjSource();
				UPR_res.moveAdjAfter(adj_UPR_res, pos);
				pos = adj_UPR_res;
			}
			run = run->cyclicSucc();
		} while(run != adjStart);
	}

	for(node v : UPR.nodes) {
		if (v == startUPR && !empty)
			continue;

		node v_UPR_res = nodeUPR2UPR_res[v];
		List<adjEntry> adj_UPR, adj_UPR_res;
		v->allAdjEntries(adj_UPR);

		// convert adj_UPR of v to adj_UPR_res of v_UPR_res
		for(adjEntry adj : adj_UPR) {
			edge e_res = edgeUPR2UPR_res[adj->theEdge()];
			if (e_res == nullptr) // associated edges in UPR_res
				continue;
			adjEntry adj_res = e_res->adjSource();
			if (adj_res->theNode() != v_UPR_res)
				adj_res = adj_res->twin();
			adj_UPR_res.pushBack(adj_res);
		}

		UPR_res.sort(v_UPR_res, adj_UPR_res);
	}

	/*
	//---------------------------------------------------debug
	if (!UPR_res.empty()) {
		GraphAttributes GA_UPR_res(UPR_res, GraphAttributes::nodeGraphics|
				GraphAttributes::edgeGraphics|
				GraphAttributes::nodeColor|
				GraphAttributes::edgeColor|
				GraphAttributes::nodeLabel|
				GraphAttributes::edgeLabel
				);
		GA_UPR_res.setAllHeight(30.0);
		GA_UPR_res.setAllWidth(30.0);
		// label the nodes with their index
		for(node z : GA_UPR_res.constGraph().nodes) {
			GA_UPR_res.label(z) = to_string(z->index());
		}
		GA_UPR_res.writeGML("c:/temp/UPR_res_tmp.gml");
		cout << "UPR_res_tmp faces:";
		UPR_res.outputFaces(UPR_res.getEmbedding());
	}

	GraphAttributes GA_UPR(UPR, GraphAttributes::nodeGraphics|
				GraphAttributes::edgeGraphics|
				GraphAttributes::nodeColor|
				GraphAttributes::edgeColor|
				GraphAttributes::nodeLabel|
				GraphAttributes::edgeLabel
				);
	GA_UPR.setAllHeight(30.0);
	GA_UPR.setAllWidth(30.0);
	// label the nodes with their index
	for(node z : GA_UPR.constGraph().nodes) {
		GA_UPR.label(z) = to_string(z->index());
	}
	GA_UPR.writeGML("c:/temp/UPR_tmp.gml");
	cout << "UPR_tmp faces:";
	UPR.outputFaces(UPR.getEmbedding());
	//end -----------------------------------------------debug
	*/

	// update UPR_res
	UPR_res.initMe();
}
Esempio n. 24
0
void ComponentSplitterLayout::call(GraphAttributes &GA)
{
	// Only do preparations and call if layout is valid
	if (m_secondaryLayout.valid())
	{
		//first we split the graph into its components
		const Graph& G = GA.constGraph();

		NodeArray<int> componentNumber(G);
		int numberOfComponents = connectedComponents(G, componentNumber);
		if (numberOfComponents == 0) {
			return;
		}

		// intialize the array of lists of nodes contained in a CC
		Array<List<node> > nodesInCC(numberOfComponents);

		for(node v : G.nodes)
			nodesInCC[componentNumber[v]].pushBack(v);

		// Create copies of the connected components and corresponding
		// GraphAttributes
		GraphCopy GC;
		GC.createEmpty(G);

		EdgeArray<edge> auxCopy(G);

		for (int i = 0; i < numberOfComponents; i++)
		{
			GC.initByNodes(nodesInCC[i],auxCopy);
			GraphAttributes cGA(GC, GA.attributes());
			//copy information into copy GA
			for(node v : GC.nodes)
			{
				cGA.width(v) = GA.width(GC.original(v));
				cGA.height(v) = GA.height(GC.original(v));
				cGA.x(v) = GA.x(GC.original(v));
				cGA.y(v) = GA.y(GC.original(v));
			}
			// copy information on edges
			if (GA.attributes() & GraphAttributes::edgeDoubleWeight) {
				for (edge e : GC.edges) {
					cGA.doubleWeight(e) = GA.doubleWeight(GC.original(e));
				}
			}
			m_secondaryLayout.get().call(cGA);

			//copy layout information back into GA
			for(node v : GC.nodes)
			{
				node w = GC.original(v);
				if (w != nullptr)
				{
					GA.x(w) = cGA.x(v);
					GA.y(w) = cGA.y(v);
					if (GA.attributes() & GraphAttributes::threeD) {
						GA.z(w) = cGA.z(v);
					}
				}
			}
		}

		// rotate component drawings and call the packer
		reassembleDrawings(GA, nodesInCC);

	}//if valid
}
Esempio n. 25
0
void SchnyderLayout::schnyderEmbedding(
	GraphCopy& GC,
	GridLayout &gridLayout,
	adjEntry adjExternal)
{
	NodeArray<int> &xcoord = gridLayout.x();
	NodeArray<int> &ycoord = gridLayout.y();

	node v;
	List<node> L;						// (un)contraction order
	GraphCopy T = GraphCopy(GC);		// the realizer tree (reverse direction of edges!!!)
	EdgeArray<int> rValues(T);			// the realizer values

	// choose outer face a,b,c
	adjEntry adja;
	if (adjExternal != 0) {
		edge eG  = adjExternal->theEdge();
		edge eGC = GC.copy(eG);
		adja = (adjExternal == eG->adjSource()) ? eGC->adjSource() : eGC->adjTarget();
	}
	else {
		adja = GC.firstEdge()->adjSource();
	}
	adjEntry adjb = adja->faceCyclePred();
	adjEntry adjc = adjb->faceCyclePred();

	node a = adja->theNode();
	node b = adjb->theNode();
	node c = adjc->theNode();

	node a_in_T = T.copy(GC.original(a));
	node b_in_T = T.copy(GC.original(b));
	node c_in_T = T.copy(GC.original(c));

	contract(GC, a, b, c, L);

	realizer(GC, L, a, b, c, rValues, T);

	NodeArray<int>  t1(T);
	NodeArray<int>  t2(T);
	NodeArray<int>  val(T, 1);

	NodeArray<int>  P1(T);
	NodeArray<int>  P3(T);
	NodeArray<int>  v1(T);
	NodeArray<int>  v2(T);

	subtreeSizes(rValues, 1, a_in_T, t1);
	subtreeSizes(rValues, 2, b_in_T, t2);

	prefixSum(rValues, 1, a_in_T, val, P1);
	prefixSum(rValues, 3, c_in_T, val, P3);
	// now Pi  =  depth of all nodes in Tree T(i) (depth[root] = 1)

	prefixSum(rValues, 2, b_in_T, t1, v1);
	// special treatment for a
	v1[a_in_T] = t1[a_in_T];

	/*
	 * v1[v] now is the sum of the
	 * "count of nodes in t1" minus the "subtree size for node x"
	 * for every node x on a path from b to v in t2
	 */

	prefixSum(rValues, 3, c_in_T, t1, val);
	// special treatment for a
	val[a_in_T] = t1[a_in_T];

	/*
	 * val[v] now is the sum of the
	 * "count of nodes in t1" minus the "subtree size for node x"
	 * for every node x on a path from c to v in t3
	 */

	// r1[v]=v1[v]+val[v]-t1[v] is the number of nodes in region 1 from v
	forall_nodes(v, T) {
		// calc v1'
		v1[v] += val[v] - t1[v] - P3[v];
	}
Esempio n. 26
0
void FPPLayout::computeOrder(
	const GraphCopy &G,
	NodeArray<int> &num,
	NodeArray<adjEntry> &e_wp,
	NodeArray<adjEntry> &e_wq,
	adjEntry e_12,
	adjEntry e_2n,
	adjEntry e_n1)
{
	NodeArray<int> num_diag(G, 0);							// number of chords
	// link[v] = Iterator in possible, that points to v (if diag[v] = 0 and outer[v] = TRUE)
	NodeArray<ListIterator<node> > link(G, 0);
	// outer[v] = TRUE <=> v is a node of the actual outer face
	NodeArray<bool> outer(G, false);
	// List of all nodes v with outer[v] = TRUE and diag[v] = 0
	List<node> possible;

	// nodes of the outer triangle (v_1,v_2,v_n)
	node v_1 = e_12->theNode();
	node v_2 = e_2n->theNode();
	node v_n = e_n1->theNode();
	node v_k, wp, wq, u;
	adjEntry e, e2;
	int k;

	// initialization: beginn with outer face (v_1,v_2,v_n)
	// v_n is the only possible node
	num[v_1] = 1;
	num[v_2] = 2;

	outer[v_1] = true;
	outer[v_2] = true;
	outer[v_n] = true;

	link[v_n] = possible.pushBack(v_n);

	e_wq[v_1] = e_n1->twin();
	e_wp[v_2] = e_2n;

	e_wq[v_n] = e_2n->twin();
	e_wp[v_n] = e_n1;

	// select next v_k and delete it
	for (k = G.numberOfNodes(); k >= 3; k--) {
		v_k = possible.popFrontRet();	// select arbitrary node from possible as v_k

		num[v_k] = k;

		// predecessor wp and successor wq from vk in C_k (actual outer face)
		wq = (e_wq [v_k])->twinNode();
		wp = (e_wp [v_k])->twinNode();

		// v_k not in C_k-1 anymore
		outer[v_k] = false;

		// shortfall of a chord?
		if (e_wq[wp]->cyclicSucc()->twinNode() == wq) {   // wp, wq is the only successor of vk in G_k
			// wp, wq loose a chord
			if (--num_diag[wp] == 0) {
				link[wp] = possible.pushBack(wp);
			}
			if (--num_diag[wq] == 0) {
				link[wq] = possible.pushBack(wq);
			}
		}

		// update or initialize e_wq, e_wp
		e_wq[wp] = e_wq[wp]->cyclicSucc();

		e_wp[wq] = e_wp[wq]->cyclicPred();
		e = e_wq[wp];
		for (u = e->twinNode(); u != wq; u = e->twinNode()) {
			outer[u] = true;
			e_wp[u] = e->twin();
			e = e_wq[u] = e_wp[u]->cyclicSucc()->cyclicSucc();

			// search for new chords
			for (e2 = e_wp[u]->cyclicPred(); e2 != e_wq[u]; e2 = e2->cyclicPred()) {
				node w = e2->twinNode();
				if (outer[w] == true) {
					++num_diag[u];
					if (w != v_1 && w != v_2)
						if (++num_diag[w] == 1) possible.del(link[w]);
				}
			}

			if (num_diag[u] == 0) {
				link[u] = possible.pushBack(u);
			}
		}
	}
}
Esempio n. 27
0
//todo: is called only once, but could be sped up the same way as the co-conn check
void MaxCPlanarMaster::clusterConnection(cluster c, GraphCopy &gc, double &upperBoundC) {
	// For better performance, a node array is used to indicate which nodes are contained
	// in the currently considered cluster.
	NodeArray<bool> vInC(gc,false);
	// First check, if the current cluster \a c is a leaf cluster.
	// If so, compute the number of edges that have at least to be added
	// to make the cluster induced graph connected.
	if (c->cCount()==0) { 	//cluster \a c is a leaf cluster
		GraphCopy *inducedC = new GraphCopy((const Graph&)gc);
		List<node> clusterNodes;
		c->getClusterNodes(clusterNodes); // \a clusterNodes now contains all (original) nodes of cluster \a c.
		for (node w : clusterNodes) {
			vInC[gc.copy(w)] = true;
		}

		// Delete all nodes from \a inducedC that do not belong to the cluster,
		// in order to obtain the cluster induced graph.
		node v = inducedC->firstNode();
		while (v!=nullptr)  {
			node w = v->succ();
			if (!vInC[inducedC->original(v)]) inducedC->delNode(v);
			v = w;
		}

		// Determine number of connected components of cluster induced graph.
		//Todo: check could be skipped
		if (!isConnected(*inducedC)) {

			NodeArray<int> conC(*inducedC);
			int nCC = connectedComponents(*inducedC,conC);
			//at least #connected components - 1 edges have to be added.
			upperBoundC -= (nCC-1)*m_largestConnectionCoeff;
		}
		delete inducedC;
	// Cluster \a c is an "inner" cluster. Process all child clusters first.
	} else {	//c->cCount is != 0, process all child clusters first

		for (cluster ci : c->children) {
			clusterConnection(ci, gc, upperBoundC);
		}

		// Create cluster induced graph.
		GraphCopy *inducedC = new GraphCopy((const Graph&)gc);
		List<node> clusterNodes;
		c->getClusterNodes(clusterNodes); //\a clusterNodes now contains all (original) nodes of cluster \a c.
		for (node w : clusterNodes) {
			vInC[gc.copy(w)] = true;
		}
		node v = inducedC->firstNode();
		while (v!=nullptr)  {
			node w = v->succ();
			if (!vInC[inducedC->original(v)]) inducedC->delNode(v);
			v = w;
		}

		// Now collapse each child cluster to one node and determine #connected components of \a inducedC.
		List<node> oChildClusterNodes;
		List<node> cChildClusterNodes;
		for (cluster ci : c->children) {
			ci->getClusterNodes(oChildClusterNodes);
			// Compute corresponding nodes of graph \a inducedC.
			for (node u : oChildClusterNodes) {
				node copy = inducedC->copy(gc.copy(u));
				cChildClusterNodes.pushBack(copy);
			}
			inducedC->collapse(cChildClusterNodes);
			oChildClusterNodes.clear();
			cChildClusterNodes.clear();
		}
		// Now, check \a inducedC for connectivity.
		if (!isConnected(*inducedC)) {

			NodeArray<int> conC(*inducedC);
			int nCC = connectedComponents(*inducedC,conC);
			//at least #connected components - 1 edges have to added.
			upperBoundC -= (nCC-1)*m_largestConnectionCoeff;
		}
		delete inducedC;
	}
}//clusterConnection
Esempio n. 28
0
bool FUPSSimple::constructMergeGraph(GraphCopy &M, adjEntry adj_orig, const List<edge> &orig_edges)
{
	CombinatorialEmbedding Beta(M);

	//set ext. face of Beta
	adjEntry ext_adj = M.copy(adj_orig->theEdge())->adjSource();
	Beta.setExternalFace(Beta.rightFace(ext_adj));

	//*************************** debug ********************************
	/*
	cout << endl << "FUPS : " << endl;
	for(face ff : Beta.faces) {
		cout << "face " << ff->index() << ": ";
		adjEntry adjNext = ff->firstAdj();
		do {
			cout << adjNext->theEdge() << "; ";
			adjNext = adjNext->faceCycleSucc();
		} while(adjNext != ff->firstAdj());
		cout << endl;
	}
	if (Beta.externalFace() != 0)
		cout << "ext. face of the graph is: " << Beta.externalFace()->index() << endl;
	else
		cout << "no ext. face set." << endl;
	*/

	FaceSinkGraph fsg(Beta, M.copy(adj_orig->theNode()));
	SList<node> aug_nodes;
	SList<edge> aug_edges;
	SList<face> fList;
	fsg.possibleExternalFaces(fList); // use this method to call the methode checkForest()
	node v_ext = fsg.faceNodeOf(Beta.externalFace());

	OGDF_ASSERT(v_ext != 0);

	fsg.stAugmentation(v_ext, M, aug_nodes, aug_edges);

	/*
	//------------------------------------debug
	GraphAttributes AG(M, GraphAttributes::nodeGraphics|
						GraphAttributes::edgeGraphics|
						GraphAttributes::nodeColor|
						GraphAttributes::edgeColor|
						GraphAttributes::nodeLabel|
						GraphAttributes::edgeLabel
						);
	// label the nodes with their index
	for(node v : AG.constGraph().nodes) {
		AG.label(v) = to_string(v->index());
	}
	AG.writeGML("c:/temp/MergeFUPS.gml");
	*/


	OGDF_ASSERT(isStGraph(M));

	//add the deleted edges
	for(edge eOrig : orig_edges) {
		node a = M.copy(eOrig->source());
		node b = M.copy(eOrig->target());
		M.newEdge(a, b);
	}
	return (isAcyclic(M));
}
Esempio n. 29
0
void OptimalRanking::doCall(
	const Graph& G,
	NodeArray<int> &rank,
	EdgeArray<bool> &reversed,
	const EdgeArray<int> &length,
	const EdgeArray<int> &costOrig)
{
	MinCostFlowReinelt<int> mcf;

	// construct min-cost flow problem
	GraphCopy GC;
	GC.createEmpty(G);

	// compute connected component of G
	NodeArray<int> component(G);
	int numCC = connectedComponents(G,component);

	// intialize the array of lists of nodes contained in a CC
	Array<List<node> > nodesInCC(numCC);

	for(node v : G.nodes)
		nodesInCC[component[v]].pushBack(v);

	EdgeArray<edge> auxCopy(G);
	rank.init(G);

	for(int i = 0; i < numCC; ++i)
	{
		GC.initByNodes(nodesInCC[i], auxCopy);
		makeLoopFree(GC);

		for(edge e : GC.edges)
			if(reversed[GC.original(e)])
				GC.reverseEdge(e);

		// special cases:
		if(GC.numberOfNodes() == 1) {
			rank[GC.original(GC.firstNode())] = 0;
			continue;
		} else if(GC.numberOfEdges() == 1) {
			edge e = GC.original(GC.firstEdge());
			rank[e->source()] = 0;
			rank[e->target()] = length[e];
			continue;
		}

		EdgeArray<int> lowerBound(GC,0);
		EdgeArray<int> upperBound(GC,mcf.infinity());
		EdgeArray<int> cost(GC);
		NodeArray<int> supply(GC);

		for(edge e : GC.edges)
			cost[e] = -length[GC.original(e)];

		for(node v : GC.nodes) {
			int s = 0;
			edge e;
			forall_adj_edges(e,v) {
				if(v == e->source())
					s += costOrig[GC.original(e)];
				else
					s -= costOrig[GC.original(e)];
			}
			supply[v] = s;
		}

		OGDF_ASSERT(isAcyclic(GC) == true);

		// find min-cost flow
		EdgeArray<int> flow(GC);
		NodeArray<int> dual(GC);
#ifdef OGDF_DEBUG
		bool feasible =
#endif
			mcf.call(GC, lowerBound, upperBound, cost, supply, flow, dual);
		OGDF_ASSERT(feasible);

		for(node v : GC.nodes)
			rank[GC.original(v)] = dual[v];
	}
}
Esempio n. 30
0
void SpringEmbedderFR::call(GraphAttributes &AG)
{
	const Graph &G = AG.constGraph();
	if(G.empty())
		return;

	// all edges straight-line
	AG.clearAllBends();

	GraphCopy GC;
	GC.createEmpty(G);

	// compute connected component of G
	NodeArray<int> component(G);
	int numCC = connectedComponents(G,component);

	// intialize the array of lists of nodes contained in a CC
	Array<List<node> > nodesInCC(numCC);

	node v;
	forall_nodes(v,G)
		nodesInCC[component[v]].pushBack(v);

	EdgeArray<edge> auxCopy(G);
	Array<DPoint> boundingBox(numCC);

	int i;
	for(i = 0; i < numCC; ++i)
	{
		GC.initByNodes(nodesInCC[i],auxCopy);

		GraphCopyAttributes AGC(GC,AG);
		node vCopy;
		forall_nodes(vCopy, GC) {
			node vOrig = GC.original(vCopy);
			AGC.x(vCopy) = AG.x(vOrig);
			AGC.y(vCopy) = AG.y(vOrig);
		}

		// original
		if (initialize(GC, AGC) == true)
		{
			for(int i = 1; i <= m_iterations; i++)
				mainStep(GC, AGC);

		}
		cleanup();
		// end original

		node vFirst = GC.firstNode();
		double minX = AGC.x(vFirst), maxX = AGC.x(vFirst),
			minY = AGC.y(vFirst), maxY = AGC.y(vFirst);

		forall_nodes(vCopy,GC) {
			node v = GC.original(vCopy);
			AG.x(v) = AGC.x(vCopy);
			AG.y(v) = AGC.y(vCopy);

			if(AG.x(v)-AG.width (v)/2 < minX) minX = AG.x(v)-AG.width(v) /2;
			if(AG.x(v)+AG.width (v)/2 > maxX) maxX = AG.x(v)+AG.width(v) /2;
			if(AG.y(v)-AG.height(v)/2 < minY) minY = AG.y(v)-AG.height(v)/2;
			if(AG.y(v)+AG.height(v)/2 > maxY) maxY = AG.y(v)+AG.height(v)/2;
		}