void VarEdgeInserterDynCore::ExpandedGraph::constructDual(node s, node t)
	{
		m_dual.clear();

		FaceArray<node> faceNode(m_E);

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

		// construct dual edges (for primal edges in exp)
		for (node v : m_exp.nodes)
		{
			for (adjEntry adj : v->adjEdges)
			{
				// cannot cross edges that does not correspond to real edges
				adjEntry adjG = m_expToG[adj];
				if (adjG == nullptr)
					continue;

				// Do not insert edges into dual if crossing the original edge
				// is forbidden
				if (m_pForbidden &&
					(*m_pForbidden)[m_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;
			}
		}

		// augment dual by m_vS and m_vT
		m_vS = m_dual.newNode();
		if (m_GtoExp[s] != nullptr)
		{
			for (adjEntry adj : m_GtoExp[s]->adjEdges)
				m_dual.newEdge(m_vS, faceNode[m_E.rightFace(adj)]);
		}
		else
		{
			m_dual.newEdge(m_vS, faceNode[m_E.rightFace(m_eS->adjSource())]);
			m_dual.newEdge(m_vS, faceNode[m_E.rightFace(m_eS->adjTarget())]);
		}

		m_vT = m_dual.newNode();
		if (m_GtoExp[t] != nullptr)
		{
			for (adjEntry adj : m_GtoExp[t]->adjEdges)
				m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT);
		}
		else
		{
			m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT);
			m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT);
		}
	}
	void EmbedderOptimalFlexDraw::optimizeOverEmbeddings(
		StaticPlanarSPQRTree &T,
		node parent,
		node mu,
		int bends,
		NodeArray<int> cost[],
		NodeArray<long long> embedding[])
	{
		cost[bends][mu] = numeric_limits<int>::max();
		long long embeddingsCount = T.numberOfNodeEmbeddings(mu);
		for (long long currentEmbedding = 0; currentEmbedding < embeddingsCount; ++currentEmbedding) {

			T.embed(mu, currentEmbedding);

			Skeleton &skeleton = T.skeleton(mu);
			Graph skeletonGraph = skeleton.getGraph();
			ConstCombinatorialEmbedding skeletonEmbedding(skeletonGraph);
			NodeArray<node> vertexNode(skeletonGraph);
			EdgeArray<node> edgeNode(skeletonGraph);
			FaceArray<node> faceNode(skeletonEmbedding);

			Graph N;
			EdgeArray<int> upper(N);
			EdgeArray<int> perUnitCost(N);
			NodeArray<int> supply(N);

			createNetwork(
				parent,
				mu,
				bends,
				cost,
				embedding,
				skeleton,
				edgeNode,
				N,
				upper,
				perUnitCost,
				supply);

			EdgeArray<int> lower(N, 0);
			EdgeArray<int> flow(N);
			NodeArray<int> dual(N);

			m_minCostFlowComputer.get().call(N, lower, upper, perUnitCost, supply, flow, dual);

			int currentCost = 0;
			for (edge e = N.firstEdge(); e != nullptr; e = e->succ())
				currentCost += perUnitCost[e] * flow[e];

			for (adjEntry adj = mu->firstAdj(); adj != nullptr; adj = adj->succ())
				currentCost += cost[0][adj->twinNode()];

			if (currentCost < cost[bends][mu]) {
				cost[bends][mu] = currentCost;
				embedding[bends][mu] = currentEmbedding;
			}
		}
	}
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 EmbedderOptimalFlexDraw::createNetwork(
		node parent,
		node mu,
		int bends,
		NodeArray<int> cost[],
		NodeArray<long long> embedding[],
		Skeleton &skeleton,
		EdgeArray<node> &edgeNode,
		Graph &N,
		EdgeArray<int> &upper,
		EdgeArray<int> &perUnitCost,
		NodeArray<int> &supply)
	{
		Graph skeletonGraph = skeleton.getGraph();
		ConstCombinatorialEmbedding skeletonEmbedding(skeletonGraph);
		NodeArray<node> vertexNode(skeletonGraph);
		FaceArray<node> faceNode(skeletonEmbedding);

		for (node v = skeletonGraph.firstNode(); v != nullptr; v = v->succ()) {
			vertexNode[v] = N.newNode();
			supply[vertexNode[v]] = 4 - skeleton.original(v)->degree() - v->degree();
		}

		if (parent != nullptr) {
			node s = skeleton.referenceEdge()->source();
			node t = skeleton.referenceEdge()->target();
			supply[vertexNode[s]] = 2 - s->degree();
			supply[vertexNode[t]] = 2 - t->degree();
		}

		for (edge e = skeletonGraph.firstEdge(); e != nullptr; e = e->succ()) {
			if (skeleton.isVirtual(e)) {
				edgeNode[e] = N.newNode();
				PertinentGraph H;
				skeleton.owner().pertinentGraph(skeleton.twinTreeNode(e), H);
				node s = H.original(e)->source();
				node t = H.original(e)->target();
				supply[edgeNode[e]] = s->degree() + t->degree() - 2;
			}
		}

		for (face f = skeletonEmbedding.firstFace(); f != nullptr; f = f->succ()) {
			faceNode[f] = N.newNode();
			supply[faceNode[f]] = 4;
		}

		if (parent != nullptr) {
			face f1 = nullptr;
			face f2 = nullptr;
			for (adjEntry adj : skeletonEmbedding.externalFace()->entries) {
				if (adj->theEdge() == skeleton.referenceEdge()) {
					f1 = skeletonEmbedding.rightFace(adj);
					f2 = skeletonEmbedding.leftFace(adj);
					break;
				}
			}
			PertinentGraph H;
			skeleton.owner().pertinentGraph(mu, H);
			node s = skeleton.referenceEdge()->source();
			node t = skeleton.referenceEdge()->target();
			supply[faceNode[f1]] =  H.original(s)->degree() + H.original(t)->degree() - 2 + bends;
			supply[faceNode[f2]] = -bends;
		} else {
			supply[faceNode[skeletonEmbedding.externalFace()]] = -4;
		}

		for (face f = skeletonEmbedding.firstFace(); f != nullptr; f = f->succ()) {
			for (adjEntry adj = f->firstAdj(); adj != nullptr; adj = adj->succ()) {
				edge e1 = N.newEdge(faceNode[f], vertexNode[adj->theNode()]);
				upper[e1] = 1;
				perUnitCost[e1] = 0;
				edge e2 = N.newEdge(vertexNode[adj->theNode()], faceNode[f]);
				upper[e2] = 1;
				perUnitCost[e2] = 0;
			}
		}

		for (face f = skeletonEmbedding.firstFace(); f != nullptr; f = f->succ()) {
			for (adjEntry adj = f->firstAdj(); adj != nullptr; adj = adj->succ()) {
				edge e = N.newEdge(edgeNode[adj->theEdge()], faceNode[f]);
				upper[e] = numeric_limits<int>::max();
				perUnitCost[e] = 0;
			}
		}

		for (face f = skeletonEmbedding.firstFace(); f != nullptr; f = f->succ()) {
			for (adjEntry adj = f->firstAdj(); adj != nullptr; adj = adj->succ()) {
				if (skeleton.isVirtual(adj->theEdge())) {
					node mu = skeleton.twinTreeNode(adj->theEdge());
					edge e0 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e0] = 1;
					perUnitCost[e0] = cost[0][mu];
					edge e1 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e1] = 1;
					perUnitCost[e0] = cost[1][mu] - cost[0][mu];
					edge e2 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e2] = 1;
					perUnitCost[e2] = cost[2][mu] - cost[1][mu];
					edge e3 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e3] = 1;
					perUnitCost[e3] = cost[3][mu] - cost[2][mu];
					for (adjEntry adj= mu->firstAdj(); adj != nullptr; adj = adj->succ()) {
						if (adj->twinNode() != mu) {
							perUnitCost[e0] -= cost[0][adj->twinNode()];
							perUnitCost[e1] -= cost[0][adj->twinNode()];
							perUnitCost[e2] -= cost[0][adj->twinNode()];
							perUnitCost[e3] -= cost[0][adj->twinNode()];
						}
					}
				} else {
					edge e0 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e0] = 1;
					perUnitCost[e0] = m_cost[0][adj->theEdge()];
					edge e1 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e1] = 1;
					perUnitCost[e1] = m_cost[1][adj->theEdge()] - m_cost[0][adj->theEdge()];
					edge e2 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e2] = 1;
					perUnitCost[e2] = m_cost[2][adj->theEdge()] - m_cost[1][adj->theEdge()];
					edge e3 = N.newEdge(faceNode[f], edgeNode[adj->theEdge()]);
					upper[e3] = 1;
					perUnitCost[e3] = m_cost[3][adj->theEdge()] - m_cost[2][adj->theEdge()];
				}
			}
		}
	}
	void VarEdgeInserterDynUMLCore::ExpandedGraphUML::constructDual(node s, node t)
	{
		VarEdgeInserterDynUMLCore::BCandSPQRtreesUML &BC
			= dynamic_cast<VarEdgeInserterDynUMLCore::BCandSPQRtreesUML&>(m_BC);
		m_dual.clear();

		FaceArray<node> faceNode(m_E);

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

#ifdef OGDF_DEBUG
		edge eDual;
#endif
		// construct dual edges (for primal edges in exp)
		for (node v : m_exp.nodes) {
			for (adjEntry adj : v->adjEdges) {
				// cannot cross edges that does not correspond to real edges
				adjEntry adjG = m_expToG[adj];
				if (adjG == nullptr)
					continue;

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

				edge e = m_dual.newEdge(vLeft, vRight);
				m_primalEdge[e] = adj;

				// mark dual edges corresponding to generalizations
				if (adjG && BC.typeOf(adjG->theEdge()) == Graph::generalization)
					m_primalIsGen[e] = true;

				OGDF_ASSERT(m_primalEdge[e] == nullptr || m_expToG[m_primalEdge[e]] != nullptr);
			}
		}

		// augment dual by m_vS and m_vT
		m_vS = m_dual.newNode();
		if (m_GtoExp[s] != nullptr) {
			for (adjEntry adj : m_GtoExp[s]->adjEdges) {
#ifdef OGDF_DEBUG
				eDual =
#endif
				m_dual.newEdge(m_vS, faceNode[m_E.rightFace(adj)]);
				OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);
			}
		} else {
#ifdef OGDF_DEBUG
			eDual =
#endif
			m_dual.newEdge(m_vS, faceNode[m_E.rightFace(m_eS->adjSource())]);
			OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);

#ifdef OGDF_DEBUG
			eDual =
#endif
			m_dual.newEdge(m_vS, faceNode[m_E.rightFace(m_eS->adjTarget())]);
			OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);
		}

		m_vT = m_dual.newNode();
		if (m_GtoExp[t] != nullptr) {
			for (adjEntry adj : m_GtoExp[t]->adjEdges) {
#ifdef OGDF_DEBUG
				eDual =
#endif
				m_dual.newEdge(faceNode[m_E.rightFace(adj)], m_vT);
				OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);
			}
		} else {
#ifdef OGDF_DEBUG
			eDual =
#endif
			m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjSource())], m_vT);
			OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);

#ifdef OGDF_DEBUG
			eDual =
#endif
			m_dual.newEdge(faceNode[m_E.rightFace(m_eT->adjTarget())], m_vT);
			OGDF_ASSERT(m_primalEdge[eDual] == nullptr || m_expToG[m_primalEdge[eDual]] != nullptr);
		}
	}