Exemple #1
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();
}
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);
			 }
		 }
Exemple #4
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]);
	}
}
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);
	}
}
Exemple #6
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);
	}
}
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;
}
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;
        }
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
}
Exemple #11
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
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;
		}
Exemple #13
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
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);
		}
Exemple #15
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 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));
}
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();
}
Exemple #18
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];
	}
Exemple #19
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];
	}
}
Exemple #20
0
void GEMLayout::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);

	for(node v : G.nodes)
		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);
		for(node vCopy : GC.nodes) {
			node vOrig = GC.original(vCopy);
			AGC.x(vCopy) = AG.x(vOrig);
			AGC.y(vCopy) = AG.y(vOrig);
		}

		SList<node> permutation;

		// 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;
		for(node v : GC.nodes) {
			m_barycenterX += weight(v) * AGC.x(v);
			m_barycenterY += weight(v) * AGC.y(v);
		}
		m_cos = cos(m_oscillationAngle / 2.0);
		m_sin = sin(Math::pi / 2 + m_rotationAngle / 2.0);

		// main loop
		int counter = m_numberOfRounds;
		while(OGDF_GEOM_ET.greater(m_globalTemperature,m_minimalTemperature) && counter--) {

			// choose nodes by random permutations
			if(permutation.empty()) {
				for(node v : GC.nodes)
					permutation.pushBack(v);
				permutation.permute(m_rng);
			}
			node v = permutation.popFrontRet();

			// compute the impulse of node v
			computeImpulse(GC,AGC,v);

			// update node v
			updateNode(GC,AGC,v);

		}

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

		for(node vCopy : GC.nodes) {
			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;
		}

		minX -= m_minDistCC;
		minY -= m_minDistCC;

		for(node vCopy : GC.nodes) {
			node v = GC.original(vCopy);
			AG.x(v) -= minX;
			AG.y(v) -= minY;
		}

		boundingBox[i] = DPoint(maxX - minX, maxY - minY);
	}

	Array<DPoint> offset(numCC);
	TileToRowsCCPacker packer;
	packer.call(boundingBox,offset,m_pageRatio);

	// The arrangement is given by offset to the origin of the coordinate
	// system. We still have to shift each node and edge by the offset
	// of its connected component.

	for(i = 0; i < numCC; ++i)
	{
		const List<node> &nodes = nodesInCC[i];

		const double dx = offset[i].m_x;
		const double dy = offset[i].m_y;

		// iterate over all nodes in ith CC
		ListConstIterator<node> it;
		for(node v : nodes)
		{
			AG.x(v) += dx;
			AG.y(v) += dy;
		}
	}


	// free node data
	m_impulseX.init();
	m_impulseY.init();
	m_skewGauge.init();
	m_localTemperature.init();
}