1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/test/suurballe_test.cc Thu Nov 05 15:50:01 2009 +0100
1.3 @@ -0,0 +1,241 @@
1.4 +/* -*- mode: C++; indent-tabs-mode: nil; -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library.
1.7 + *
1.8 + * Copyright (C) 2003-2009
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +#include <iostream>
1.23 +
1.24 +#include <lemon/list_graph.h>
1.25 +#include <lemon/lgf_reader.h>
1.26 +#include <lemon/path.h>
1.27 +#include <lemon/suurballe.h>
1.28 +#include <lemon/concepts/digraph.h>
1.29 +
1.30 +#include "test_tools.h"
1.31 +
1.32 +using namespace lemon;
1.33 +
1.34 +char test_lgf[] =
1.35 + "@nodes\n"
1.36 + "label\n"
1.37 + "1\n"
1.38 + "2\n"
1.39 + "3\n"
1.40 + "4\n"
1.41 + "5\n"
1.42 + "6\n"
1.43 + "7\n"
1.44 + "8\n"
1.45 + "9\n"
1.46 + "10\n"
1.47 + "11\n"
1.48 + "12\n"
1.49 + "@arcs\n"
1.50 + " length\n"
1.51 + " 1 2 70\n"
1.52 + " 1 3 150\n"
1.53 + " 1 4 80\n"
1.54 + " 2 8 80\n"
1.55 + " 3 5 140\n"
1.56 + " 4 6 60\n"
1.57 + " 4 7 80\n"
1.58 + " 4 8 110\n"
1.59 + " 5 7 60\n"
1.60 + " 5 11 120\n"
1.61 + " 6 3 0\n"
1.62 + " 6 9 140\n"
1.63 + " 6 10 90\n"
1.64 + " 7 1 30\n"
1.65 + " 8 12 60\n"
1.66 + " 9 12 50\n"
1.67 + "10 12 70\n"
1.68 + "10 2 100\n"
1.69 + "10 7 60\n"
1.70 + "11 10 20\n"
1.71 + "12 11 30\n"
1.72 + "@attributes\n"
1.73 + "source 1\n"
1.74 + "target 12\n"
1.75 + "@end\n";
1.76 +
1.77 +// Check the interface of Suurballe
1.78 +void checkSuurballeCompile()
1.79 +{
1.80 + typedef int VType;
1.81 + typedef concepts::Digraph Digraph;
1.82 +
1.83 + typedef Digraph::Node Node;
1.84 + typedef Digraph::Arc Arc;
1.85 + typedef concepts::ReadMap<Arc, VType> LengthMap;
1.86 +
1.87 + typedef Suurballe<Digraph, LengthMap> SuurballeType;
1.88 +
1.89 + Digraph g;
1.90 + Node n;
1.91 + Arc e;
1.92 + LengthMap len;
1.93 + SuurballeType::FlowMap flow(g);
1.94 + SuurballeType::PotentialMap pi(g);
1.95 +
1.96 + SuurballeType suurb_test(g, len);
1.97 + const SuurballeType& const_suurb_test = suurb_test;
1.98 +
1.99 + suurb_test
1.100 + .flowMap(flow)
1.101 + .potentialMap(pi);
1.102 +
1.103 + int k;
1.104 + k = suurb_test.run(n, n);
1.105 + k = suurb_test.run(n, n, k);
1.106 + suurb_test.init(n);
1.107 + k = suurb_test.findFlow(n);
1.108 + k = suurb_test.findFlow(n, k);
1.109 + suurb_test.findPaths();
1.110 +
1.111 + int f;
1.112 + VType c;
1.113 + c = const_suurb_test.totalLength();
1.114 + f = const_suurb_test.flow(e);
1.115 + const SuurballeType::FlowMap& fm =
1.116 + const_suurb_test.flowMap();
1.117 + c = const_suurb_test.potential(n);
1.118 + const SuurballeType::PotentialMap& pm =
1.119 + const_suurb_test.potentialMap();
1.120 + k = const_suurb_test.pathNum();
1.121 + Path<Digraph> p = const_suurb_test.path(k);
1.122 +
1.123 + ignore_unused_variable_warning(fm);
1.124 + ignore_unused_variable_warning(pm);
1.125 +}
1.126 +
1.127 +// Check the feasibility of the flow
1.128 +template <typename Digraph, typename FlowMap>
1.129 +bool checkFlow( const Digraph& gr, const FlowMap& flow,
1.130 + typename Digraph::Node s, typename Digraph::Node t,
1.131 + int value )
1.132 +{
1.133 + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
1.134 + for (ArcIt e(gr); e != INVALID; ++e)
1.135 + if (!(flow[e] == 0 || flow[e] == 1)) return false;
1.136 +
1.137 + for (NodeIt n(gr); n != INVALID; ++n) {
1.138 + int sum = 0;
1.139 + for (OutArcIt e(gr, n); e != INVALID; ++e)
1.140 + sum += flow[e];
1.141 + for (InArcIt e(gr, n); e != INVALID; ++e)
1.142 + sum -= flow[e];
1.143 + if (n == s && sum != value) return false;
1.144 + if (n == t && sum != -value) return false;
1.145 + if (n != s && n != t && sum != 0) return false;
1.146 + }
1.147 +
1.148 + return true;
1.149 +}
1.150 +
1.151 +// Check the optimalitiy of the flow
1.152 +template < typename Digraph, typename CostMap,
1.153 + typename FlowMap, typename PotentialMap >
1.154 +bool checkOptimality( const Digraph& gr, const CostMap& cost,
1.155 + const FlowMap& flow, const PotentialMap& pi )
1.156 +{
1.157 + // Check the "Complementary Slackness" optimality condition
1.158 + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
1.159 + bool opt = true;
1.160 + for (ArcIt e(gr); e != INVALID; ++e) {
1.161 + typename CostMap::Value red_cost =
1.162 + cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
1.163 + opt = (flow[e] == 0 && red_cost >= 0) ||
1.164 + (flow[e] == 1 && red_cost <= 0);
1.165 + if (!opt) break;
1.166 + }
1.167 + return opt;
1.168 +}
1.169 +
1.170 +// Check a path
1.171 +template <typename Digraph, typename Path>
1.172 +bool checkPath( const Digraph& gr, const Path& path,
1.173 + typename Digraph::Node s, typename Digraph::Node t)
1.174 +{
1.175 + TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
1.176 + Node n = s;
1.177 + for (int i = 0; i < path.length(); ++i) {
1.178 + if (gr.source(path.nth(i)) != n) return false;
1.179 + n = gr.target(path.nth(i));
1.180 + }
1.181 + return n == t;
1.182 +}
1.183 +
1.184 +
1.185 +int main()
1.186 +{
1.187 + DIGRAPH_TYPEDEFS(ListDigraph);
1.188 +
1.189 + // Read the test digraph
1.190 + ListDigraph digraph;
1.191 + ListDigraph::ArcMap<int> length(digraph);
1.192 + Node s, t;
1.193 +
1.194 + std::istringstream input(test_lgf);
1.195 + DigraphReader<ListDigraph>(digraph, input).
1.196 + arcMap("length", length).
1.197 + node("source", s).
1.198 + node("target", t).
1.199 + run();
1.200 +
1.201 + // Find 2 paths
1.202 + {
1.203 + Suurballe<ListDigraph> suurballe(digraph, length);
1.204 + check(suurballe.run(s, t) == 2, "Wrong number of paths");
1.205 + check(checkFlow(digraph, suurballe.flowMap(), s, t, 2),
1.206 + "The flow is not feasible");
1.207 + check(suurballe.totalLength() == 510, "The flow is not optimal");
1.208 + check(checkOptimality(digraph, length, suurballe.flowMap(),
1.209 + suurballe.potentialMap()),
1.210 + "Wrong potentials");
1.211 + for (int i = 0; i < suurballe.pathNum(); ++i)
1.212 + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
1.213 + }
1.214 +
1.215 + // Find 3 paths
1.216 + {
1.217 + Suurballe<ListDigraph> suurballe(digraph, length);
1.218 + check(suurballe.run(s, t, 3) == 3, "Wrong number of paths");
1.219 + check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
1.220 + "The flow is not feasible");
1.221 + check(suurballe.totalLength() == 1040, "The flow is not optimal");
1.222 + check(checkOptimality(digraph, length, suurballe.flowMap(),
1.223 + suurballe.potentialMap()),
1.224 + "Wrong potentials");
1.225 + for (int i = 0; i < suurballe.pathNum(); ++i)
1.226 + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
1.227 + }
1.228 +
1.229 + // Find 5 paths (only 3 can be found)
1.230 + {
1.231 + Suurballe<ListDigraph> suurballe(digraph, length);
1.232 + check(suurballe.run(s, t, 5) == 3, "Wrong number of paths");
1.233 + check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
1.234 + "The flow is not feasible");
1.235 + check(suurballe.totalLength() == 1040, "The flow is not optimal");
1.236 + check(checkOptimality(digraph, length, suurballe.flowMap(),
1.237 + suurballe.potentialMap()),
1.238 + "Wrong potentials");
1.239 + for (int i = 0; i < suurballe.pathNum(); ++i)
1.240 + check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
1.241 + }
1.242 +
1.243 + return 0;
1.244 +}