Пример #1
0
//to be called AFTER calling read(G, AG)
bool GmlParser::readAttributedCluster(
	Graph &G,
	ClusterGraph& CG,
	ClusterGraphAttributes& ACG)
{
	OGDF_ASSERT(&CG.constGraph() == &G)


	//now we need the cluster object
	GmlObject *rootObject = m_objectTree;
	for(; rootObject; rootObject = rootObject->m_pBrother)
		if (id(rootObject) == rootClusterPredefKey) break;

	if(rootObject == nullptr)
		return true;

	if (id(rootObject) != rootClusterPredefKey)
	{
		setError("missing rootcluster key");
		return false;
	}

	if (rootObject->m_valueType != gmlListBegin) return false;

	attributedClusterRead(rootObject, CG, ACG);

	return true;
}//readAttributedCluster
Пример #2
0
// write cluster graph structure with clusters
static void write_ogml_graph(const ClusterGraph &C, ostream &os)
{
	GraphIO::indent(os,2) << "<structure>\n";

	write_ogml_graph(C.rootCluster(), 0, os);
	write_ogml_graph_edges(C.constGraph(), os);

	GraphIO::indent(os,2) << "</structure>\n";
}
Пример #3
0
void CPlanarSubClusteredST::call(const ClusterGraph &CG, EdgeArray<bool>& inST)
{
	initialize(CG);
	inST.fill(false);

	//representationsgraphs for every cluster, on clustergraph
	ClusterArray<Graph*> l_clusterRepGraph(CG, nullptr);
	computeRepresentationGraphs(CG, l_clusterRepGraph);

	//now we compute the spanning trees on the representation graphs
	//we should save the selection info on the original edge
	//are statically on the repgraphedges (we only have edge -> repedge
	//information) but
	ClusterArray< EdgeArray<bool> > l_inTree(CG);

	for(cluster c : CG.clusters) {
		l_inTree[c].init(*l_clusterRepGraph[c], false);
		//compute STs
		NodeArray<bool> visited(*l_clusterRepGraph[c], false);
		dfsBuildSpanningTree(l_clusterRepGraph[c]->firstNode(), l_inTree[c], visited);
	}

	OGDF_ASSERT(isConnected(CG.constGraph()));

	//compute the subclustered graph by constructing a spanning tree
	//using only the representation edges used in STs on the repgraphs
	NodeArray<bool> visited(CG, false);

	dfsBuildOriginalST(CG.constGraph().firstNode(),
	                   l_inTree,
	                   inST,
	                   visited);

	//unregister the edgearrays to avoid destructor failure after
	//representation graph deletion
	for(cluster c : CG.clusters) {
		l_inTree[c].init();
	}

	deleteRepresentationGraphs(CG, l_clusterRepGraph);
}
Пример #4
0
// true <=> C is C-connected
bool isCConnected(const ClusterGraph &C)
{
	if(C.constGraph().empty())
		return true;

	Graph G;
	ClusterGraph Cp(C,G);


	cluster root = Cp.rootCluster();
	SListPure<node>   compNodes;
	NodeArray<bool> mark(G,false);
	return cConnectTest(Cp,root,mark,G);
}
Пример #5
0
bool GraphIO::writeDOT(const ClusterGraph &C, std::ostream &out)
{
	const Graph &G = C.constGraph();
	int id = 1;

	// Assign a list of edges for each cluster. Perhaps usage of std::vector
	// here needs reconsideration - vector is fast but usage of STL iterators
	// is ugly without C++11 for-each loop.
	ClusterArray< std::vector<edge> > edgeMap(C);
	for(edge e : G.edges) {
		const node s = e->source(), t = e->target();
		edgeMap[C.commonCluster(s, t)].push_back(e);
	}

	return dot::writeCluster(out, 0, edgeMap, C, nullptr, C.rootCluster(), id);
}
Пример #6
0
ClusterGraph::ClusterGraph(const ClusterGraph &C) :
	GraphObserver(&(C.constGraph())),
	m_lcaSearch(0),
	m_vAncestor(0),
	m_wAncestor(0)
{
	m_clusterIdCount = 0;
	m_postOrderStart = 0;
	m_rootCluster    = 0;

	m_allowEmptyClusters = true;
	m_updateDepth   = false;
	m_depthUpToDate = false;

	m_nClusters = 0;
	m_lcaNumber = 0;

	m_clusterArrayTableSize = C.m_clusterArrayTableSize;
	shallowCopy(C);
}
Пример #7
0
static void writeCluster(
	std::ostream &out, int depth,
	const ClusterGraph &C, const ClusterGraphAttributes *CA, cluster c)
{
	if(C.rootCluster() != c) {
		GraphIO::indent(out, depth) << "<node "
		                            << "id=\"cluster" << c->index() << "\""
		                            << ">\n";
	} else {
		const std::string dir =
			(CA && !CA->directed()) ? "undirected" : "directed";
		GraphIO::indent(out, depth) << "<graph "
		                            << "mode=\"static\""
		                            << "defaultedgetype=\"" << dir << "\""
		                            << ">\n";

		if(CA) {
			defineAttributes(out, depth + 1, *CA);
		}
	}

	GraphIO::indent(out, depth + 1) << "<nodes>\n";

	for(ListConstIterator<cluster> cit = c->cBegin(); cit.valid(); ++cit) {
		writeCluster(out, depth + 2, C, CA, *cit);
	}

	for(ListConstIterator<node> nit = c->nBegin(); nit.valid(); ++nit) {
		writeNode(out, depth + 2, CA, *nit);
	}

	GraphIO::indent(out, depth + 1) << "</nodes>\n";

	if(C.rootCluster() != c) {
		GraphIO::indent(out, depth) << "</node>\n";
	} else {
		writeEdges(out, C.constGraph(), CA);
		GraphIO::indent(out, depth) << "</graph>\n";
	}
}
Пример #8
0
//the clustergraph has to be initialized on G!!,
//no clusters other then root cluster may exist, which holds all nodes
bool GmlParser::readCluster(Graph &G, ClusterGraph& CG)
{
	OGDF_ASSERT(&CG.constGraph() == &G)

	//now we need the cluster object
	GmlObject *rootObject = m_objectTree;
	for(; rootObject; rootObject = rootObject->m_pBrother)
		if (id(rootObject) == rootClusterPredefKey) break;

	//we have to check if the file does really contain clusters
	//otherwise, rootcluster will suffice
	if (rootObject == nullptr) return true;
	if (id(rootObject) != rootClusterPredefKey)
	{
		setError("missing rootcluster key");
		return false;
	}

	if (rootObject->m_valueType != gmlListBegin) return false;

	clusterRead(rootObject, CG);

	return true;
}//read clustergraph
Пример #9
0
void CPlanarSubClusteredST::call(const ClusterGraph& CG,
		EdgeArray<bool>& inST,
		EdgeArray<double>& weight)
{
	initialize(CG);

	//representationsgraphs for every cluster, on clustergraph
	ClusterArray<Graph*> l_clusterRepGraph(CG, nullptr);
	computeRepresentationGraphs(CG, l_clusterRepGraph);

	//Now we compute the spanning trees on the representation graphs
	//are statically on the repgraphedges (we only have edge -> repedge
	//information)
	ClusterArray< EdgeArray<bool> > l_inTree(CG);
	//Weight of the representation edges
	ClusterArray< EdgeArray<double> > l_repWeight(CG);

	//Copy the weight
	for(cluster c : CG.clusters) {
		l_repWeight[c].init(*l_clusterRepGraph[c], 0.0);
	}
	for(edge e : CG.constGraph().edges) {
		l_repWeight[m_allocCluster[e]][m_repEdge[e]] = weight[e];
	}

	for(cluster c : CG.clusters)
	{
		l_inTree[c].init(*l_clusterRepGraph[c], false);
		//compute STs
		computeMinST(*l_clusterRepGraph[c], l_repWeight[c],
			l_inTree[c]);
	}

	OGDF_ASSERT(isConnected(CG.constGraph()));

	//Compute the subclustered graph
	for(edge e : CG.constGraph().edges)
	{
		if (l_inTree[m_allocCluster[e]][m_repEdge[e]])
			inST[e] = true;
		else inST[e] = false;
	}
#ifdef OGDF_DEBUG
	GraphCopy cg(CG.constGraph());
	for(edge e : CG.constGraph().edges)
	{
		if (!inST[e])
			cg.delEdge(cg.copy(e));
	}
	OGDF_ASSERT(isConnected(cg));
	OGDF_ASSERT(cg.numberOfEdges() == cg.numberOfNodes()-1);

#endif
	//unregister the edgearrays to avoid destructor failure after
	//representation graph deletion
	for(cluster c : CG.clusters)
	{
		l_inTree[c].init();
		l_repWeight[c].init();
	}

	deleteRepresentationGraphs(CG, l_clusterRepGraph);
}
Пример #10
0
MaxCPlanarMaster::MaxCPlanarMaster(
	const ClusterGraph &C,
	int heuristicLevel,
	int heuristicRuns,
	double heuristicOEdgeBound,
	int heuristicNPermLists,
	int kuratowskiIterations,
	int subdivisions,
	int kSupportGraphs,
	double kHigh,
	double kLow,
	bool perturbation,
	double branchingGap,
	const char *time,
	bool dopricing,
	bool checkCPlanar,
	int numAddVariables,
	double strongConstraintViolation,
	double strongVariableViolation) : 	Master("MaxCPlanar", true, dopricing, OptSense::Max),
	m_numAddVariables(numAddVariables),
	m_strongConstraintViolation(strongConstraintViolation),
	m_strongVariableViolation(strongVariableViolation),
	m_fastHeuristicRuns(25),
	m_cutConnPool(nullptr),
	m_cutKuraPool(nullptr),
	m_useDefaultCutPool(true),
	m_checkCPlanar(checkCPlanar),
	m_porta(false)
{

	// Reference to the given ClusterGraph and the underlying Graph.
	m_C = &C;
	m_G = &(C.constGraph());
	// Create a copy of the graph as we need to modify it
	m_solutionGraph = new GraphCopy(*m_G);
	// Define the maximum number of variables needed.
	// The actual number needed may be much smaller, so there
	// is room for improvement...
	//ToDo: Just count how many vars are added

	//Max number of edges
	//KK: Check this change, added div 2
	int nComplete = (m_G->numberOfNodes()*(m_G->numberOfNodes()-1)) / 2;
	m_nMaxVars = nComplete;
	//to use less variables in case we have only the root cluster,
	//we temporarily set m_nMaxVars to the number of edges
	if ( (m_C->numberOfClusters() == 1) && (isConnected(*m_G)) )
		m_nMaxVars = m_G->numberOfEdges();

	// Computing the main objective function coefficient for the connection edges.
	//int nConnectionEdges = nComplete - m_G->numberOfEdges();
	m_epsilon = (double)(0.2/(2*(m_G->numberOfNodes())));

	// Setting parameters
	m_nKuratowskiIterations = kuratowskiIterations;
	m_nSubdivisions = subdivisions;
	m_nKuratowskiSupportGraphs = kSupportGraphs;
	m_heuristicLevel = heuristicLevel;
	m_nHeuristicRuns = heuristicRuns;
	m_usePerturbation = perturbation;
	m_kuratowskiBoundHigh = kHigh;
	m_kuratowskiBoundLow = kLow;
	m_branchingGap = branchingGap;
	m_maxCpuTime = new string(time);
	m_heuristicFractionalBound = heuristicOEdgeBound;
	m_nHeuristicPermutationLists = heuristicNPermLists;
	m_mpHeuristic = true;

	// Further settings
	m_nCConsAdded = 0;
	m_nKConsAdded = 0;
	m_solvesLP = 0;
	m_varsInit = 0;
	m_varsAdded = 0;
	m_varsPotential = 0;
	m_varsMax = 0;
	m_varsCut = 0;
	m_varsKura = 0;
	m_varsPrice = 0;
	m_varsBranch = 0;
	m_activeRepairs = 0;
	m_repairStat.init(100);
}
Пример #11
0
void CPlanarSubClusteredGraph::call(const ClusterGraph &CGO,
									EdgeArray<bool>& inSub, //original edges in subgraph?
									List<edge>& leftOver,   //original edges not in subgraph
									EdgeArray<double>& edgeWeight) //prefer lightweight edges
{
	leftOver.clear();

	//we compute a c-planar subclustered graph by calling
	//CPlanarSubClusteredST and then perform reinsertion on
	//a copy of the computed subclustered graph
	//initialize "call-global" info arrays
	//edge status
	const Graph& origG = CGO.constGraph();
	m_edgeStatus.init(origG, 0);

	CPlanarSubClusteredST CPST;
	if (edgeWeight.valid())
		CPST.call(CGO, inSub, edgeWeight);
	else
		CPST.call(CGO, inSub);

	//now construct the copy
	//we should create a clusterGraph copy function that
	//builds a clustergraph upon a subgraph of the
	//original graph, preliminarily use fullcopy and delete edges

	ClusterArray<cluster> clusterCopy(CGO);
	NodeArray<node> nodeCopy(origG);
	EdgeArray<edge> edgeCopy(origG);
	Graph testG;
	ClusterGraph CG(CGO, testG, clusterCopy, nodeCopy, edgeCopy);

	CconnectClusterPlanar CCCP;

	//-------------------------------------
	//perform reinsertion of leftover edges
	//fill list of uninserted edges

	EdgeArray<bool> visited(origG,false);

	//delete the non-ST edges
	edge e;
	forall_edges(e, origG)
	{
		if (!inSub[e])
		{
			leftOver.pushBack(e); //original edges
			testG.delEdge(edgeCopy[e]);
		}//if
	}//foralledges

	//todo: cope with preferred edges
	//simple reinsertion strategy: just iterate over list and test
	ListIterator<edge> itE = leftOver.begin();
	while (itE.valid())
	{
		//testG=CG.getGraph()
		edge newCopy = testG.newEdge(nodeCopy[(*itE)->source()],
											 nodeCopy[(*itE)->target()]);
		edgeCopy[*itE] = newCopy;

		bool cplanar = CCCP.call(CG);


		if (!cplanar)
		{
			testG.delEdge(newCopy);
			itE++;
		}//if
		else
		{
			ListIterator<edge> itDel = itE;
			itE++;
			leftOver.del(itDel);
		}
	}//while

	/*
	ListConstIterator<edge> it;
	for(it = preferedEdges.begin(); it.valid(); ++it)
	{
		edge eG = *it;
		visited[eG] = true;

		edge eH = testG.newEdge(toTestG[eG->source()],toTestG[eG->target()]);

		if (preferedImplyPlanar == false && isPlanar(H) == false) {
			testG.delEdge(eH);
			delEdges.pushBack(eG);
		}
	}
	*/


}//call
Пример #12
0
bool ClusterPlanarity::isClusterPlanar(const ClusterGraph &CG, List<nodePair> &addedEdges) {
	m_optStatus = Master::Optimal;
	// We first check if there is more to do then just checking planarity on the
	// input graph.
	// Simple shortcut: With < 5 vertices, no non-planarity is possible...
	bool result = isPlanar(CG.constGraph());
	if (!result || (CG.numberOfClusters() == 1))
	{
		// Either non-planar or only root cluster exists, which does not restrict c-planarity.
		return result;
	}
	// We first create a copy of input G, and work solely on the copy

	// In case of the sm_new solution method, we partition the graph in
	// independent parts and test them separately
	// For all parts we test until non-c-planar or all tested.
	if (m_solmeth==sm_new)
	{
		// We use the ClusterAnalysis to search for independent bags
		// Here is the idea: We detect all bags that are minimum wrt
		// cluster inclusion (i.e. if a cluster contains a cluster c with
		// a single bag, we don't add the cluster c itself) but do
		// not contain an outeractive vertex wrt to smallest containing cluster
		// (i.e. the cluster used in the definition of bag).
		// The clustered subgraphs induced by these bags can be tested independently,
		// as we can move them freely in the drawing area of their enclosing parent cluster.

		ClusterAnalysis ca(CG, true); //Compute all structures, indyBags too
		// We can solve the c-planarity testing for all indyBags independently,
		// and in case all are c-planar, also our input c-graph is c-planar.
		const int numIndyBags = ca.numberOfIndyBags();
		GraphCopy** theGraphs = new GraphCopy * [numIndyBags]; //Stores copies for the bag graphs.
#ifdef OGDF_DEBUG
		cout << "Number of IndyBags "<<numIndyBags<<"\n";
#endif
		Logger::slout() << "Number of IndyBags "<<numIndyBags<<"\n";
		Array<List<node> > nodesInBag(numIndyBags); //Stores vertices for the bag graphs.
		const Graph & G = CG.constGraph();
		for(node v : G.nodes){
		   nodesInBag[ca.indyBagIndex(v)].pushBack(v);
		}

		for (int i = 0; i < numIndyBags && m_optStatus == Master::Optimal; i++)
		{
			// Create underlying graph
			theGraphs[i] = new GraphCopy();
			theGraphs[i]->createEmpty(G);
			// Judging from the interface and the description, there are two
			// methods in GraphCopy that allow to construct parts based on a
			// set of vertices, initByNodes and initByActiveNodes, where the
			// latter one seems to be appropriate and can be used with an
			// additional 3n work to initialize the NodeArray and mark the vertices.
			// However, even though the former is meant to be used for connected
			// components, it also works for set of connected components, and
			// an independent bag is such a creature.
			EdgeArray<edge> eCopy(G);
			theGraphs[i]->initByNodes(nodesInBag[i], eCopy);
			ClusterGraph bagCG(*theGraphs[i]);
			//node v;
			ClusterArray<List<node> > cNodes(CG);
			ClusterArray<List<cluster> > cChildren(CG);
			ClusterArray<cluster> cCopy(CG);
			// Run through all original vertices and store
			// lists of copies at each cluster that is part of the bag.
			// Note: We should not add an enclosing parent cluster below
			// root, i.e., when the root does only have a single child
			// and no vertices, we delete the child again.
			for(node u : nodesInBag[i])
			{
				cluster ct = CG.clusterOf(u);
				cNodes[ct].pushBack(theGraphs[i]->copy(u));
				// Check if we need to store the parent relation on the path
				// to the root. Indicator is: We have just added the first element.

				while ((ct != CG.rootCluster()) &&
						(cNodes[ct].size() + cChildren[ct].size() == 1))
				{
					cChildren[ct->parent()].pushBack(ct);
					ct = ct->parent();
				}
			}

			// Create cluster structure
			// For each vertex in the indyBag we create the cluster path
			// to the bag root if necessary.

			// Now build the cluster structure top down
			// Lists of root are never both empty
			List<cluster> queue;
			queue.pushBack(ca.indyBagRoot(i));
			cCopy[queue.front()] = bagCG.rootCluster();
			while (!queue.empty())
			{
				cluster c = queue.popFrontRet();

				//vertices are assigned to root by construction
				if (cCopy[c] != bagCG.rootCluster())
				{
					for(node u : cNodes[c])
						bagCG.reassignNode(u, cCopy[c]);
				}

				for(cluster ci : cChildren[c])
				{
					cCopy[ci] = bagCG.newCluster(cCopy[c]);
					queue.pushBack(ci);
				}

			}
#ifdef OGDF_DEBUG
			Logger::slout() << "Created clustered graph for indy bag with "<<theGraphs[i]->numberOfNodes()<< " nodes and "<<
					bagCG.numberOfClusters()<<" clusters\n";
			// Make sure the cluster structure is a rooted tree
			cluster t = bagCG.rootCluster();
			int ccnt = 0;
			List<cluster> cqueue;
			cqueue.pushBack(t);
			while (!cqueue.empty())
			{
				t = cqueue.popFrontRet();
				for(cluster c : t->children) {
					cqueue.pushBack(c);
				}
				ccnt++;
			}
			OGDF_ASSERT(ccnt == bagCG.numberOfClusters());
			string filename = string("IndySubcgraph") + to_string(i) + ".gml";

			ClusterGraphAttributes CGA(bagCG);
			GraphIO::writeGML(CGA, filename);
#endif
			//now the actual test, similar to the one below...
			if (theGraphs[i]->numberOfNodes() > 2) //could even start at 4...
			{
				makeParallelFreeUndirected(*theGraphs[i]); //Could do this while creating copy
				Logger::slout()<< "IndyBag of size n m c"<<theGraphs[i]->numberOfNodes()<< " "<<
						theGraphs[i]->numberOfEdges()<< " "<< bagCG.numberOfClusters()<<"\n";
				List<nodePair> ae;
				//Todo: Add an interface here that allows to transfer bag and
				// activity information to the master, otherwise we have to
				// compute this info twice.
				bool imresult = doTest(bagCG, ae);
	#ifdef OGDF_DEBUG
				Logger::slout() << "IndyBag number "<<i<<" is "<< (imresult ? "" : "non-") <<"c-planar\n";
				Logger::slout() << "Number of edges added for IndyBag: "<<ae.size()<<"\n";
	#endif
				result = result && imresult;
				if (!result) return result;
				for(const nodePair &np : ae) {
					addedEdges.emplaceBack(theGraphs[i]->original(np.v1), theGraphs[i]->original(np.v2));
				}
			}
#ifdef OGDF_DEBUG
			else
			{
				Logger::slout() << "IndyBag number "<<i<<" skipped due to size\n";
			}
#endif
		}//for indy bags

		for (int i = 0; i < numIndyBags; i++)
		{
			delete theGraphs[i];
		}
		delete [] theGraphs;

		// We test consistency by summing up the number of vertices.
	}
	else { //todo: can be joined again, as it is a special case wo cluster analysis
		//otherwise we just make a copy of the whole graph
		Graph G;
		ClusterArray<cluster> clusterCopy(CG);
		NodeArray<node> nodeCopy(CG.constGraph());
		EdgeArray<edge> edgeCopy(CG.constGraph());
		ClusterGraph C(CG,G,clusterCopy, nodeCopy, edgeCopy);
		makeParallelFreeUndirected(G);
		NodeArray<node> nodeOrig(G);
		for(node v : CG.constGraph().nodes)
		{
			nodeOrig[nodeCopy[v]] = v;
		}

		//Could use same list here for both graphs.
		addedEdges.clear();
		List<nodePair> ae;
		result = doTest(C,ae);
		//nodepairs are for the copy, store original nodes here
		for (const nodePair &np : ae) {
			addedEdges.emplaceBack(nodeOrig[np.v1], nodeOrig[np.v2]);
		}
	}

	return result;
}
Пример #13
0
bool ClusterPlanarity::doTest(const ClusterGraph &G,
			List<nodePair> &addedEdges)
{
//	if (m_solmeth==sm_new) return doFastTest(G,addedEdges);
	// We could take care of multiedges, but as long this is
	// not done, we do not allow this.
	OGDF_ASSERT(isParallelFreeUndirected(G)); // Graph has to be simple
#ifdef OGDF_DEBUG
	cout << "Creating new Masterproblem for clustergraph with "<<G.constGraph().numberOfNodes()<<" nodes\n";
#endif
	CP_MasterBase* cplanMaster;
	cplanMaster = new CPlanarityMaster(G,
									 m_heuristicLevel,
									 m_heuristicRuns,
									 m_heuristicOEdgeBound,
									 m_heuristicNPermLists,
									 m_kuratowskiIterations,
									 m_subdivisions,
									 m_kSupportGraphs,
									 m_kuratowskiHigh,
									 m_kuratowskiLow,
									 m_perturbation);
	if (m_solmeth == sm_new)
		static_cast<CPlanarityMaster*>(cplanMaster)->setSearchSpaceShrinking(true);
	else
		static_cast<CPlanarityMaster*>(cplanMaster)->setSearchSpaceShrinking(false);
		//new CPlanarMaster(G,m_heuristicLevel,m_heuristicRuns,m_heuristicOEdgeBound,m_heuristicNPermLists,m_kuratowskiIterations,
		//m_subdivisions,m_kSupportGraphs,m_kuratowskiHigh, m_kuratowskiLow,m_perturbation,m_branchingGap,m_time, m_pricing,
		//m_numAddVariables,m_strongConstraintViolation,m_strongVariableViolation,m_ol);
	cplanMaster->setTimeLimit(m_time.c_str());
	cplanMaster->setPortaFile(m_portaOutput);
	cplanMaster->useDefaultCutPool() = m_defaultCutPool;
#ifdef OGDF_DEBUG
	cout << "Starting Optimization\n";
#endif
	Master::STATUS abastatus;
	try {
		abastatus = cplanMaster->optimize();
	}
	catch (...)
	{
		#ifdef OGDF_DEBUG
		cerr << "ABACUS Optimization failed...\n";
		#endif
	}

	m_optStatus    = abastatus;
	m_totalTime    = getDoubleTime(*cplanMaster->totalTime());
	m_heurTime     = getDoubleTime(*cplanMaster->improveTime());
	m_sepTime      = getDoubleTime(*cplanMaster->separationTime());
	m_lpTime       = getDoubleTime(*cplanMaster->lpTime());
	m_lpSolverTime = getDoubleTime(*cplanMaster->lpSolverTime());
	m_totalWTime   = getDoubleTime(*cplanMaster->totalCowTime());
	m_numKCons     = cplanMaster->addedKConstraints();
	m_numCCons     = cplanMaster->addedCConstraints();
	m_numLPs       = cplanMaster->nLp();
	m_numBCs       = cplanMaster->nSub();
	m_numSubSelected = cplanMaster->nSubSelected();
	m_numVars      = cplanMaster->nMaxVars()-cplanMaster->getNumInactiveVars();
#ifdef OGDF_DEBUG
	m_solByHeuristic = cplanMaster->m_solByHeuristic;
#endif
#ifdef OGDF_DEBUG
	if(cplanMaster->pricing())
		Logger::slout() << "Pricing was ON\n";
	Logger::slout()<<"ABACUS returned with status '"<< Master::STATUS_[abastatus] <<"'\n"<<flush;
#endif

	cplanMaster->getConnectionOptimalSolutionEdges(addedEdges);
	//int addE = addedEdges.size();

#ifdef OGDF_DEBUG
	cout<<"-Number of added edges "<< addedEdges.size()<<"\n";
#endif

	if (m_portaOutput)
	{
		writeFeasible(getPortaFileName(), *cplanMaster, abastatus);
	}

	CP_MasterBase::solutionstate status = cplanMaster->m_solState;

	delete cplanMaster;

	switch (status) {
	case CP_MasterBase::ss_cp: return true; break;
	//Todo: catch and publish errors here
	case CP_MasterBase::ss_ncp: return false; break;
	default: cerr<<"** Undefined optimization result for c-planarity computation **\n"; break;
	}//switch

	return false; //Todo: Throw error here if eg outofmemory etc
}//doTest