void StressMinimization::call(GraphAttributes& GA) { const Graph& G = GA.constGraph(); // if the graph has at most one node nothing to do if (G.numberOfNodes() <= 1) { // make it exception save for(node v : G.nodes) { GA.x(v) = 0; GA.y(v) = 0; } return; } if (m_componentLayout && !isConnected(G)) { OGDF_THROW(PreconditionViolatedException); return; } NodeArray<NodeArray<double> > shortestPathMatrix(G); NodeArray<NodeArray<double> > weightMatrix(G); initMatrices(G, shortestPathMatrix, weightMatrix); // if the edge costs are defined by the attribute copy it to an array and // construct the proper shortest path matrix if (m_hasEdgeCostsAttribute) { if (!GA.has(GraphAttributes::edgeDoubleWeight)) { OGDF_THROW(PreconditionViolatedException); return; } m_avgEdgeCosts = dijkstra_SPAP(GA, shortestPathMatrix); // compute shortest path all pairs } else { m_avgEdgeCosts = m_edgeCosts; bfs_SPAP(G, shortestPathMatrix, m_edgeCosts); } call(GA, shortestPathMatrix, weightMatrix); }
void GmlParser::createObjectTree(istream &is, bool doCheck) { initPredefinedKeys(); m_error = false; m_objectTree = 0; m_is = &is; m_doCheck = doCheck; // indicates more extensive checking // initialize line buffer (note: GML specifies a maximal line length // of 254 characters!) m_rLineBuffer = new char[256]; if (m_rLineBuffer == 0) OGDF_THROW(InsufficientMemoryException); *m_rLineBuffer = '\n'; m_lineBuffer = m_rLineBuffer+1; m_pCurrent = m_pStore = m_lineBuffer; m_cStore = 0; // forces getNextSymbol() to read first line // create object tree m_objectTree = parseList(gmlEOF,gmlListEnd); delete[] m_rLineBuffer; }
void PivotMDS::eigenValueDecomposition( Array<Array<double> >& K, Array<Array<double> >& eVecs, Array<double>& eValues) { randomize(eVecs); const int p = K.size(); double r = 0; for (int i = 0; i < DIMENSION_COUNT; i++) { eValues[i] = normalize(eVecs[i]); } while (r < EPSILON) { if (std::isnan(r) || isinf(r)) { // Throw arithmetic exception (Shouldn't occur // for DIMEMSION_COUNT = 2 OGDF_THROW(AlgorithmFailureException); return; } // remember prev values Array<Array<double> > tmpOld(DIMENSION_COUNT); for (int i = 0; i < DIMENSION_COUNT; i++) { tmpOld[i].init(p); for (int j = 0; j < p; j++) { tmpOld[i][j] = eVecs[i][j]; eVecs[i][j] = 0; } } // multiply matrices for (int i = 0; i < DIMENSION_COUNT; i++) { for (int j = 0; j < p; j++) { for (int k = 0; k < p; k++) { eVecs[i][k] += K[j][k] * tmpOld[i][j]; } } } // orthogonalize for (int i = 0; i < DIMENSION_COUNT; i++) { for (int j = 0; j < i; j++) { double fac = prod(eVecs[j], eVecs[i]) / prod(eVecs[j], eVecs[j]); for (int k = 0; k < p; k++) { eVecs[i][k] -= fac * eVecs[j][k]; } } } // normalize for (int i = 0; i < DIMENSION_COUNT; i++) { eValues[i] = normalize(eVecs[i]); } r = 1; for (int i = 0; i < DIMENSION_COUNT; i++) { // get absolute value (abs only defined for int) double tmp = prod(eVecs[i], tmpOld[i]); if (tmp < 0) { tmp *= -1; } r = min(r, tmp); } } }
String::String(const char *str) { m_length = strlen(str); m_pChar = new char[m_length+1]; if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); ogdf::strcpy(m_pChar,m_length+1,str); }
String::String(size_t maxLen, const char *str) { m_length = maxLen; m_pChar = new char[m_length+1]; if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); ogdf::strncpy(m_pChar, m_length+1, str, m_length); m_pChar[m_length] = '\0'; }
// // C o n s t r u c t o r // DinoLineBuffer::DinoLineBuffer(const char *fileName) : m_pIs(0), m_pLinBuf(0), m_numberOfMostRecentlyReadLine(0), m_inputFileLineCounter(0) { // Open file m_pIs = new ifstream(fileName, ios::in); if (!(*m_pIs)) { DinoTools::reportError("DinoLineBuffer::DinoLineBuffer", __LINE__, "Error opening file!"); } // Create and initialize lineUpdateCountArray m_lineUpdateCountArray = new int[DinoLineBuffer::c_maxNoOfLines]; int i; for (i = 0; i < DinoLineBuffer::c_maxNoOfLines; i++){ m_lineUpdateCountArray[i] = 0; } // Create and initialize line buffer m_pLinBuf = new char[(DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength)]; if (m_pLinBuf == 0) OGDF_THROW(InsufficientMemoryException); for (i = 0; i < DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength; i++){ m_pLinBuf[i] = '0'; } // Read first line if (!m_pIs->eof()){ // Read first line m_pIs->getline(m_pLinBuf, DinoLineBuffer::c_maxLineLength); // Increase inputFileLineCounter ++m_inputFileLineCounter; // Increase updateCount ++(m_lineUpdateCountArray[0]); } // End of file is reached immeadiately else{ // Set eof marker *m_pLinBuf = EOF; } // Set position m_currentPosition.set(0, m_lineUpdateCountArray[0], 0); } // DinoLineBuffer::DinoLineBuffer
// embeds constraint graph such that all sources and sinks lie in a common // face void CompactionConstraintGraphBase::embed() { NodeArray<bool> onExternal(*this,false); const CombinatorialEmbedding &E = *m_pOR; face fExternal = E.externalFace(); for(adjEntry adj : fExternal->entries) onExternal[m_pathNode[adj->theNode()]] = true; // compute lists of sources and sinks SList<node> sources, sinks; for(node v : nodes) { if (onExternal[v]) { if (v->indeg() == 0) sources.pushBack(v); if (v->outdeg() == 0) sinks.pushBack(v); } } // determine super source and super sink node s,t; if (sources.size() > 1) { s = newNode(); for (node v : sources) newEdge(s,v); } else s = sources.front(); if (sinks.size() > 1) { t = newNode(); for (node v : sinks) newEdge(v,t); } else t = sinks.front(); edge st = newEdge(s,t); bool isPlanar = planarEmbed(*this); if (!isPlanar) OGDF_THROW(AlgorithmFailureException); delEdge(st); if (sources.size() > 1) delNode(s); if (sinks.size() > 1) delNode(t); }
String &String::operator =(const char *str) { delete [] m_pChar; m_length = strlen(str); m_pChar = new char[m_length+1]; if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); ogdf::strcpy(m_pChar,m_length+1,str); return *this; }
void String::sprintf(const char *format, ...) { delete [] m_pChar; va_list argList; va_start(argList,format); m_length = ogdf::vsprintf(s_pBuffer,OGDF_STRING_BUFFER_SIZE,format,argList); m_pChar = new char[m_length+1]; if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException); ogdf::strcpy(m_pChar,m_length+1,s_pBuffer); }
void PivotMDS::call(GraphAttributes& GA) { if (!isConnected(GA.constGraph())) { OGDF_THROW_PARAM(PreconditionViolatedException,pvcConnected); return; } if (m_hasEdgeCostsAttribute && !GA.has(GraphAttributes::edgeDoubleWeight)) { OGDF_THROW(PreconditionViolatedException); return; } pivotMDSLayout(GA); }
// // C o n s t r u c t o r // LineBuffer::LineBuffer(istream &is) : m_pIs(&is), m_pLinBuf(0), m_numberOfMostRecentlyReadLine(0), m_inputFileLineCounter(0) { if (!(*m_pIs)) { Logger::slout() << "LineBuffer::LineBuffer: Error opening file!\n"; OGDF_THROW_PARAM(AlgorithmFailureException, afcUnknown); } // Create and initialize lineUpdateCountArray m_lineUpdateCountArray = new int[LineBuffer::c_maxNoOfLines]; int i; for (i = 0; i < LineBuffer::c_maxNoOfLines; i++){ m_lineUpdateCountArray[i] = 0; } // Create and initialize line buffer m_pLinBuf = new char[(LineBuffer::c_maxNoOfLines * LineBuffer::c_maxLineLength)]; if (m_pLinBuf == 0) OGDF_THROW(InsufficientMemoryException); for (i = 0; i < LineBuffer::c_maxNoOfLines * LineBuffer::c_maxLineLength; i++){ m_pLinBuf[i] = '0'; } // Read first line if (!m_pIs->eof()){ // Read first line m_pIs->getline(m_pLinBuf, LineBuffer::c_maxLineLength); // Increase inputFileLineCounter ++m_inputFileLineCounter; // Increase updateCount ++(m_lineUpdateCountArray[0]); } // End of file is reached immeadiately else{ // Set eof marker *m_pLinBuf = EOF; } // Set position m_currentPosition.set(0, m_lineUpdateCountArray[0], 0); } // LineBuffer::LineBuffer
// // C o n s t r u c t o r // DinoXmlScanner::DinoXmlScanner(const char *fileName) { // Create line buffer m_pLineBuffer = new DinoLineBuffer(fileName); // Create current token string m_pCurrentTokenString = new char[DinoLineBuffer::c_maxStringLength]; if (m_pCurrentTokenString == 0) OGDF_THROW(InsufficientMemoryException); for (int i = 0; i < DinoLineBuffer::c_maxStringLength; i++){ m_pCurrentTokenString[i] = '0'; } } // DinoXmlScanner::DinoXmlScanner
void ModularMultilevelMixer::call(MultilevelGraph &MLG) { const Graph &G = MLG.getGraph(); m_errorCode = ercNone; clock_t time = clock(); if ((m_multilevelBuilder.valid() == false || m_initialPlacement.valid() == false) && m_oneLevelLayoutModule.valid() == false) { OGDF_THROW(AlgorithmFailureException); } if (m_fixedEdgeLength > 0.0) { edge e; forall_edges(e,G) { MLG.weight(e, m_fixedEdgeLength); }
void Constraint::generateIndent(char ** indent, const int & indentSize) { // free memory block (INFO: indent must point to an array of chars or to NULL) delete [] *indent; // instantiate array of chars *indent = new char[indentSize + 1]; // if memory couldn't be allocated, we throw an exception if (!*indent) { OGDF_THROW(InsufficientMemoryException); // don't use regular throw! } // fill char array for(int i = 0; i < indentSize; ++i) { (*indent)[i] = INDENTCHAR; } // terminate string (*indent)[indentSize] = '\0'; }
MultilevelGraph::MultilevelGraph() :m_createdGraph(true) { m_G = new Graph(); if(m_G == nullptr) { OGDF_THROW(InsufficientMemoryException); } //replaces layout info stuff below initInternal(); m_nodeAssociations.init(*m_G, 0); m_edgeAssociations.init(*m_G, 0); m_radius.init(*m_G, 1.0); m_weight.init(*m_G, 1.0); initReverseIndizes(); }
MultilevelGraph::MultilevelGraph() :m_createdGraph(false) { m_G = new Graph(); if(m_G == 0) { OGDF_THROW(InsufficientMemoryException); } else { m_createdGraph = true; } m_nodeAssociations.init(*m_G, 0); m_edgeAssociations.init(*m_G, 0); m_x.init(*m_G, 0); m_y.init(*m_G, 0); m_radius.init(*m_G, 1.0); m_weight.init(*m_G, 1.0); initReverseIndizes(); }
String &String::operator +=(const String &str) { size_t oldLength = m_length; char *pOldChar = m_pChar; m_length += str.m_length; m_pChar = new char[m_length+1]; if (m_pChar == 0) { delete [] pOldChar; OGDF_THROW(InsufficientMemoryException); } ogdf::strcpy(m_pChar,m_length+1,pOldChar); ogdf::strcpy(m_pChar+oldLength,m_length+1-oldLength,str.m_pChar); delete [] pOldChar; return *this; }
MultilevelGraph::MultilevelGraph(const String &filename) :m_createdGraph(true) { m_G = new Graph(); if(m_G == 0) { OGDF_THROW(InsufficientMemoryException); } m_nodeAssociations.init(*m_G); m_edgeAssociations.init(*m_G); m_radius.init(*m_G); m_weight.init(*m_G); initInternal(); //GraphAttributes tempGA(*m_G); m_GA->readGML(*m_G, filename); prepareGraphAttributes(*m_GA); importAttributesSimple(*m_GA); initReverseIndizes(); }
MultilevelGraph::MultilevelGraph(GraphAttributes &GA) :m_createdGraph(false) { m_G = new Graph(); if(m_G == 0) { OGDF_THROW(InsufficientMemoryException); } else { m_createdGraph = true; } m_nodeAssociations.init(*m_G); m_edgeAssociations.init(*m_G); m_x.init(*m_G); m_y.init(*m_G); m_radius.init(*m_G); m_weight.init(*m_G); copyFromGraph(GA.constGraph(), m_nodeAssociations, m_edgeAssociations); prepareGraphAttributes(GA); importAttributes(GA); initReverseIndizes(); }
MultilevelGraph::MultilevelGraph(const char *filename) : m_createdGraph(true) { m_G = new Graph(); if(m_G == nullptr) { OGDF_THROW(InsufficientMemoryException); } m_nodeAssociations.init(*m_G); m_edgeAssociations.init(*m_G); m_radius.init(*m_G); m_weight.init(*m_G); initInternal(); #if 0 GraphAttributes tempGA(*m_G); #endif GraphIO::read(*m_GA, *m_G, filename, GraphIO::readGML); prepareGraphAttributes(*m_GA); importAttributesSimple(*m_GA); initReverseIndizes(); }
MultilevelGraph::MultilevelGraph(GraphAttributes &GA) :m_createdGraph(true) { m_G = new Graph(); if(m_G == 0) { OGDF_THROW(InsufficientMemoryException); } //replaces layout info stuff below initInternal(); m_nodeAssociations.init(*m_G); m_edgeAssociations.init(*m_G); m_radius.init(*m_G); m_weight.init(*m_G); copyFromGraph(GA.constGraph(), m_nodeAssociations, m_edgeAssociations); prepareGraphAttributes(GA); importAttributes(GA); initReverseIndizes(); }
MultilevelGraph::MultilevelGraph(istream &is) :m_createdGraph(false) { m_G = new Graph(); if(m_G == 0) { OGDF_THROW(InsufficientMemoryException); } else { m_createdGraph = true; } m_nodeAssociations.init(*m_G); m_edgeAssociations.init(*m_G); m_x.init(*m_G); m_y.init(*m_G); m_radius.init(*m_G); m_weight.init(*m_G); GraphAttributes tempGA(*m_G); tempGA.readGML(*m_G, is); prepareGraphAttributes(tempGA); importAttributesSimple(tempGA); initReverseIndizes(); }
//the call function that lets ClusterPlanarizationLayout compute a layout //for the input using \a weight for the computation of the cluster planar subgraph void ClusterPlanarizationLayout::call( Graph& G, ClusterGraphAttributes& acGraph, ClusterGraph& cGraph, EdgeArray<double>& edgeWeight, bool simpleCConnect) //default true { m_nCrossings = 0; bool subGraph = false; // c-planar subgraph computed? //check some simple cases if (G.numberOfNodes() == 0) return; //------------------------------------------------------------- //we set pointers and arrays to the working graph, which can be //the original or, in the case of non-c-planar input, a copy Graph* workGraph = &G; ClusterGraph* workCG = &cGraph; ClusterGraphAttributes* workACG = &acGraph; //potential copy of original if non c-planar Graph GW; //list of non c-planarity causing edges List<edge> leftEdges; //list of nodepairs to be connected (deleted edges) List<NodePair> leftWNodes; //store some information //original to copy NodeArray<node> resultNode(G); EdgeArray<edge> resultEdge(G); ClusterArray<cluster> resultCluster(cGraph); //copy to original NodeArray<node> orNode(G); EdgeArray<edge> orEdge(G); ClusterArray<cluster> orCluster(cGraph); for(node workv : G.nodes) { resultNode[workv] = workv; //will be set to copy if non-c-planar orNode[workv] = workv; } for(edge worke : G.edges) { resultEdge[worke] = worke; //will be set to copy if non-c-planar orEdge[worke] = worke; } for (cluster workc : cGraph.clusters) { resultCluster[workc] = workc; //will be set to copy if non-c-planar orCluster[workc] = workc; } //----------------------------------------------- //check if instance is clusterplanar and embed it CconnectClusterPlanarEmbed CCPE; //cccp bool cplanar = CCPE.embed(cGraph, G); List<edge> connectEdges; //if the graph is not c-planar, we have to check the reason and to //correct the problem by planarising or inserting connection edges if (!cplanar) { bool connect = false; if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) || (CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) ) { //we insert edges to make the input c-connected makeCConnected(cGraph, G, connectEdges, simpleCConnect); //save edgearray info for inserted edges for(edge e : connectEdges) { resultEdge[e] = e; orEdge[e] = e; } connect = true; CCPE.embed(cGraph, G); if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) || (CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) ) { cerr << "no correct connection made\n"<<flush; OGDF_THROW(AlgorithmFailureException); } }//if not cconnected if ((CCPE.errCode() == CconnectClusterPlanarEmbed::nonPlanar) || (CCPE.errCode() == CconnectClusterPlanarEmbed::nonCPlanar)) { subGraph = true; EdgeArray<bool> inSubGraph(G, false); CPlanarSubClusteredGraph cps; if (edgeWeight.valid()) cps.call(cGraph, inSubGraph, leftEdges, edgeWeight); else cps.call(cGraph, inSubGraph, leftEdges); #ifdef OGDF_DEBUG // for(edge worke : G.edges) { // if (inSubGraph[worke]) // acGraph.strokeColor(worke) = "#FF0000"; // } #endif //--------------------------------------------------------------- //now we delete the copies of all edges not in subgraph and embed //the subgraph (use a new copy) //construct copy workGraph = &GW; workCG = new ClusterGraph(cGraph, GW, resultCluster, resultNode, resultEdge); //---------------------- //reinit original arrays orNode.init(GW, nullptr); orEdge.init(GW, nullptr); orCluster.init(*workCG, nullptr); //set array entries to the appropriate values for (node workv : G.nodes) orNode[resultNode[workv]] = workv; for (edge worke : G.edges) orEdge[resultEdge[worke]] = worke; for (cluster workc : cGraph.clusters) orCluster[resultCluster[workc]] = workc; //---------------------------------------------------- //create new ACG and copy values (width, height, type) workACG = new ClusterGraphAttributes(*workCG, workACG->attributes()); for (node workv : GW.nodes) { //should set same attributes in construction!!! if (acGraph.attributes() & GraphAttributes::nodeType) workACG->type(workv) = acGraph.type(orNode[workv]); workACG->height(workv) = acGraph.height(orNode[workv]); workACG->width(workv) = acGraph.width(orNode[workv]); } if (acGraph.attributes() & GraphAttributes::edgeType) { for (edge worke : GW.edges) { workACG->type(worke) = acGraph.type(orEdge[worke]); //all other attributes are not needed or will be set } } for(edge ei : leftEdges) { edge e = resultEdge[ei]; NodePair np; np.m_src = e->source(); np.m_tgt = e->target(); leftWNodes.pushBack(np); GW.delEdge(e); } CconnectClusterPlanarEmbed CCP; #ifdef OGDF_DEBUG bool subPlanar = #endif CCP.embed(*workCG, GW); OGDF_ASSERT(subPlanar); }//if not planar else { if (!connect) OGDF_THROW_PARAM(PreconditionViolatedException, pvcClusterPlanar); } }//if //if multiple CCs are handled, the connectedges (their copies resp.) //can be deleted here //now CCPE should give us the external face ClusterPlanRep CP(*workACG, *workCG); OGDF_ASSERT(CP.representsCombEmbedding()); const int numCC = CP.numberOfCCs(); //equal to one //preliminary OGDF_ASSERT(numCC == 1); // (width,height) of the layout of each connected component Array<DPoint> boundingBox(numCC); for (int ikl = 0; ikl < numCC; ikl++) { CP.initCC(ikl); CP.setOriginalEmbedding(); OGDF_ASSERT(CP.representsCombEmbedding()) Layout drawing(CP); //m_planarLayouter.get().setOptions(4);//progressive adjEntry ae = nullptr; //internally compute adjEntry for outer face //edges that are reinserted in workGraph (in the same //order as leftWNodes) List<edge> newEdges; m_planarLayouter.get().call(CP, ae, drawing, leftWNodes, newEdges, *workGraph); OGDF_ASSERT(leftWNodes.size()==newEdges.size()) OGDF_ASSERT(leftEdges.size()==newEdges.size()) ListConstIterator<edge> itE = newEdges.begin(); ListConstIterator<edge> itEor = leftEdges.begin(); while (itE.valid()) { orEdge[*itE] = *itEor; ++itE; ++itEor; } //hash index over cluster ids HashArray<int, ClusterPosition> CA; computeClusterPositions(CP, drawing, CA); // copy layout into acGraph // Later, we move nodes and edges in each connected component, such // that no two overlap. for(int i = CP.startNode(); i < CP.stopNode(); ++i) { node vG = CP.v(i); acGraph.x(orNode[vG]) = drawing.x(CP.copy(vG)); acGraph.y(orNode[vG]) = drawing.y(CP.copy(vG)); for(adjEntry adj : vG->adjEdges) { if ((adj->index() & 1) == 0) continue; edge eG = adj->theEdge(); edge orE = orEdge[eG]; if (orE) drawing.computePolylineClear(CP,eG,acGraph.bends(orE)); } }//for //even assignment for all nodes is not enough, we need all clusters for(cluster c : workCG->clusters) { int clNumber = c->index(); //int orNumber = originalClId[c]; cluster orCl = orCluster[c]; if (c != workCG->rootCluster()) { OGDF_ASSERT(CA.isDefined(clNumber)); acGraph.height(orCl) = CA[clNumber].m_height; acGraph.width(orCl) = CA[clNumber].m_width; acGraph.y(orCl) = CA[clNumber].m_miny; acGraph.x(orCl) = CA[clNumber].m_minx; }//if real cluster } // the width/height of the layout has been computed by the planar // layout algorithm; required as input to packing algorithm boundingBox[ikl] = m_planarLayouter.get().getBoundingBox(); }//for connected components //postProcess(acGraph); // // arrange layouts of connected components // Array<DPoint> offset(numCC); m_packer.get().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, edge and cluster by the offset // of its connected component. const Graph::CCsInfo &ccInfo = CP.ccInfo(); for(int i = 0; i < numCC; ++i) { const double dx = offset[i].m_x; const double dy = offset[i].m_y; HashArray<int, bool> shifted(false); // iterate over all nodes in ith CC for(int j = ccInfo.startNode(i); j < ccInfo.stopNode(i); ++j) { node v = ccInfo.v(j); acGraph.x(orNode[v]) += dx; acGraph.y(orNode[v]) += dy; // update cluster positions accordingly //int clNumber = cGraph.clusterOf(orNode[v])->index(); cluster cl = cGraph.clusterOf(orNode[v]); if ((cl->index() > 0) && !shifted[cl->index()]) { acGraph.y(cl) += dy; acGraph.x(cl) += dx; shifted[cl->index()] = true; }//if real cluster for(adjEntry adj : v->adjEdges) { if ((adj->index() & 1) == 0) continue; edge e = adj->theEdge(); //edge eOr = orEdge[e]; if (orEdge[e]) { DPolyline &dpl = acGraph.bends(orEdge[e]); for(DPoint &p : dpl) { p.m_x += dx; p.m_y += dy; } } } }//for nodes }//for numcc while (!connectEdges.empty()) { G.delEdge(connectEdges.popFrontRet()); } if (subGraph) { //originalClId.init(); orCluster.init(); orNode.init(); orEdge.init(); delete workCG; delete workACG; }//if subgraph created acGraph.removeUnnecessaryBendsHV(); }//call
// // p a r s e // // Take a look at the state machine of parse() to understand // what is going on here. // // TODO: It seems to be useful that this function throws an exception // if something goes wrong. XmlTagObject *XmlParser::parse() { // Increment recursion depth ++m_recursionDepth; // currentTagObject is the tag object we want to create // in this invocation of parse() XmlTagObject *currentTagObject = 0; // Now we are in the start state of the state machine for( ; ; ) { XmlToken token = m_pScanner->getNextToken(); // Expect "<", otherwise failure if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } // Let's look what comes after "<" token = m_pScanner->getNextToken(); // Read "?", i.e. we have the XML header line <? ... ?> if (token == questionMark) { // Skip until we reach the matching question mark if (!m_pScanner->skipUntil('?')) { reportError("XmlParser::parse", __LINE__, "Could not found the matching '?'", getInputFileLineCounter()); } // Consume ">", otherwise failure token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // Go to start state of the state machine continue; } // end of Read "?" // Read "!", i.e. we have a XML comment <!-- bla --> if (token == exclamationMark) { // A preambel comment <!lala > which could be also nested if ((m_pScanner->getNextToken() != minus) || (m_pScanner->getNextToken() != minus)) { if (!m_pScanner->skipUntilMatchingClosingBracket()) { reportError("XmlParser::parse", __LINE__, "Could not find closing comment bracket!", getInputFileLineCounter()); } continue; } // Find end of comment bool endOfCommentFound = false; while (!endOfCommentFound) { // Skip until we find a - (and skip over it) if (!m_pScanner->skipUntil('-', true)) { reportError("XmlParser::parse", __LINE__, "Closing --> of comment not found!", getInputFileLineCounter()); } // The next characters must be -> (note that one minus is already consumed) if ((m_pScanner->getNextToken() == minus) && (m_pScanner->getNextToken() == closingBracket)) { endOfCommentFound = true; } } // while // Go to start state of the state machine continue; } // end of Read "!" // We have found an identifier, i.e. a tag name if (token == identifier) { // Get hash element of token string HashedString *tagName = hashString(m_pScanner->getCurrentTokenString()); // Create new tag object currentTagObject = new XmlTagObject(tagName); if (currentTagObject == 0) { OGDF_THROW(InsufficientMemoryException); } //push (opening) tagName to stack m_tagObserver.push(tagName->key()); // set depth of current tag object currentTagObject->setDepth(m_recursionDepth); // set line of the tag object in the parsed xml document currentTagObject->setLine(getInputFileLineCounter()); // Next token token = m_pScanner->getNextToken(); // Again we found an identifier, so it must be an attribute if (token == identifier) { // Read list of attributes do { // Save the attribute name HashedString *attributeName = hashString(m_pScanner->getCurrentTokenString()); // Consume "=", otherwise failure token = m_pScanner->getNextToken(); if (token != equalSign) { reportError("XmlParser::parse", __LINE__, "Equal Sign expected!", getInputFileLineCounter()); } // Read value token = m_pScanner->getNextToken(); if ((token != quotedValue) && (token != identifier) && (token != attributeValue)) { reportError("XmlParser::parse", __LINE__, "No valid attribute value!", getInputFileLineCounter()); } // Create a new XmlAttributeObject XmlAttributeObject *currentAttributeObject = new XmlAttributeObject(attributeName, hashString(m_pScanner->getCurrentTokenString())); if (currentAttributeObject == 0) { OGDF_THROW(InsufficientMemoryException); } // Append attribute to attribute list of the current tag object appendAttributeObject(currentTagObject, currentAttributeObject); // Get next token token = m_pScanner->getNextToken(); } while (token == identifier); } // Found an identifier of an attribute // Read "/", i.e. the tag is ended immeadiately, e.g. // <A ... /> without a closing tag </A> if (token == slash) { // Consume ">", otherwise failure token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // The tag is closed and ended so we return string s = m_tagObserver.pop(); --m_recursionDepth; return currentTagObject; } // end of Read "/" // Read ">", i.e. the tag is closed and we // expect some content if (token == closingBracket) { // We read something different from "<", so we have to // deal with a tag value now, i.e. a string inbetween the // opening and the closing tag, e.g. <A ...> lalala </A> if (m_pScanner->testNextToken() != openingBracket) { // Read the characters until "<" is reached and put them into // currentTagObject m_pScanner->readStringUntil('<'); currentTagObject->m_pTagValue = hashString(m_pScanner->getCurrentTokenString()); // We expect a closing tag now, i.e. </id> token = m_pScanner->getNextToken(); if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != slash) { reportError("XmlParser::parse", __LINE__, "Slash expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != identifier) { reportError("XmlParser::parse", __LINE__, "Identifier expected!", getInputFileLineCounter()); } // next token is the closing tag string nextTag(m_pScanner->getCurrentTokenString()); // pop corresponding tag from stack string s = m_tagObserver.pop(); // compare the two tags if (s != nextTag) { // the closing tag doesn't correspond to the opening tag: reportError("XmlParser::parse", __LINE__, "wrong closing tag!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // The tag is closed so we return --m_recursionDepth; return currentTagObject; } // end of read something different from "<" // Found "<", so a (series of) new tag begins and we have to perform // recursive invocation of parse() // // There are two exceptions: // - a slash follows afer <, i.e. we have a closing tag // - an exclamation mark follows after <, i.e. we have a comment while (m_pScanner->testNextToken() == openingBracket) { // Leave the while loop if a closing tag occurs if (m_pScanner->testNextNextToken() == slash) { break; } // Ignore comments if (m_pScanner->testNextNextToken() == exclamationMark) { // Comment must start with <!-- if ((m_pScanner->getNextToken() != openingBracket) || (m_pScanner->getNextToken() != exclamationMark) || (m_pScanner->getNextToken() != minus) || (m_pScanner->getNextToken() != minus)) { reportError("XmlParser::parse", __LINE__, "Comment must start with <!--", getInputFileLineCounter()); } // Find end of comment bool endOfCommentFound = false; while (!endOfCommentFound) { // Skip until we find a - (and skip over it) if (!m_pScanner->skipUntil('-', true)) { reportError("XmlParser::parse", __LINE__, "Closing --> of comment not found!", getInputFileLineCounter()); } // The next characters must be -> (note that one minus is already consumed) if ((m_pScanner->getNextToken() == minus) && (m_pScanner->getNextToken() == closingBracket)) { endOfCommentFound = true; } } // while // Proceed with outer while loop continue; } // Ignore comments // The new tag object is a son of the current tag object XmlTagObject *sonTagObject = parse(); appendSonTagObject(currentTagObject, sonTagObject); } // while // Now we have found all tags. // We expect a closing tag now, i.e. </id> token = m_pScanner->getNextToken(); if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != slash) { reportError("XmlParser::parse", __LINE__, "Slash expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != identifier) { reportError("XmlParser::parse", __LINE__, "Identifier expected!", getInputFileLineCounter()); } // next token is the closing tag string nextTag(m_pScanner->getCurrentTokenString()); // pop corresponding tag from stack string s = m_tagObserver.pop(); // compare the two tags if (s != nextTag) { // the closing tag doesn't correspond to the opening tag: reportError("XmlParser::parse", __LINE__, "wrong closing tag!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } --m_recursionDepth; // check if Document contains code after the last closing bracket if (m_recursionDepth == 0) { token = m_pScanner->getNextToken(); if (token != endOfFile) { reportError("XmlParser::parse", __LINE__, "Document contains code after the last closing bracket!", getInputFileLineCounter()); } } return currentTagObject; } // end of Read ">" OGDF_ASSERT(false) //continue; } // end of found identifier OGDF_ASSERT(false) } // end of while (true)
GmlObject *GmlParser::parseList(GmlObjectType closingKey, GmlObjectType /* errorKey */) { GmlObject *firstSon = nullptr; GmlObject **pPrev = &firstSon; for( ; ; ) { GmlObjectType symbol = getNextSymbol(); if (symbol == closingKey || symbol == gmlError) return firstSon; if (symbol != gmlKey) { setError("key expected"); return firstSon; } GmlKey key = m_keySymbol; symbol = getNextSymbol(); GmlObject *object = nullptr; switch (symbol) { case gmlIntValue: object = OGDF_NEW GmlObject(key,m_intSymbol); break; case gmlDoubleValue: object = OGDF_NEW GmlObject(key,m_doubleSymbol); break; case gmlStringValue: { size_t len = strlen(m_stringSymbol)+1; char *pChar = new char[len]; if (pChar == nullptr) OGDF_THROW(InsufficientMemoryException); strcpy(pChar,m_stringSymbol); object = OGDF_NEW GmlObject(key,pChar); } break; case gmlListBegin: object = OGDF_NEW GmlObject(key); object->m_pFirstSon = parseList(gmlListEnd,gmlEOF); break; case gmlListEnd: setError("unexpected end of list"); return firstSon; case gmlKey: setError("unexpected key"); return firstSon; case gmlEOF: setError("missing value"); return firstSon; case gmlError: return firstSon; OGDF_NODEFAULT // one of the cases above has to occur } *pPrev = object; pPrev = &object->m_pBrother; } return firstSon; }
void MultilevelLayout::call(GraphAttributes &GA, GraphConstraints &GC) { //we assume that both structures work on the same graph OGDF_THROW(AlgorithmFailureException); }
//-------------------------------------------------------------------- // actual algorithm call //-------------------------------------------------------------------- Module::ReturnType FixEdgeInserterCore::call( const Array<edge> &origEdges, bool keepEmbedding, RemoveReinsertType rrPost, double percentMostCrossed) { double T; usedTime(T); Module::ReturnType retValue = Module::retFeasible; m_runsPostprocessing = 0; if(!keepEmbedding) m_pr.embed(); OGDF_ASSERT(m_pr.representsCombEmbedding() == true); if (origEdges.size() == 0) return Module::retOptimal; // nothing to do // initialization CombinatorialEmbedding E(m_pr); // embedding of PG init(E); constructDual(E); // m_delFaces and m_newFaces are used by removeEdge() // if we can't allocate memory for them, we throw an exception if (rrPost != rrNone) { m_delFaces = new FaceSetSimple(E); if (m_delFaces == nullptr) OGDF_THROW(InsufficientMemoryException); m_newFaces = new FaceSetPure(E); if (m_newFaces == nullptr) { delete m_delFaces; OGDF_THROW(InsufficientMemoryException); } // no postprocessing -> no removeEdge() } else { m_delFaces = nullptr; m_newFaces = nullptr; } SListPure<edge> currentOrigEdges; if(rrPost == rrIncremental) { for(edge e : m_pr.edges) currentOrigEdges.pushBack(m_pr.original(e)); } // insertion of edges bool doIncrementalPostprocessing = ( rrPost == rrIncremental || rrPost == rrIncInserted ); for(int i = origEdges.low(); i <= origEdges.high(); ++i) { edge eOrig = origEdges[i]; storeTypeOfCurrentEdge(eOrig); //int eSubGraph = 0; // edgeSubGraphs-data of eOrig //if(edgeSubGraphs!=0) eSubGraph = (*edgeSubGraphs)[eOrig]; SList<adjEntry> crossed; if(m_pCost != nullptr) { findWeightedShortestPath(E, eOrig, crossed); } else { findShortestPath(E, eOrig, crossed); } insertEdge(E, eOrig, crossed); if(doIncrementalPostprocessing) { currentOrigEdges.pushBack(eOrig); bool improved; do { ++m_runsPostprocessing; improved = false; for (edge eOrigRR : currentOrigEdges) { int pathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1); if (pathLength == 0) continue; // cannot improve removeEdge(E, eOrigRR); storeTypeOfCurrentEdge(eOrigRR); // try to find a better insertion path SList<adjEntry> crossed; if(m_pCost != nullptr) { findWeightedShortestPath(E, eOrigRR, crossed); } else { findShortestPath(E, eOrigRR, crossed); } // re-insert edge (insertion path cannot be longer) insertEdge(E, eOrigRR, crossed); int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1); OGDF_ASSERT(newPathLength <= pathLength); if(newPathLength < pathLength) improved = true; } } while (improved); } } if(!doIncrementalPostprocessing) { // postprocessing (remove-reinsert heuristc) const int m = m_pr.original().numberOfEdges(); SListPure<edge> rrEdges; switch(rrPost) { case rrAll: case rrMostCrossed: for(int i = m_pr.startEdge(); i < m_pr.stopEdge(); ++i) rrEdges.pushBack(m_pr.e(i)); break; case rrInserted: for(int i = origEdges.low(); i <= origEdges.high(); ++i) rrEdges.pushBack(origEdges[i]); break; case rrNone: case rrIncremental: case rrIncInserted: break; } // marks the end of the interval of rrEdges over which we iterate // initially set to invalid iterator which means all edges SListConstIterator<edge> itStop; bool improved; do { // abort postprocessing if time limit reached if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { retValue = Module::retTimeoutFeasible; break; } ++m_runsPostprocessing; improved = false; if(rrPost == rrMostCrossed) { FEICrossingsBucket bucket(&m_pr); rrEdges.bucketSort(bucket); const int num = int(0.01 * percentMostCrossed * m); itStop = rrEdges.get(num); } SListConstIterator<edge> it; for(it = rrEdges.begin(); it != itStop; ++it) { edge eOrig = *it; int pathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1); if (pathLength == 0) continue; // cannot improve removeEdge(E, eOrig); storeTypeOfCurrentEdge(eOrig); // try to find a better insertion path SList<adjEntry> crossed; if(m_pCost != nullptr) { findWeightedShortestPath(E, eOrig, crossed); } else { findShortestPath(E, eOrig, crossed); } // re-insert edge (insertion path cannot be longer) insertEdge(E, eOrig, crossed); // we cannot find a shortest path that is longer than before! int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1); OGDF_ASSERT(newPathLength <= pathLength); if(newPathLength < pathLength) improved = true; } } while (improved); } // verify computed planarization OGDF_ASSERT(m_pr.representsCombEmbedding()); // free resources cleanup(); return retValue; }
//--------------------------------------------------------- // actual call (called by all variations of call) // crossing of generalizations is forbidden if forbidCrossingGens = true // edge costs are obeyed if costOrig != 0 // Module::ReturnType FixedEmbeddingInserter::doCall( PlanRep &PG, const List<edge> &origEdges, bool forbidCrossingGens, const EdgeArray<int> *costOrig, const EdgeArray<bool> *forbiddenEdgeOrig, const EdgeArray<unsigned int> *edgeSubGraph) { double T; usedTime(T); ReturnType retValue = retFeasible; m_runsPostprocessing = 0; PG.embed(); OGDF_ASSERT(PG.representsCombEmbedding() == true); if (origEdges.size() == 0) return retOptimal; // nothing to do // initialization CombinatorialEmbedding E(PG); // embedding of PG m_dual.clear(); m_primalAdj.init(m_dual); m_nodeOf.init(E); // construct dual graph m_primalIsGen.init(m_dual,false); OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0); if(forbidCrossingGens) constructDualForbidCrossingGens((const PlanRepUML&)PG,E); else constructDual(PG,E,forbiddenEdgeOrig); // m_delFaces and m_newFaces are used by removeEdge() // if we can't allocate memory for them, we throw an exception if (removeReinsert() != rrNone) { m_delFaces = new FaceSetSimple(E); if (m_delFaces == 0) OGDF_THROW(InsufficientMemoryException); m_newFaces = new FaceSetPure(E); if (m_newFaces == 0) { delete m_delFaces; OGDF_THROW(InsufficientMemoryException); } // no postprocessing -> no removeEdge() } else { m_delFaces = 0; m_newFaces = 0; } SListPure<edge> currentOrigEdges; if(removeReinsert() == rrIncremental) { edge e; forall_edges(e,PG) currentOrigEdges.pushBack(PG.original(e)); } // insertion of edges ListConstIterator<edge> it; for(it = origEdges.begin(); it.valid(); ++it) { edge eOrig = *it; int eSubGraph = 0; // edgeSubGraph-data of eOrig if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig]; SList<adjEntry> crossed; if(costOrig != 0) { findShortestPath(PG, E, *costOrig, PG.copy(eOrig->source()),PG.copy(eOrig->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, crossed, edgeSubGraph, eSubGraph); } else { findShortestPath(E, PG.copy(eOrig->source()),PG.copy(eOrig->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, crossed); } insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig); if(removeReinsert() == rrIncremental) { currentOrigEdges.pushBack(eOrig); bool improved; do { ++m_runsPostprocessing; improved = false; SListConstIterator<edge> itRR; for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR) { edge eOrigRR = *itRR; int pathLength; if(costOrig != 0) pathLength = costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph); else pathLength = PG.chain(eOrigRR).size() - 1; if (pathLength == 0) continue; // cannot improve removeEdge(PG,E,eOrigRR,forbidCrossingGens,forbiddenEdgeOrig); // try to find a better insertion path SList<adjEntry> crossed; if(costOrig != 0) { int eSubGraph = 0; // edgeSubGraph-data of eOrig if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrigRR]; findShortestPath(PG, E, *costOrig, PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association, crossed, edgeSubGraph, eSubGraph); } else { findShortestPath(E, PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association, crossed); } // re-insert edge (insertion path cannot be longer) insertEdge(PG,E,eOrigRR,crossed,forbidCrossingGens,forbiddenEdgeOrig); int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrigRR).size() - 1); OGDF_ASSERT(newPathLength <= pathLength); if(newPathLength < pathLength) improved = true; } } while (improved); } } const Graph &G = PG.original(); if(removeReinsert() != rrIncremental) { // postprocessing (remove-reinsert heuristc) SListPure<edge> rrEdges; switch(removeReinsert()) { case rrAll: case rrMostCrossed: { const List<node> &origInCC = PG.nodesInCC(); ListConstIterator<node> itV; for(itV = origInCC.begin(); itV.valid(); ++itV) { node vG = *itV; adjEntry adj; forall_adj(adj,vG) { if ((adj->index() & 1) == 0) continue; edge eG = adj->theEdge(); rrEdges.pushBack(eG); } } } break; case rrInserted: for(ListConstIterator<edge> it = origEdges.begin(); it.valid(); ++it) rrEdges.pushBack(*it); break; case rrNone: case rrIncremental: break; } // marks the end of the interval of rrEdges over which we iterate // initially set to invalid iterator which means all edges SListConstIterator<edge> itStop; bool improved; do { // abort postprocessing if time limit reached if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) { retValue = retTimeoutFeasible; break; } ++m_runsPostprocessing; improved = false; if(removeReinsert() == rrMostCrossed) { FEICrossingsBucket bucket(&PG); rrEdges.bucketSort(bucket); const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges()); itStop = rrEdges.get(num); } SListConstIterator<edge> it; for(it = rrEdges.begin(); it != itStop; ++it) { edge eOrig = *it; // remove only if crossings on edge; // in especially: forbidden edges are never handled by postprocessing // since there are no crossings on such edges int pathLength; if(costOrig != 0) pathLength = costCrossed(eOrig,PG,*costOrig,edgeSubGraph); else pathLength = PG.chain(eOrig).size() - 1; if (pathLength == 0) continue; // cannot improve removeEdge(PG,E,eOrig,forbidCrossingGens,forbiddenEdgeOrig); // try to find a better insertion path SList<adjEntry> crossed; if(costOrig != 0) { int eSubGraph = 0; // edgeSubGraph-data of eOrig if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig]; findShortestPath(PG, E, *costOrig, PG.copy(eOrig->source()),PG.copy(eOrig->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, crossed, edgeSubGraph, eSubGraph); } else { findShortestPath(E, PG.copy(eOrig->source()),PG.copy(eOrig->target()), forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association, crossed); } // re-insert edge (insertion path cannot be longer) insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig); int newPathLength = (costOrig != 0) ? costCrossed(eOrig,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrig).size() - 1); OGDF_ASSERT(newPathLength <= pathLength); if(newPathLength < pathLength) improved = true; } } while(improved); // iterate as long as we improve }