Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,161 @@
INCLUDE_DIRECTORIES(
${PROJECT_SOURCE_DIR}
${PROJECT_BINARY_DIR}
)
LINK_DIRECTORIES(
${PROJECT_BINARY_DIR}/lemon
)
SET(TEST_WITH_VALGRIND "NO" CACHE STRING
"Run the test with valgrind (YES/NO).")
SET(VALGRIND_FLAGS "" CACHE STRING "Valgrind flags used by the tests.")
SET(TESTS
adaptors_test
arc_look_up_test
bellman_ford_test
bfs_test
bpgraph_test
circulation_test
connectivity_test
counter_test
dfs_test
digraph_test
dijkstra_test
dim_test
edge_set_test
error_test
euler_test
fractional_matching_test
gomory_hu_test
graph_copy_test
graph_test
graph_utils_test
hao_orlin_test
heap_test
kruskal_test
lgf_reader_writer_test
lgf_test
maps_test
matching_test
max_cardinality_search_test
max_clique_test
max_flow_test
min_cost_arborescence_test
min_cost_flow_test
min_mean_cycle_test
nagamochi_ibaraki_test
path_test
planarity_test
radix_sort_test
random_test
suurballe_test
time_measure_test
tsp_test
unionfind_test
)
IF(LEMON_HAVE_LP)
IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
ADD_EXECUTABLE(lp_test lp_test.cc)
ELSE()
ADD_EXECUTABLE(lp_test EXCLUDE_FROM_ALL lp_test.cc)
ENDIF()
SET(LP_TEST_LIBS lemon)
IF(LEMON_HAVE_GLPK)
SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES})
ENDIF()
IF(LEMON_HAVE_CPLEX)
SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${ILOG_LIBRARIES})
ENDIF()
IF(LEMON_HAVE_CLP)
SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES})
ENDIF()
IF(LEMON_HAVE_SOPLEX)
SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${SOPLEX_LIBRARIES})
ENDIF()
TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS})
ADD_TEST(lp_test lp_test)
ADD_DEPENDENCIES(check lp_test)
IF(WIN32 AND LEMON_HAVE_GLPK)
GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
)
ENDIF()
IF(WIN32 AND LEMON_HAVE_CPLEX)
GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH}
)
ENDIF()
ENDIF()
IF(LEMON_HAVE_MIP)
IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
ADD_EXECUTABLE(mip_test mip_test.cc)
ELSE()
ADD_EXECUTABLE(mip_test EXCLUDE_FROM_ALL mip_test.cc)
ENDIF()
SET(MIP_TEST_LIBS lemon)
IF(LEMON_HAVE_GLPK)
SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES})
ENDIF()
IF(LEMON_HAVE_CPLEX)
SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${ILOG_LIBRARIES})
ENDIF()
IF(LEMON_HAVE_CBC)
SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES})
ENDIF()
TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS})
ADD_TEST(mip_test mip_test)
ADD_DEPENDENCIES(check mip_test)
IF(WIN32 AND LEMON_HAVE_GLPK)
GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
)
ENDIF()
IF(WIN32 AND LEMON_HAVE_CPLEX)
GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH}
)
ENDIF()
ENDIF()
FOREACH(TEST_NAME ${TESTS})
IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
ELSE()
ADD_EXECUTABLE(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cc)
ENDIF()
TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
IF(TEST_WITH_VALGRIND)
ADD_TEST(${TEST_NAME}
valgrind --error-exitcode=1 ${VALGRIND_FLAGS}
${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} )
ELSE()
ADD_TEST(${TEST_NAME} ${TEST_NAME})
ENDIF()
ADD_DEPENDENCIES(check ${TEST_NAME})
ENDFOREACH()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include "lemon/list_graph.h"
#include "lemon/lgf_reader.h"
#include "test_tools.h"
using namespace lemon;
const std::string lgf =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"@arcs\n"
"label\n"
"5 6 0\n"
"5 4 1\n"
"4 6 2\n"
"3 4 3\n"
"3 4 4\n"
"3 2 5\n"
"3 5 6\n"
"3 5 7\n"
"3 5 8\n"
"3 5 9\n"
"2 4 10\n"
"2 4 11\n"
"2 4 12\n"
"2 4 13\n"
"1 2 14\n"
"1 2 15\n"
"1 0 16\n"
"1 3 17\n"
"1 3 18\n"
"1 3 19\n"
"1 3 20\n"
"0 2 21\n"
"0 2 22\n"
"0 2 23\n"
"0 2 24\n";
int main() {
ListDigraph graph;
std::istringstream lgfs(lgf);
DigraphReader<ListDigraph>(graph, lgfs).run();
AllArcLookUp<ListDigraph> lookup(graph);
int numArcs = countArcs(graph);
int arcCnt = 0;
for(ListDigraph::NodeIt n1(graph); n1 != INVALID; ++n1)
for(ListDigraph::NodeIt n2(graph); n2 != INVALID; ++n2)
for(ListDigraph::Arc a = lookup(n1, n2); a != INVALID;
a = lookup(n1, n2, a))
++arcCnt;
check(arcCnt==numArcs, "Wrong total number of arcs");
return 0;
}

View File

@@ -0,0 +1,289 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/digraph.h>
#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/bellman_ford.h>
#include <lemon/path.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"@arcs\n"
" length\n"
"0 1 3\n"
"1 2 -3\n"
"1 2 -5\n"
"1 3 -2\n"
"0 2 -1\n"
"1 2 -4\n"
"0 3 2\n"
"4 2 -5\n"
"2 3 1\n"
"@attributes\n"
"source 0\n"
"target 3\n";
void checkBellmanFordCompile()
{
typedef int Value;
typedef concepts::Digraph Digraph;
typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
typedef BellmanFord<Digraph, LengthMap> BF;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
Digraph gr;
Node s, t, n;
Arc e;
Value l;
::lemon::ignore_unused_variable_warning(l);
int k=3;
bool b;
::lemon::ignore_unused_variable_warning(b);
BF::DistMap d(gr);
BF::PredMap p(gr);
LengthMap length;
concepts::Path<Digraph> pp;
{
BF bf_test(gr,length);
const BF& const_bf_test = bf_test;
bf_test.run(s);
bf_test.run(s,k);
bf_test.init();
bf_test.addSource(s);
bf_test.addSource(s, 1);
b = bf_test.processNextRound();
b = bf_test.processNextWeakRound();
bf_test.start();
bf_test.checkedStart();
bf_test.limitedStart(k);
l = const_bf_test.dist(t);
e = const_bf_test.predArc(t);
s = const_bf_test.predNode(t);
b = const_bf_test.reached(t);
d = const_bf_test.distMap();
p = const_bf_test.predMap();
pp = const_bf_test.path(t);
pp = const_bf_test.negativeCycle();
for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {}
}
{
BF::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
::SetDistMap<concepts::ReadWriteMap<Node,Value> >
::SetOperationTraits<BellmanFordDefaultOperationTraits<Value> >
::Create bf_test(gr,length);
LengthMap length_map;
concepts::ReadWriteMap<Node,Arc> pred_map;
concepts::ReadWriteMap<Node,Value> dist_map;
bf_test
.lengthMap(length_map)
.predMap(pred_map)
.distMap(dist_map);
bf_test.run(s);
bf_test.run(s,k);
bf_test.init();
bf_test.addSource(s);
bf_test.addSource(s, 1);
b = bf_test.processNextRound();
b = bf_test.processNextWeakRound();
bf_test.start();
bf_test.checkedStart();
bf_test.limitedStart(k);
l = bf_test.dist(t);
e = bf_test.predArc(t);
s = bf_test.predNode(t);
b = bf_test.reached(t);
pp = bf_test.path(t);
pp = bf_test.negativeCycle();
}
}
void checkBellmanFordFunctionCompile()
{
typedef int Value;
typedef concepts::Digraph Digraph;
typedef Digraph::Arc Arc;
typedef Digraph::Node Node;
typedef concepts::ReadMap<Digraph::Arc,Value> LengthMap;
Digraph g;
bool b;
::lemon::ignore_unused_variable_warning(b);
bellmanFord(g,LengthMap()).run(Node());
b = bellmanFord(g,LengthMap()).run(Node(),Node());
bellmanFord(g,LengthMap())
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,Value>())
.run(Node());
b=bellmanFord(g,LengthMap())
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,Value>())
.path(concepts::Path<Digraph>())
.dist(Value())
.run(Node(),Node());
}
template <typename Digraph, typename Value>
void checkBellmanFord() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
typedef typename Digraph::template ArcMap<Value> LengthMap;
Digraph gr;
Node s, t;
LengthMap length(gr);
std::istringstream input(test_lgf);
digraphReader(gr, input).
arcMap("length", length).
node("source", s).
node("target", t).
run();
BellmanFord<Digraph, LengthMap>
bf(gr, length);
bf.run(s);
Path<Digraph> p = bf.path(t);
check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path.");
check(p.length() == 3, "path() found a wrong path.");
check(checkPath(gr, p), "path() found a wrong path.");
check(pathSource(gr, p) == s, "path() found a wrong path.");
check(pathTarget(gr, p) == t, "path() found a wrong path.");
ListPath<Digraph> path;
Value dist = 0;
bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t);
check(reached && dist == -1, "Bellman-Ford found a wrong path.");
check(path.length() == 3, "path() found a wrong path.");
check(checkPath(gr, path), "path() found a wrong path.");
check(pathSource(gr, path) == s, "path() found a wrong path.");
check(pathTarget(gr, path) == t, "path() found a wrong path.");
for(ArcIt e(gr); e!=INVALID; ++e) {
Node u=gr.source(e);
Node v=gr.target(e);
check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]),
"Wrong output. dist(target)-dist(source)-arc_length=" <<
bf.dist(v) - bf.dist(u) - length[e]);
}
for(NodeIt v(gr); v!=INVALID; ++v) {
if (bf.reached(v)) {
check(v==s || bf.predArc(v)!=INVALID, "Wrong tree.");
if (bf.predArc(v)!=INVALID ) {
Arc e=bf.predArc(v);
Node u=gr.source(e);
check(u==bf.predNode(v),"Wrong tree.");
check(bf.dist(v) - bf.dist(u) == length[e],
"Wrong distance! Difference: " <<
bf.dist(v) - bf.dist(u) - length[e]);
}
}
}
}
void checkBellmanFordNegativeCycle() {
DIGRAPH_TYPEDEFS(SmartDigraph);
SmartDigraph gr;
IntArcMap length(gr);
Node n1 = gr.addNode();
Node n2 = gr.addNode();
Node n3 = gr.addNode();
Node n4 = gr.addNode();
Arc a1 = gr.addArc(n1, n2);
Arc a2 = gr.addArc(n2, n2);
length[a1] = 2;
length[a2] = -1;
{
BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
bf.run(n1);
StaticPath<SmartDigraph> p = bf.negativeCycle();
check(p.length() == 1 && p.front() == p.back() && p.front() == a2,
"Wrong negative cycle.");
}
length[a2] = 0;
{
BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
bf.run(n1);
check(bf.negativeCycle().empty(),
"Negative cycle should not be found.");
}
length[gr.addArc(n1, n3)] = 5;
length[gr.addArc(n4, n3)] = 1;
length[gr.addArc(n2, n4)] = 2;
length[gr.addArc(n3, n2)] = -4;
{
BellmanFord<SmartDigraph, IntArcMap> bf(gr, length);
bf.init();
bf.addSource(n1);
for (int i = 0; i < 4; ++i) {
check(bf.negativeCycle().empty(),
"Negative cycle should not be found.");
bf.processNextRound();
}
StaticPath<SmartDigraph> p = bf.negativeCycle();
check(p.length() == 3, "Wrong negative cycle.");
check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1,
"Wrong negative cycle.");
}
}
int main() {
checkBellmanFord<ListDigraph, int>();
checkBellmanFord<SmartDigraph, double>();
checkBellmanFordNegativeCycle();
return 0;
}

View File

@@ -0,0 +1,239 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/digraph.h>
#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/bfs.h>
#include <lemon/path.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@arcs\n"
" label\n"
"0 1 0\n"
"1 2 1\n"
"2 3 2\n"
"3 4 3\n"
"0 3 4\n"
"0 3 5\n"
"5 2 6\n"
"@attributes\n"
"source 0\n"
"target 4\n";
void checkBfsCompile()
{
typedef concepts::Digraph Digraph;
typedef Bfs<Digraph> BType;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
Digraph G;
Node s, t, n;
Arc e;
int l, i;
::lemon::ignore_unused_variable_warning(l,i);
bool b;
BType::DistMap d(G);
BType::PredMap p(G);
Path<Digraph> pp;
concepts::ReadMap<Node,bool> nm;
{
BType bfs_test(G);
const BType& const_bfs_test = bfs_test;
bfs_test.run(s);
bfs_test.run(s,t);
bfs_test.run();
bfs_test.init();
bfs_test.addSource(s);
n = bfs_test.processNextNode();
n = bfs_test.processNextNode(t, b);
n = bfs_test.processNextNode(nm, n);
n = const_bfs_test.nextNode();
b = const_bfs_test.emptyQueue();
i = const_bfs_test.queueSize();
bfs_test.start();
bfs_test.start(t);
bfs_test.start(nm);
l = const_bfs_test.dist(t);
e = const_bfs_test.predArc(t);
s = const_bfs_test.predNode(t);
b = const_bfs_test.reached(t);
d = const_bfs_test.distMap();
p = const_bfs_test.predMap();
pp = const_bfs_test.path(t);
}
{
BType
::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
::SetDistMap<concepts::ReadWriteMap<Node,int> >
::SetReachedMap<concepts::ReadWriteMap<Node,bool> >
::SetStandardProcessedMap
::SetProcessedMap<concepts::WriteMap<Node,bool> >
::Create bfs_test(G);
concepts::ReadWriteMap<Node,Arc> pred_map;
concepts::ReadWriteMap<Node,int> dist_map;
concepts::ReadWriteMap<Node,bool> reached_map;
concepts::WriteMap<Node,bool> processed_map;
bfs_test
.predMap(pred_map)
.distMap(dist_map)
.reachedMap(reached_map)
.processedMap(processed_map);
bfs_test.run(s);
bfs_test.run(s,t);
bfs_test.run();
bfs_test.init();
bfs_test.addSource(s);
n = bfs_test.processNextNode();
n = bfs_test.processNextNode(t, b);
n = bfs_test.processNextNode(nm, n);
n = bfs_test.nextNode();
b = bfs_test.emptyQueue();
i = bfs_test.queueSize();
bfs_test.start();
bfs_test.start(t);
bfs_test.start(nm);
l = bfs_test.dist(t);
e = bfs_test.predArc(t);
s = bfs_test.predNode(t);
b = bfs_test.reached(t);
pp = bfs_test.path(t);
}
}
void checkBfsFunctionCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef Digraph::Arc Arc;
typedef Digraph::Node Node;
Digraph g;
bool b;
::lemon::ignore_unused_variable_warning(b);
bfs(g).run(Node());
b=bfs(g).run(Node(),Node());
bfs(g).run();
bfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.run(Node());
b=bfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.path(concepts::Path<Digraph>())
.dist(VType())
.run(Node(),Node());
bfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.run();
}
template <class Digraph>
void checkBfs() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node s, t;
std::istringstream input(test_lgf);
digraphReader(G, input).
node("source", s).
node("target", t).
run();
Bfs<Digraph> bfs_test(G);
bfs_test.run(s);
check(bfs_test.dist(t)==2,"Bfs found a wrong path.");
Path<Digraph> p = bfs_test.path(t);
check(p.length()==2,"path() found a wrong path.");
check(checkPath(G, p),"path() found a wrong path.");
check(pathSource(G, p) == s,"path() found a wrong path.");
check(pathTarget(G, p) == t,"path() found a wrong path.");
for(ArcIt a(G); a!=INVALID; ++a) {
Node u=G.source(a);
Node v=G.target(a);
check( !bfs_test.reached(u) ||
(bfs_test.dist(v) <= bfs_test.dist(u)+1),
"Wrong output. " << G.id(u) << "->" << G.id(v));
}
for(NodeIt v(G); v!=INVALID; ++v) {
if (bfs_test.reached(v)) {
check(v==s || bfs_test.predArc(v)!=INVALID, "Wrong tree.");
if (bfs_test.predArc(v)!=INVALID ) {
Arc a=bfs_test.predArc(v);
Node u=G.source(a);
check(u==bfs_test.predNode(v),"Wrong tree.");
check(bfs_test.dist(v) - bfs_test.dist(u) == 1,
"Wrong distance. Difference: "
<< std::abs(bfs_test.dist(v) - bfs_test.dist(u) - 1));
}
}
}
{
NullMap<Node,Arc> myPredMap;
bfs(G).predMap(myPredMap).run(s);
}
}
int main()
{
checkBfs<ListDigraph>();
checkBfs<SmartDigraph>();
return 0;
}

View File

@@ -0,0 +1,456 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/bpgraph.h>
#include <lemon/list_graph.h>
#include <lemon/smart_graph.h>
#include <lemon/full_graph.h>
#include "test_tools.h"
#include "graph_test.h"
using namespace lemon;
using namespace lemon::concepts;
template <class BpGraph>
void checkBpGraphBuild() {
TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
BpGraph G;
checkGraphNodeList(G, 0);
checkGraphRedNodeList(G, 0);
checkGraphBlueNodeList(G, 0);
checkGraphEdgeList(G, 0);
checkGraphArcList(G, 0);
G.reserveNode(3);
G.reserveEdge(3);
RedNode
rn1 = G.addRedNode();
checkGraphNodeList(G, 1);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 0);
checkGraphEdgeList(G, 0);
checkGraphArcList(G, 0);
BlueNode
bn1 = G.addBlueNode(),
bn2 = G.addBlueNode();
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 0);
checkGraphArcList(G, 0);
Edge e1 = G.addEdge(rn1, bn2);
check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge");
check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge");
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 1);
checkGraphArcList(G, 2);
checkGraphIncEdgeArcLists(G, rn1, 1);
checkGraphIncEdgeArcLists(G, bn1, 0);
checkGraphIncEdgeArcLists(G, bn2, 1);
checkGraphConEdgeList(G, 1);
checkGraphConArcList(G, 2);
Edge
e2 = G.addEdge(bn1, rn1),
e3 = G.addEdge(rn1, bn2);
::lemon::ignore_unused_variable_warning(e2,e3);
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
checkGraphIncEdgeArcLists(G, rn1, 3);
checkGraphIncEdgeArcLists(G, bn1, 1);
checkGraphIncEdgeArcLists(G, bn2, 2);
checkGraphConEdgeList(G, 3);
checkGraphConArcList(G, 6);
checkArcDirections(G);
checkNodeIds(G);
checkRedNodeIds(G);
checkBlueNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphRedNodeMap(G);
checkGraphBlueNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
}
template <class BpGraph>
void checkBpGraphErase() {
TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
BpGraph G;
RedNode
n1 = G.addRedNode(), n4 = G.addRedNode();
BlueNode
n2 = G.addBlueNode(), n3 = G.addBlueNode();
Edge
e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3),
e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3);
::lemon::ignore_unused_variable_warning(e1,e3,e4);
// Check edge deletion
G.erase(e2);
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
checkGraphIncEdgeArcLists(G, n1, 1);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphIncEdgeArcLists(G, n3, 1);
checkGraphIncEdgeArcLists(G, n4, 2);
checkGraphConEdgeList(G, 3);
checkGraphConArcList(G, 6);
// Check node deletion
G.erase(n3);
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 1);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
checkGraphIncEdgeArcLists(G, n1, 1);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphIncEdgeArcLists(G, n4, 1);
checkGraphConEdgeList(G, 2);
checkGraphConArcList(G, 4);
}
template <class BpGraph>
void checkBpGraphAlter() {
TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
BpGraph G;
RedNode
n1 = G.addRedNode(), n4 = G.addRedNode();
BlueNode
n2 = G.addBlueNode(), n3 = G.addBlueNode();
Edge
e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3),
e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3);
::lemon::ignore_unused_variable_warning(e1,e3,e4);
G.changeRed(e2, n4);
check(G.redNode(e2) == n4, "Wrong red node");
check(G.blueNode(e2) == n3, "Wrong blue node");
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 4);
checkGraphArcList(G, 8);
checkGraphIncEdgeArcLists(G, n1, 1);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphIncEdgeArcLists(G, n3, 2);
checkGraphIncEdgeArcLists(G, n4, 3);
checkGraphConEdgeList(G, 4);
checkGraphConArcList(G, 8);
G.changeBlue(e2, n2);
check(G.redNode(e2) == n4, "Wrong red node");
check(G.blueNode(e2) == n2, "Wrong blue node");
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 4);
checkGraphArcList(G, 8);
checkGraphIncEdgeArcLists(G, n1, 1);
checkGraphIncEdgeArcLists(G, n2, 3);
checkGraphIncEdgeArcLists(G, n3, 1);
checkGraphIncEdgeArcLists(G, n4, 3);
checkGraphConEdgeList(G, 4);
checkGraphConArcList(G, 8);
}
template <class BpGraph>
void checkBpGraphSnapshot() {
TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
BpGraph G;
RedNode
n1 = G.addRedNode();
BlueNode
n2 = G.addBlueNode(),
n3 = G.addBlueNode();
Edge
e1 = G.addEdge(n1, n2),
e2 = G.addEdge(n1, n3);
::lemon::ignore_unused_variable_warning(e1,e2);
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
typename BpGraph::Snapshot snapshot(G);
RedNode n4 = G.addRedNode();
G.addEdge(n4, n2);
G.addEdge(n4, n3);
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 4);
checkGraphArcList(G, 8);
snapshot.restore();
checkGraphNodeList(G, 3);
checkGraphRedNodeList(G, 1);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 1);
checkGraphIncEdgeArcLists(G, n3, 1);
checkGraphConEdgeList(G, 2);
checkGraphConArcList(G, 4);
checkNodeIds(G);
checkRedNodeIds(G);
checkBlueNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphRedNodeMap(G);
checkGraphBlueNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
G.addRedNode();
snapshot.save(G);
G.addEdge(G.addRedNode(), G.addBlueNode());
snapshot.restore();
snapshot.save(G);
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
G.addEdge(G.addRedNode(), G.addBlueNode());
snapshot.restore();
checkGraphNodeList(G, 4);
checkGraphRedNodeList(G, 2);
checkGraphBlueNodeList(G, 2);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
}
template <typename BpGraph>
void checkBpGraphValidity() {
TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph);
BpGraph g;
RedNode
n1 = g.addRedNode();
BlueNode
n2 = g.addBlueNode(),
n3 = g.addBlueNode();
Edge
e1 = g.addEdge(n1, n2),
e2 = g.addEdge(n1, n3);
::lemon::ignore_unused_variable_warning(e2);
check(g.valid(n1), "Wrong validity check");
check(g.valid(e1), "Wrong validity check");
check(g.valid(g.direct(e1, true)), "Wrong validity check");
check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
}
void checkConcepts() {
{ // Checking graph components
checkConcept<BaseBpGraphComponent, BaseBpGraphComponent >();
checkConcept<IDableBpGraphComponent<>,
IDableBpGraphComponent<> >();
checkConcept<IterableBpGraphComponent<>,
IterableBpGraphComponent<> >();
checkConcept<AlterableBpGraphComponent<>,
AlterableBpGraphComponent<> >();
checkConcept<MappableBpGraphComponent<>,
MappableBpGraphComponent<> >();
checkConcept<ExtendableBpGraphComponent<>,
ExtendableBpGraphComponent<> >();
checkConcept<ErasableBpGraphComponent<>,
ErasableBpGraphComponent<> >();
checkConcept<ClearableBpGraphComponent<>,
ClearableBpGraphComponent<> >();
}
{ // Checking skeleton graph
checkConcept<BpGraph, BpGraph>();
}
{ // Checking SmartBpGraph
checkConcept<BpGraph, SmartBpGraph>();
checkConcept<AlterableBpGraphComponent<>, SmartBpGraph>();
checkConcept<ExtendableBpGraphComponent<>, SmartBpGraph>();
checkConcept<ClearableBpGraphComponent<>, SmartBpGraph>();
}
}
void checkFullBpGraph(int redNum, int blueNum) {
typedef FullBpGraph BpGraph;
BPGRAPH_TYPEDEFS(BpGraph);
BpGraph G(redNum, blueNum);
checkGraphNodeList(G, redNum + blueNum);
checkGraphRedNodeList(G, redNum);
checkGraphBlueNodeList(G, blueNum);
checkGraphEdgeList(G, redNum * blueNum);
checkGraphArcList(G, 2 * redNum * blueNum);
G.resize(redNum, blueNum);
checkGraphNodeList(G, redNum + blueNum);
checkGraphRedNodeList(G, redNum);
checkGraphBlueNodeList(G, blueNum);
checkGraphEdgeList(G, redNum * blueNum);
checkGraphArcList(G, 2 * redNum * blueNum);
for (RedNodeIt n(G); n != INVALID; ++n) {
checkGraphOutArcList(G, n, blueNum);
checkGraphInArcList(G, n, blueNum);
checkGraphIncEdgeList(G, n, blueNum);
}
for (BlueNodeIt n(G); n != INVALID; ++n) {
checkGraphOutArcList(G, n, redNum);
checkGraphInArcList(G, n, redNum);
checkGraphIncEdgeList(G, n, redNum);
}
checkGraphConArcList(G, 2 * redNum * blueNum);
checkGraphConEdgeList(G, redNum * blueNum);
checkArcDirections(G);
checkNodeIds(G);
checkRedNodeIds(G);
checkBlueNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphRedNodeMap(G);
checkGraphBlueNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
for (int i = 0; i < G.redNum(); ++i) {
check(G.red(G.redNode(i)), "Wrong node");
check(G.index(G.redNode(i)) == i, "Wrong index");
}
for (int i = 0; i < G.blueNum(); ++i) {
check(G.blue(G.blueNode(i)), "Wrong node");
check(G.index(G.blueNode(i)) == i, "Wrong index");
}
for (NodeIt u(G); u != INVALID; ++u) {
for (NodeIt v(G); v != INVALID; ++v) {
Edge e = G.edge(u, v);
Arc a = G.arc(u, v);
if (G.red(u) == G.red(v)) {
check(e == INVALID, "Wrong edge lookup");
check(a == INVALID, "Wrong arc lookup");
} else {
check((G.u(e) == u && G.v(e) == v) ||
(G.u(e) == v && G.v(e) == u), "Wrong edge lookup");
check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup");
}
}
}
}
void checkGraphs() {
{ // Checking ListGraph
checkBpGraphBuild<ListBpGraph>();
checkBpGraphErase<ListBpGraph>();
checkBpGraphAlter<ListBpGraph>();
checkBpGraphSnapshot<ListBpGraph>();
checkBpGraphValidity<ListBpGraph>();
}
{ // Checking SmartGraph
checkBpGraphBuild<SmartBpGraph>();
checkBpGraphSnapshot<SmartBpGraph>();
checkBpGraphValidity<SmartBpGraph>();
}
{ // Checking FullBpGraph
checkFullBpGraph(6, 8);
checkFullBpGraph(7, 4);
}
}
int main() {
checkConcepts();
checkGraphs();
return 0;
}

View File

@@ -0,0 +1,169 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include "test_tools.h"
#include <lemon/list_graph.h>
#include <lemon/circulation.h>
#include <lemon/lgf_reader.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/maps.h>
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@arcs\n"
" lcap ucap\n"
"0 1 2 10\n"
"0 2 2 6\n"
"1 3 4 7\n"
"1 4 0 5\n"
"2 4 1 3\n"
"3 5 3 8\n"
"4 5 3 7\n"
"@attributes\n"
"source 0\n"
"sink 5\n";
void checkCirculationCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
typedef concepts::ReadMap<Arc,VType> CapMap;
typedef concepts::ReadMap<Node,VType> SupplyMap;
typedef concepts::ReadWriteMap<Arc,VType> FlowMap;
typedef concepts::WriteMap<Node,bool> BarrierMap;
typedef Elevator<Digraph, Digraph::Node> Elev;
typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
Digraph g;
Node n;
Arc a;
CapMap lcap, ucap;
SupplyMap supply;
FlowMap flow;
BarrierMap bar;
VType v;
bool b;
::lemon::ignore_unused_variable_warning(v,b);
typedef Circulation<Digraph, CapMap, CapMap, SupplyMap>
::SetFlowMap<FlowMap>
::SetElevator<Elev>
::SetStandardElevator<LinkedElev>
::Create CirculationType;
CirculationType circ_test(g, lcap, ucap, supply);
const CirculationType& const_circ_test = circ_test;
circ_test
.lowerMap(lcap)
.upperMap(ucap)
.supplyMap(supply)
.flowMap(flow);
const CirculationType::Elevator& elev = const_circ_test.elevator();
circ_test.elevator(const_cast<CirculationType::Elevator&>(elev));
CirculationType::Tolerance tol = const_circ_test.tolerance();
circ_test.tolerance(tol);
circ_test.init();
circ_test.greedyInit();
circ_test.start();
circ_test.run();
v = const_circ_test.flow(a);
const FlowMap& fm = const_circ_test.flowMap();
b = const_circ_test.barrier(n);
const_circ_test.barrierMap(bar);
::lemon::ignore_unused_variable_warning(fm);
}
template <class G, class LM, class UM, class DM>
void checkCirculation(const G& g, const LM& lm, const UM& um,
const DM& dm, bool find)
{
Circulation<G, LM, UM, DM> circ(g, lm, um, dm);
bool ret = circ.run();
if (find) {
check(ret, "A feasible solution should have been found.");
check(circ.checkFlow(), "The found flow is corrupt.");
check(!circ.checkBarrier(), "A barrier should not have been found.");
} else {
check(!ret, "A feasible solution should not have been found.");
check(circ.checkBarrier(), "The found barrier is corrupt.");
}
}
int main (int, char*[])
{
typedef ListDigraph Digraph;
DIGRAPH_TYPEDEFS(Digraph);
Digraph g;
IntArcMap lo(g), up(g);
IntNodeMap delta(g, 0);
Node s, t;
std::istringstream input(test_lgf);
DigraphReader<Digraph>(g,input).
arcMap("lcap", lo).
arcMap("ucap", up).
node("source",s).
node("sink",t).
run();
delta[s] = 7; delta[t] = -7;
checkCirculation(g, lo, up, delta, true);
delta[s] = 13; delta[t] = -13;
checkCirculation(g, lo, up, delta, true);
delta[s] = 6; delta[t] = -6;
checkCirculation(g, lo, up, delta, false);
delta[s] = 14; delta[t] = -14;
checkCirculation(g, lo, up, delta, false);
delta[s] = 7; delta[t] = -13;
checkCirculation(g, lo, up, delta, true);
delta[s] = 5; delta[t] = -15;
checkCirculation(g, lo, up, delta, true);
delta[s] = 10; delta[t] = -11;
checkCirculation(g, lo, up, delta, true);
delta[s] = 11; delta[t] = -10;
checkCirculation(g, lo, up, delta, false);
return 0;
}

View File

@@ -0,0 +1,316 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/connectivity.h>
#include <lemon/list_graph.h>
#include <lemon/adaptors.h>
#include "test_tools.h"
using namespace lemon;
int main()
{
typedef ListDigraph Digraph;
typedef Undirector<Digraph> Graph;
{
Digraph d;
Digraph::NodeMap<int> order(d);
Graph g(d);
check(stronglyConnected(d), "The empty digraph is strongly connected");
check(countStronglyConnectedComponents(d) == 0,
"The empty digraph has 0 strongly connected component");
check(connected(g), "The empty graph is connected");
check(countConnectedComponents(g) == 0,
"The empty graph has 0 connected component");
check(biNodeConnected(g), "The empty graph is bi-node-connected");
check(countBiNodeConnectedComponents(g) == 0,
"The empty graph has 0 bi-node-connected component");
check(biEdgeConnected(g), "The empty graph is bi-edge-connected");
check(countBiEdgeConnectedComponents(g) == 0,
"The empty graph has 0 bi-edge-connected component");
check(dag(d), "The empty digraph is DAG.");
check(checkedTopologicalSort(d, order), "The empty digraph is DAG.");
check(loopFree(d), "The empty digraph is loop-free.");
check(parallelFree(d), "The empty digraph is parallel-free.");
check(simpleGraph(d), "The empty digraph is simple.");
check(acyclic(g), "The empty graph is acyclic.");
check(tree(g), "The empty graph is tree.");
check(bipartite(g), "The empty graph is bipartite.");
check(loopFree(g), "The empty graph is loop-free.");
check(parallelFree(g), "The empty graph is parallel-free.");
check(simpleGraph(g), "The empty graph is simple.");
}
{
Digraph d;
Digraph::NodeMap<int> order(d);
Graph g(d);
Digraph::Node n = d.addNode();
::lemon::ignore_unused_variable_warning(n);
check(stronglyConnected(d), "This digraph is strongly connected");
check(countStronglyConnectedComponents(d) == 1,
"This digraph has 1 strongly connected component");
check(connected(g), "This graph is connected");
check(countConnectedComponents(g) == 1,
"This graph has 1 connected component");
check(biNodeConnected(g), "This graph is bi-node-connected");
check(countBiNodeConnectedComponents(g) == 0,
"This graph has 0 bi-node-connected component");
check(biEdgeConnected(g), "This graph is bi-edge-connected");
check(countBiEdgeConnectedComponents(g) == 1,
"This graph has 1 bi-edge-connected component");
check(dag(d), "This digraph is DAG.");
check(checkedTopologicalSort(d, order), "This digraph is DAG.");
check(loopFree(d), "This digraph is loop-free.");
check(parallelFree(d), "This digraph is parallel-free.");
check(simpleGraph(d), "This digraph is simple.");
check(acyclic(g), "This graph is acyclic.");
check(tree(g), "This graph is tree.");
check(bipartite(g), "This graph is bipartite.");
check(loopFree(g), "This graph is loop-free.");
check(parallelFree(g), "This graph is parallel-free.");
check(simpleGraph(g), "This graph is simple.");
}
{
ListGraph g;
ListGraph::NodeMap<bool> map(g);
ListGraph::Node n1 = g.addNode();
ListGraph::Node n2 = g.addNode();
ListGraph::Edge e1 = g.addEdge(n1, n2);
::lemon::ignore_unused_variable_warning(e1);
check(biNodeConnected(g), "Graph is bi-node-connected");
ListGraph::Node n3 = g.addNode();
::lemon::ignore_unused_variable_warning(n3);
check(!biNodeConnected(g), "Graph is not bi-node-connected");
}
{
Digraph d;
Digraph::NodeMap<int> order(d);
Graph g(d);
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
Digraph::Node n4 = d.addNode();
Digraph::Node n5 = d.addNode();
Digraph::Node n6 = d.addNode();
d.addArc(n1, n3);
d.addArc(n3, n2);
d.addArc(n2, n1);
d.addArc(n4, n2);
d.addArc(n4, n3);
d.addArc(n5, n6);
d.addArc(n6, n5);
check(!stronglyConnected(d), "This digraph is not strongly connected");
check(countStronglyConnectedComponents(d) == 3,
"This digraph has 3 strongly connected components");
check(!connected(g), "This graph is not connected");
check(countConnectedComponents(g) == 2,
"This graph has 2 connected components");
check(!dag(d), "This digraph is not DAG.");
check(!checkedTopologicalSort(d, order), "This digraph is not DAG.");
check(loopFree(d), "This digraph is loop-free.");
check(parallelFree(d), "This digraph is parallel-free.");
check(simpleGraph(d), "This digraph is simple.");
check(!acyclic(g), "This graph is not acyclic.");
check(!tree(g), "This graph is not tree.");
check(!bipartite(g), "This graph is not bipartite.");
check(loopFree(g), "This graph is loop-free.");
check(!parallelFree(g), "This graph is not parallel-free.");
check(!simpleGraph(g), "This graph is not simple.");
d.addArc(n3, n3);
check(!loopFree(d), "This digraph is not loop-free.");
check(!loopFree(g), "This graph is not loop-free.");
check(!simpleGraph(d), "This digraph is not simple.");
d.addArc(n3, n2);
check(!parallelFree(d), "This digraph is not parallel-free.");
}
{
Digraph d;
Digraph::ArcMap<bool> cutarcs(d, false);
Graph g(d);
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
Digraph::Node n4 = d.addNode();
Digraph::Node n5 = d.addNode();
Digraph::Node n6 = d.addNode();
Digraph::Node n7 = d.addNode();
Digraph::Node n8 = d.addNode();
d.addArc(n1, n2);
d.addArc(n5, n1);
d.addArc(n2, n8);
d.addArc(n8, n5);
d.addArc(n6, n4);
d.addArc(n4, n6);
d.addArc(n2, n5);
d.addArc(n1, n8);
d.addArc(n6, n7);
d.addArc(n7, n6);
check(!stronglyConnected(d), "This digraph is not strongly connected");
check(countStronglyConnectedComponents(d) == 3,
"This digraph has 3 strongly connected components");
Digraph::NodeMap<int> scomp1(d);
check(stronglyConnectedComponents(d, scomp1) == 3,
"This digraph has 3 strongly connected components");
check(scomp1[n1] != scomp1[n3] && scomp1[n1] != scomp1[n4] &&
scomp1[n3] != scomp1[n4], "Wrong stronglyConnectedComponents()");
check(scomp1[n1] == scomp1[n2] && scomp1[n1] == scomp1[n5] &&
scomp1[n1] == scomp1[n8], "Wrong stronglyConnectedComponents()");
check(scomp1[n4] == scomp1[n6] && scomp1[n4] == scomp1[n7],
"Wrong stronglyConnectedComponents()");
Digraph::ArcMap<bool> scut1(d, false);
check(stronglyConnectedCutArcs(d, scut1) == 0,
"This digraph has 0 strongly connected cut arc.");
for (Digraph::ArcIt a(d); a != INVALID; ++a) {
check(!scut1[a], "Wrong stronglyConnectedCutArcs()");
}
check(!connected(g), "This graph is not connected");
check(countConnectedComponents(g) == 3,
"This graph has 3 connected components");
Graph::NodeMap<int> comp(g);
check(connectedComponents(g, comp) == 3,
"This graph has 3 connected components");
check(comp[n1] != comp[n3] && comp[n1] != comp[n4] &&
comp[n3] != comp[n4], "Wrong connectedComponents()");
check(comp[n1] == comp[n2] && comp[n1] == comp[n5] &&
comp[n1] == comp[n8], "Wrong connectedComponents()");
check(comp[n4] == comp[n6] && comp[n4] == comp[n7],
"Wrong connectedComponents()");
cutarcs[d.addArc(n3, n1)] = true;
cutarcs[d.addArc(n3, n5)] = true;
cutarcs[d.addArc(n3, n8)] = true;
cutarcs[d.addArc(n8, n6)] = true;
cutarcs[d.addArc(n8, n7)] = true;
check(!stronglyConnected(d), "This digraph is not strongly connected");
check(countStronglyConnectedComponents(d) == 3,
"This digraph has 3 strongly connected components");
Digraph::NodeMap<int> scomp2(d);
check(stronglyConnectedComponents(d, scomp2) == 3,
"This digraph has 3 strongly connected components");
check(scomp2[n3] == 0, "Wrong stronglyConnectedComponents()");
check(scomp2[n1] == 1 && scomp2[n2] == 1 && scomp2[n5] == 1 &&
scomp2[n8] == 1, "Wrong stronglyConnectedComponents()");
check(scomp2[n4] == 2 && scomp2[n6] == 2 && scomp2[n7] == 2,
"Wrong stronglyConnectedComponents()");
Digraph::ArcMap<bool> scut2(d, false);
check(stronglyConnectedCutArcs(d, scut2) == 5,
"This digraph has 5 strongly connected cut arcs.");
for (Digraph::ArcIt a(d); a != INVALID; ++a) {
check(scut2[a] == cutarcs[a], "Wrong stronglyConnectedCutArcs()");
}
}
{
// DAG example for topological sort from the book New Algorithms
// (T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein)
Digraph d;
Digraph::NodeMap<int> order(d);
Digraph::Node belt = d.addNode();
Digraph::Node trousers = d.addNode();
Digraph::Node necktie = d.addNode();
Digraph::Node coat = d.addNode();
Digraph::Node socks = d.addNode();
Digraph::Node shirt = d.addNode();
Digraph::Node shoe = d.addNode();
Digraph::Node watch = d.addNode();
Digraph::Node pants = d.addNode();
::lemon::ignore_unused_variable_warning(watch);
d.addArc(socks, shoe);
d.addArc(pants, shoe);
d.addArc(pants, trousers);
d.addArc(trousers, shoe);
d.addArc(trousers, belt);
d.addArc(belt, coat);
d.addArc(shirt, belt);
d.addArc(shirt, necktie);
d.addArc(necktie, coat);
check(dag(d), "This digraph is DAG.");
topologicalSort(d, order);
for (Digraph::ArcIt a(d); a != INVALID; ++a) {
check(order[d.source(a)] < order[d.target(a)],
"Wrong topologicalSort()");
}
}
{
ListGraph g;
ListGraph::NodeMap<bool> map(g);
ListGraph::Node n1 = g.addNode();
ListGraph::Node n2 = g.addNode();
ListGraph::Node n3 = g.addNode();
ListGraph::Node n4 = g.addNode();
ListGraph::Node n5 = g.addNode();
ListGraph::Node n6 = g.addNode();
ListGraph::Node n7 = g.addNode();
g.addEdge(n1, n3);
g.addEdge(n1, n4);
g.addEdge(n2, n5);
g.addEdge(n3, n6);
g.addEdge(n4, n6);
g.addEdge(n4, n7);
g.addEdge(n5, n7);
check(bipartite(g), "This graph is bipartite");
check(bipartitePartitions(g, map), "This graph is bipartite");
check(map[n1] == map[n2] && map[n1] == map[n6] && map[n1] == map[n7],
"Wrong bipartitePartitions()");
check(map[n3] == map[n4] && map[n3] == map[n5],
"Wrong bipartitePartitions()");
}
return 0;
}

View File

@@ -0,0 +1,118 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/counter.h>
#include <vector>
#include <sstream>
#include "test/test_tools.h"
using namespace lemon;
template <typename T>
void bubbleSort(std::vector<T>& v) {
std::stringstream s1, s2, s3;
{
Counter op("Bubble Sort - Operations: ", s1);
Counter::SubCounter as(op, "Assignments: ", s2);
Counter::SubCounter co(op, "Comparisons: ", s3);
for (int i = v.size()-1; i > 0; --i) {
for (int j = 0; j < i; ++j) {
if (v[j] > v[j+1]) {
T tmp = v[j];
v[j] = v[j+1];
v[j+1] = tmp;
as += 3;
}
++co;
}
}
}
check(s1.str() == "Bubble Sort - Operations: 102\n", "Wrong counter");
check(s2.str() == "Assignments: 57\n", "Wrong subcounter");
check(s3.str() == "Comparisons: 45\n", "Wrong subcounter");
}
template <typename T>
void insertionSort(std::vector<T>& v) {
std::stringstream s1, s2, s3;
{
Counter op("Insertion Sort - Operations: ", s1);
Counter::SubCounter as(op, "Assignments: ", s2);
Counter::SubCounter co(op, "Comparisons: ", s3);
for (int i = 1; i < int(v.size()); ++i) {
T value = v[i];
++as;
int j = i;
while (j > 0 && v[j-1] > value) {
v[j] = v[j-1];
--j;
++co; ++as;
}
v[j] = value;
++as;
}
}
check(s1.str() == "Insertion Sort - Operations: 56\n", "Wrong counter");
check(s2.str() == "Assignments: 37\n", "Wrong subcounter");
check(s3.str() == "Comparisons: 19\n", "Wrong subcounter");
}
template <typename MyCounter>
void counterTest(bool output) {
std::stringstream s1, s2, s3;
{
MyCounter c("Main Counter: ", s1);
c++;
typename MyCounter::SubCounter d(c, "SubCounter: ", s2);
d++;
typename MyCounter::SubCounter::NoSubCounter e(d, "SubSubCounter: ", s3);
e++;
d+=3;
c-=4;
e-=2;
c.reset(2);
c.reset();
}
if (output) {
check(s1.str() == "Main Counter: 3\n", "Wrong Counter");
check(s2.str() == "SubCounter: 3\n", "Wrong SubCounter");
check(s3.str() == "", "Wrong NoSubCounter");
} else {
check(s1.str() == "", "Wrong NoCounter");
check(s2.str() == "", "Wrong SubCounter");
check(s3.str() == "", "Wrong NoSubCounter");
}
}
void init(std::vector<int>& v) {
v[0] = 10; v[1] = 60; v[2] = 20; v[3] = 90; v[4] = 100;
v[5] = 80; v[6] = 40; v[7] = 30; v[8] = 50; v[9] = 70;
}
int main()
{
counterTest<Counter>(true);
counterTest<NoCounter>(false);
std::vector<int> x(10);
init(x); bubbleSort(x);
init(x); insertionSort(x);
return 0;
}

View File

@@ -0,0 +1,238 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/digraph.h>
#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/dfs.h>
#include <lemon/path.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"@arcs\n"
" label\n"
"0 1 0\n"
"1 2 1\n"
"2 3 2\n"
"1 4 3\n"
"4 2 4\n"
"4 5 5\n"
"5 0 6\n"
"6 3 7\n"
"@attributes\n"
"source 0\n"
"target 5\n"
"source1 6\n"
"target1 3\n";
void checkDfsCompile()
{
typedef concepts::Digraph Digraph;
typedef Dfs<Digraph> DType;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
Digraph G;
Node s, t;
Arc e;
int l, i;
bool b;
::lemon::ignore_unused_variable_warning(l,i,b);
DType::DistMap d(G);
DType::PredMap p(G);
Path<Digraph> pp;
concepts::ReadMap<Arc,bool> am;
{
DType dfs_test(G);
const DType& const_dfs_test = dfs_test;
dfs_test.run(s);
dfs_test.run(s,t);
dfs_test.run();
dfs_test.init();
dfs_test.addSource(s);
e = dfs_test.processNextArc();
e = const_dfs_test.nextArc();
b = const_dfs_test.emptyQueue();
i = const_dfs_test.queueSize();
dfs_test.start();
dfs_test.start(t);
dfs_test.start(am);
l = const_dfs_test.dist(t);
e = const_dfs_test.predArc(t);
s = const_dfs_test.predNode(t);
b = const_dfs_test.reached(t);
d = const_dfs_test.distMap();
p = const_dfs_test.predMap();
pp = const_dfs_test.path(t);
}
{
DType
::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
::SetDistMap<concepts::ReadWriteMap<Node,int> >
::SetReachedMap<concepts::ReadWriteMap<Node,bool> >
::SetStandardProcessedMap
::SetProcessedMap<concepts::WriteMap<Node,bool> >
::Create dfs_test(G);
concepts::ReadWriteMap<Node,Arc> pred_map;
concepts::ReadWriteMap<Node,int> dist_map;
concepts::ReadWriteMap<Node,bool> reached_map;
concepts::WriteMap<Node,bool> processed_map;
dfs_test
.predMap(pred_map)
.distMap(dist_map)
.reachedMap(reached_map)
.processedMap(processed_map);
dfs_test.run(s);
dfs_test.run(s,t);
dfs_test.run();
dfs_test.init();
dfs_test.addSource(s);
e = dfs_test.processNextArc();
e = dfs_test.nextArc();
b = dfs_test.emptyQueue();
i = dfs_test.queueSize();
dfs_test.start();
dfs_test.start(t);
dfs_test.start(am);
l = dfs_test.dist(t);
e = dfs_test.predArc(t);
s = dfs_test.predNode(t);
b = dfs_test.reached(t);
pp = dfs_test.path(t);
}
}
void checkDfsFunctionCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef Digraph::Arc Arc;
typedef Digraph::Node Node;
Digraph g;
bool b;
::lemon::ignore_unused_variable_warning(b);
dfs(g).run(Node());
b=dfs(g).run(Node(),Node());
dfs(g).run();
dfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.run(Node());
b=dfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.path(concepts::Path<Digraph>())
.dist(VType())
.run(Node(),Node());
dfs(g)
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.reachedMap(concepts::ReadWriteMap<Node,bool>())
.processedMap(concepts::WriteMap<Node,bool>())
.run();
}
template <class Digraph>
void checkDfs() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node s, t;
Node s1, t1;
std::istringstream input(test_lgf);
digraphReader(G, input).
node("source", s).
node("target", t).
node("source1", s1).
node("target1", t1).
run();
Dfs<Digraph> dfs_test(G);
dfs_test.run(s);
Path<Digraph> p = dfs_test.path(t);
check(p.length() == dfs_test.dist(t),"path() found a wrong path.");
check(checkPath(G, p),"path() found a wrong path.");
check(pathSource(G, p) == s,"path() found a wrong path.");
check(pathTarget(G, p) == t,"path() found a wrong path.");
for(NodeIt v(G); v!=INVALID; ++v) {
if (dfs_test.reached(v)) {
check(v==s || dfs_test.predArc(v)!=INVALID, "Wrong tree.");
if (dfs_test.predArc(v)!=INVALID ) {
Arc e=dfs_test.predArc(v);
Node u=G.source(e);
check(u==dfs_test.predNode(v),"Wrong tree.");
check(dfs_test.dist(v) - dfs_test.dist(u) == 1,
"Wrong distance. (" << dfs_test.dist(u) << "->"
<< dfs_test.dist(v) << ")");
}
}
}
{
Dfs<Digraph> dfs(G);
check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6.");
}
{
NullMap<Node,Arc> myPredMap;
dfs(G).predMap(myPredMap).run(s);
}
}
int main()
{
checkDfs<ListDigraph>();
checkDfs<SmartDigraph>();
return 0;
}

View File

@@ -0,0 +1,569 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/digraph.h>
#include <lemon/list_graph.h>
#include <lemon/smart_graph.h>
#include <lemon/static_graph.h>
#include <lemon/full_graph.h>
#include "test_tools.h"
#include "graph_test.h"
using namespace lemon;
using namespace lemon::concepts;
template <class Digraph>
void checkDigraphBuild() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
checkGraphNodeList(G, 0);
checkGraphArcList(G, 0);
G.reserveNode(3);
G.reserveArc(4);
Node
n1 = G.addNode(),
n2 = G.addNode(),
n3 = G.addNode();
checkGraphNodeList(G, 3);
checkGraphArcList(G, 0);
Arc a1 = G.addArc(n1, n2);
check(G.source(a1) == n1 && G.target(a1) == n2, "Wrong arc");
checkGraphNodeList(G, 3);
checkGraphArcList(G, 1);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 0);
checkGraphOutArcList(G, n3, 0);
checkGraphInArcList(G, n1, 0);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 0);
checkGraphConArcList(G, 1);
Arc a2 = G.addArc(n2, n1),
a3 = G.addArc(n2, n3),
a4 = G.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a2,a3,a4);
checkGraphNodeList(G, 3);
checkGraphArcList(G, 4);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 3);
checkGraphOutArcList(G, n3, 0);
checkGraphInArcList(G, n1, 1);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 2);
checkGraphConArcList(G, 4);
checkNodeIds(G);
checkArcIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
}
template <class Digraph>
void checkDigraphSplit() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1),
a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a1,a2,a3,a4);
Node n4 = G.split(n2);
check(G.target(OutArcIt(G, n2)) == n4 &&
G.source(InArcIt(G, n4)) == n2,
"Wrong split.");
checkGraphNodeList(G, 4);
checkGraphArcList(G, 5);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 1);
checkGraphOutArcList(G, n3, 0);
checkGraphOutArcList(G, n4, 3);
checkGraphInArcList(G, n1, 1);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 2);
checkGraphInArcList(G, n4, 1);
checkGraphConArcList(G, 5);
}
template <class Digraph>
void checkDigraphAlter() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node n1 = G.addNode(), n2 = G.addNode(),
n3 = G.addNode(), n4 = G.addNode();
Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1),
a3 = G.addArc(n4, n3), a4 = G.addArc(n4, n3),
a5 = G.addArc(n2, n4);
::lemon::ignore_unused_variable_warning(a1,a2,a3,a5);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 5);
// Check changeSource() and changeTarget()
G.changeTarget(a4, n1);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 5);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 1);
checkGraphOutArcList(G, n3, 0);
checkGraphOutArcList(G, n4, 3);
checkGraphInArcList(G, n1, 2);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 1);
checkGraphInArcList(G, n4, 1);
checkGraphConArcList(G, 5);
G.changeSource(a4, n3);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 5);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 1);
checkGraphOutArcList(G, n3, 1);
checkGraphOutArcList(G, n4, 2);
checkGraphInArcList(G, n1, 2);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 1);
checkGraphInArcList(G, n4, 1);
checkGraphConArcList(G, 5);
// Check contract()
G.contract(n2, n4, false);
checkGraphNodeList(G, 3);
checkGraphArcList(G, 5);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 3);
checkGraphOutArcList(G, n3, 1);
checkGraphInArcList(G, n1, 2);
checkGraphInArcList(G, n2, 2);
checkGraphInArcList(G, n3, 1);
checkGraphConArcList(G, 5);
G.contract(n2, n1);
checkGraphNodeList(G, 2);
checkGraphArcList(G, 3);
checkGraphOutArcList(G, n2, 2);
checkGraphOutArcList(G, n3, 1);
checkGraphInArcList(G, n2, 2);
checkGraphInArcList(G, n3, 1);
checkGraphConArcList(G, 3);
}
template <class Digraph>
void checkDigraphErase() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node n1 = G.addNode(), n2 = G.addNode(),
n3 = G.addNode(), n4 = G.addNode();
Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1),
a3 = G.addArc(n4, n3), a4 = G.addArc(n3, n1),
a5 = G.addArc(n2, n4);
::lemon::ignore_unused_variable_warning(a2,a3,a4,a5);
// Check arc deletion
G.erase(a1);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 4);
checkGraphOutArcList(G, n1, 0);
checkGraphOutArcList(G, n2, 1);
checkGraphOutArcList(G, n3, 1);
checkGraphOutArcList(G, n4, 2);
checkGraphInArcList(G, n1, 2);
checkGraphInArcList(G, n2, 0);
checkGraphInArcList(G, n3, 1);
checkGraphInArcList(G, n4, 1);
checkGraphConArcList(G, 4);
// Check node deletion
G.erase(n4);
checkGraphNodeList(G, 3);
checkGraphArcList(G, 1);
checkGraphOutArcList(G, n1, 0);
checkGraphOutArcList(G, n2, 0);
checkGraphOutArcList(G, n3, 1);
checkGraphOutArcList(G, n4, 0);
checkGraphInArcList(G, n1, 1);
checkGraphInArcList(G, n2, 0);
checkGraphInArcList(G, n3, 0);
checkGraphInArcList(G, n4, 0);
checkGraphConArcList(G, 1);
}
template <class Digraph>
void checkDigraphSnapshot() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph G;
Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1),
a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a1,a2,a3,a4);
typename Digraph::Snapshot snapshot(G);
Node n = G.addNode();
G.addArc(n3, n);
G.addArc(n, n3);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 6);
snapshot.restore();
checkGraphNodeList(G, 3);
checkGraphArcList(G, 4);
checkGraphOutArcList(G, n1, 1);
checkGraphOutArcList(G, n2, 3);
checkGraphOutArcList(G, n3, 0);
checkGraphInArcList(G, n1, 1);
checkGraphInArcList(G, n2, 1);
checkGraphInArcList(G, n3, 2);
checkGraphConArcList(G, 4);
checkNodeIds(G);
checkArcIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
G.addNode();
snapshot.save(G);
G.addArc(G.addNode(), G.addNode());
snapshot.restore();
snapshot.save(G);
checkGraphNodeList(G, 4);
checkGraphArcList(G, 4);
G.addArc(G.addNode(), G.addNode());
snapshot.restore();
checkGraphNodeList(G, 4);
checkGraphArcList(G, 4);
}
void checkConcepts() {
{ // Checking digraph components
checkConcept<BaseDigraphComponent, BaseDigraphComponent >();
checkConcept<IDableDigraphComponent<>,
IDableDigraphComponent<> >();
checkConcept<IterableDigraphComponent<>,
IterableDigraphComponent<> >();
checkConcept<MappableDigraphComponent<>,
MappableDigraphComponent<> >();
}
{ // Checking skeleton digraph
checkConcept<Digraph, Digraph>();
}
{ // Checking ListDigraph
checkConcept<Digraph, ListDigraph>();
checkConcept<AlterableDigraphComponent<>, ListDigraph>();
checkConcept<ExtendableDigraphComponent<>, ListDigraph>();
checkConcept<ClearableDigraphComponent<>, ListDigraph>();
checkConcept<ErasableDigraphComponent<>, ListDigraph>();
}
{ // Checking SmartDigraph
checkConcept<Digraph, SmartDigraph>();
checkConcept<AlterableDigraphComponent<>, SmartDigraph>();
checkConcept<ExtendableDigraphComponent<>, SmartDigraph>();
checkConcept<ClearableDigraphComponent<>, SmartDigraph>();
}
{ // Checking StaticDigraph
checkConcept<Digraph, StaticDigraph>();
checkConcept<ClearableDigraphComponent<>, StaticDigraph>();
}
{ // Checking FullDigraph
checkConcept<Digraph, FullDigraph>();
}
}
template <typename Digraph>
void checkDigraphValidity() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph g;
Node
n1 = g.addNode(),
n2 = g.addNode(),
n3 = g.addNode();
Arc
e1 = g.addArc(n1, n2),
e2 = g.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(e2);
check(g.valid(n1), "Wrong validity check");
check(g.valid(e1), "Wrong validity check");
check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
}
template <typename Digraph>
void checkDigraphValidityErase() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph g;
Node
n1 = g.addNode(),
n2 = g.addNode(),
n3 = g.addNode();
Arc
e1 = g.addArc(n1, n2),
e2 = g.addArc(n2, n3);
check(g.valid(n1), "Wrong validity check");
check(g.valid(e1), "Wrong validity check");
g.erase(n1);
check(!g.valid(n1), "Wrong validity check");
check(g.valid(n2), "Wrong validity check");
check(g.valid(n3), "Wrong validity check");
check(!g.valid(e1), "Wrong validity check");
check(g.valid(e2), "Wrong validity check");
check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
}
void checkStaticDigraph() {
SmartDigraph g;
SmartDigraph::NodeMap<StaticDigraph::Node> nref(g);
SmartDigraph::ArcMap<StaticDigraph::Arc> aref(g);
StaticDigraph G;
checkGraphNodeList(G, 0);
checkGraphArcList(G, 0);
G.build(g, nref, aref);
checkGraphNodeList(G, 0);
checkGraphArcList(G, 0);
SmartDigraph::Node
n1 = g.addNode(),
n2 = g.addNode(),
n3 = g.addNode();
G.build(g, nref, aref);
checkGraphNodeList(G, 3);
checkGraphArcList(G, 0);
SmartDigraph::Arc a1 = g.addArc(n1, n2);
G.build(g, nref, aref);
check(G.source(aref[a1]) == nref[n1] && G.target(aref[a1]) == nref[n2],
"Wrong arc or wrong references");
checkGraphNodeList(G, 3);
checkGraphArcList(G, 1);
checkGraphOutArcList(G, nref[n1], 1);
checkGraphOutArcList(G, nref[n2], 0);
checkGraphOutArcList(G, nref[n3], 0);
checkGraphInArcList(G, nref[n1], 0);
checkGraphInArcList(G, nref[n2], 1);
checkGraphInArcList(G, nref[n3], 0);
checkGraphConArcList(G, 1);
SmartDigraph::Arc
a2 = g.addArc(n2, n1),
a3 = g.addArc(n2, n3),
a4 = g.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a2,a3,a4);
digraphCopy(g, G).nodeRef(nref).run();
checkGraphNodeList(G, 3);
checkGraphArcList(G, 4);
checkGraphOutArcList(G, nref[n1], 1);
checkGraphOutArcList(G, nref[n2], 3);
checkGraphOutArcList(G, nref[n3], 0);
checkGraphInArcList(G, nref[n1], 1);
checkGraphInArcList(G, nref[n2], 1);
checkGraphInArcList(G, nref[n3], 2);
checkGraphConArcList(G, 4);
std::vector<std::pair<int,int> > arcs;
arcs.push_back(std::make_pair(0,1));
arcs.push_back(std::make_pair(0,2));
arcs.push_back(std::make_pair(1,3));
arcs.push_back(std::make_pair(1,2));
arcs.push_back(std::make_pair(3,0));
arcs.push_back(std::make_pair(3,3));
arcs.push_back(std::make_pair(4,2));
arcs.push_back(std::make_pair(4,3));
arcs.push_back(std::make_pair(4,1));
G.build(6, arcs.begin(), arcs.end());
checkGraphNodeList(G, 6);
checkGraphArcList(G, 9);
checkGraphOutArcList(G, G.node(0), 2);
checkGraphOutArcList(G, G.node(1), 2);
checkGraphOutArcList(G, G.node(2), 0);
checkGraphOutArcList(G, G.node(3), 2);
checkGraphOutArcList(G, G.node(4), 3);
checkGraphOutArcList(G, G.node(5), 0);
checkGraphInArcList(G, G.node(0), 1);
checkGraphInArcList(G, G.node(1), 2);
checkGraphInArcList(G, G.node(2), 3);
checkGraphInArcList(G, G.node(3), 3);
checkGraphInArcList(G, G.node(4), 0);
checkGraphInArcList(G, G.node(5), 0);
checkGraphConArcList(G, 9);
checkNodeIds(G);
checkArcIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
int n = G.nodeNum();
int m = G.arcNum();
check(G.index(G.node(n-1)) == n-1, "Wrong index.");
check(G.index(G.arc(m-1)) == m-1, "Wrong index.");
}
void checkFullDigraph(int num) {
typedef FullDigraph Digraph;
DIGRAPH_TYPEDEFS(Digraph);
Digraph G(num);
check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size");
G.resize(num);
check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size");
checkGraphNodeList(G, num);
checkGraphArcList(G, num * num);
for (NodeIt n(G); n != INVALID; ++n) {
checkGraphOutArcList(G, n, num);
checkGraphInArcList(G, n, num);
}
checkGraphConArcList(G, num * num);
checkNodeIds(G);
checkArcIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
for (int i = 0; i < G.nodeNum(); ++i) {
check(G.index(G(i)) == i, "Wrong index");
}
for (NodeIt s(G); s != INVALID; ++s) {
for (NodeIt t(G); t != INVALID; ++t) {
Arc a = G.arc(s, t);
check(G.source(a) == s && G.target(a) == t, "Wrong arc lookup");
}
}
}
void checkDigraphs() {
{ // Checking ListDigraph
checkDigraphBuild<ListDigraph>();
checkDigraphSplit<ListDigraph>();
checkDigraphAlter<ListDigraph>();
checkDigraphErase<ListDigraph>();
checkDigraphSnapshot<ListDigraph>();
checkDigraphValidityErase<ListDigraph>();
}
{ // Checking SmartDigraph
checkDigraphBuild<SmartDigraph>();
checkDigraphSplit<SmartDigraph>();
checkDigraphSnapshot<SmartDigraph>();
checkDigraphValidity<SmartDigraph>();
}
{ // Checking StaticDigraph
checkStaticDigraph();
}
{ // Checking FullDigraph
checkFullDigraph(8);
}
}
int main() {
checkDigraphs();
checkConcepts();
return 0;
}

View File

@@ -0,0 +1,246 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/digraph.h>
#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/dijkstra.h>
#include <lemon/path.h>
#include <lemon/bin_heap.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"@arcs\n"
" label length\n"
"0 1 0 1\n"
"1 2 1 1\n"
"2 3 2 1\n"
"0 3 4 5\n"
"0 3 5 10\n"
"0 3 6 7\n"
"4 2 7 1\n"
"@attributes\n"
"source 0\n"
"target 3\n";
void checkDijkstraCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap;
typedef Dijkstra<Digraph, LengthMap> DType;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
Digraph G;
Node s, t, n;
Arc e;
VType l;
int i;
bool b;
::lemon::ignore_unused_variable_warning(l,i,b);
DType::DistMap d(G);
DType::PredMap p(G);
LengthMap length;
Path<Digraph> pp;
concepts::ReadMap<Node,bool> nm;
{
DType dijkstra_test(G,length);
const DType& const_dijkstra_test = dijkstra_test;
dijkstra_test.run(s);
dijkstra_test.run(s,t);
dijkstra_test.init();
dijkstra_test.addSource(s);
dijkstra_test.addSource(s, 1);
n = dijkstra_test.processNextNode();
n = const_dijkstra_test.nextNode();
b = const_dijkstra_test.emptyQueue();
i = const_dijkstra_test.queueSize();
dijkstra_test.start();
dijkstra_test.start(t);
dijkstra_test.start(nm);
l = const_dijkstra_test.dist(t);
e = const_dijkstra_test.predArc(t);
s = const_dijkstra_test.predNode(t);
b = const_dijkstra_test.reached(t);
b = const_dijkstra_test.processed(t);
d = const_dijkstra_test.distMap();
p = const_dijkstra_test.predMap();
pp = const_dijkstra_test.path(t);
l = const_dijkstra_test.currentDist(t);
}
{
DType
::SetPredMap<concepts::ReadWriteMap<Node,Arc> >
::SetDistMap<concepts::ReadWriteMap<Node,VType> >
::SetStandardProcessedMap
::SetProcessedMap<concepts::WriteMap<Node,bool> >
::SetOperationTraits<DijkstraDefaultOperationTraits<VType> >
::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > >
::SetStandardHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> > >
::SetHeap<BinHeap<VType, concepts::ReadWriteMap<Node,int> >,
concepts::ReadWriteMap<Node,int> >
::Create dijkstra_test(G,length);
LengthMap length_map;
concepts::ReadWriteMap<Node,Arc> pred_map;
concepts::ReadWriteMap<Node,VType> dist_map;
concepts::WriteMap<Node,bool> processed_map;
concepts::ReadWriteMap<Node,int> heap_cross_ref;
BinHeap<VType, concepts::ReadWriteMap<Node,int> > heap(heap_cross_ref);
dijkstra_test
.lengthMap(length_map)
.predMap(pred_map)
.distMap(dist_map)
.processedMap(processed_map)
.heap(heap, heap_cross_ref);
dijkstra_test.run(s);
dijkstra_test.run(s,t);
dijkstra_test.addSource(s);
dijkstra_test.addSource(s, 1);
n = dijkstra_test.processNextNode();
n = dijkstra_test.nextNode();
b = dijkstra_test.emptyQueue();
i = dijkstra_test.queueSize();
dijkstra_test.start();
dijkstra_test.start(t);
dijkstra_test.start(nm);
l = dijkstra_test.dist(t);
e = dijkstra_test.predArc(t);
s = dijkstra_test.predNode(t);
b = dijkstra_test.reached(t);
b = dijkstra_test.processed(t);
pp = dijkstra_test.path(t);
l = dijkstra_test.currentDist(t);
}
}
void checkDijkstraFunctionCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef Digraph::Arc Arc;
typedef Digraph::Node Node;
typedef concepts::ReadMap<Digraph::Arc,VType> LengthMap;
Digraph g;
bool b;
::lemon::ignore_unused_variable_warning(b);
dijkstra(g,LengthMap()).run(Node());
b=dijkstra(g,LengthMap()).run(Node(),Node());
dijkstra(g,LengthMap())
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.processedMap(concepts::WriteMap<Node,bool>())
.run(Node());
b=dijkstra(g,LengthMap())
.predMap(concepts::ReadWriteMap<Node,Arc>())
.distMap(concepts::ReadWriteMap<Node,VType>())
.processedMap(concepts::WriteMap<Node,bool>())
.path(concepts::Path<Digraph>())
.dist(VType())
.run(Node(),Node());
}
template <class Digraph>
void checkDijkstra() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
typedef typename Digraph::template ArcMap<int> LengthMap;
Digraph G;
Node s, t;
LengthMap length(G);
std::istringstream input(test_lgf);
digraphReader(G, input).
arcMap("length", length).
node("source", s).
node("target", t).
run();
Dijkstra<Digraph, LengthMap>
dijkstra_test(G, length);
dijkstra_test.run(s);
check(dijkstra_test.dist(t)==3,"Dijkstra found a wrong path.");
Path<Digraph> p = dijkstra_test.path(t);
check(p.length()==3,"path() found a wrong path.");
check(checkPath(G, p),"path() found a wrong path.");
check(pathSource(G, p) == s,"path() found a wrong path.");
check(pathTarget(G, p) == t,"path() found a wrong path.");
for(ArcIt e(G); e!=INVALID; ++e) {
Node u=G.source(e);
Node v=G.target(e);
check( !dijkstra_test.reached(u) ||
(dijkstra_test.dist(v) - dijkstra_test.dist(u) <= length[e]),
"Wrong output. dist(target)-dist(source)-arc_length=" <<
dijkstra_test.dist(v) - dijkstra_test.dist(u) - length[e]);
}
for(NodeIt v(G); v!=INVALID; ++v) {
if (dijkstra_test.reached(v)) {
check(v==s || dijkstra_test.predArc(v)!=INVALID, "Wrong tree.");
if (dijkstra_test.predArc(v)!=INVALID ) {
Arc e=dijkstra_test.predArc(v);
Node u=G.source(e);
check(u==dijkstra_test.predNode(v),"Wrong tree.");
check(dijkstra_test.dist(v) - dijkstra_test.dist(u) == length[e],
"Wrong distance! Difference: " <<
std::abs(dijkstra_test.dist(v)-dijkstra_test.dist(u)-length[e]));
}
}
}
{
NullMap<Node,Arc> myPredMap;
dijkstra(G,length).predMap(myPredMap).run(s);
}
}
int main() {
checkDijkstra<ListDigraph>();
checkDijkstra<SmartDigraph>();
return 0;
}

View File

@@ -0,0 +1,87 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/dim2.h>
#include <iostream>
#include "test_tools.h"
using namespace std;
using namespace lemon;
int main()
{
typedef dim2::Point<int> Point;
Point p;
check(p.size()==2, "Wrong dim2::Point initialization.");
Point a(1,2);
Point b(3,4);
check(a[0]==1 && a[1]==2, "Wrong dim2::Point initialization.");
p = a+b;
check(p.x==4 && p.y==6, "Wrong dim2::Point addition.");
p = a-b;
check(p.x==-2 && p.y==-2, "Wrong dim2::Point subtraction.");
check(a.normSquare()==5,"Wrong dim2::Point norm calculation.");
check(a*b==11, "Wrong dim2::Point scalar product.");
int l=2;
p = a*l;
check(p.x==2 && p.y==4, "Wrong dim2::Point multiplication by a scalar.");
p = b/l;
check(p.x==1 && p.y==2, "Wrong dim2::Point division by a scalar.");
typedef dim2::Box<int> Box;
Box box1;
check(box1.empty(), "Wrong empty() in dim2::Box.");
box1.add(a);
check(!box1.empty(), "Wrong empty() in dim2::Box.");
box1.add(b);
check(box1.left()==1 && box1.bottom()==2 &&
box1.right()==3 && box1.top()==4,
"Wrong addition of points to dim2::Box.");
check(box1.inside(Point(2,3)), "Wrong inside() in dim2::Box.");
check(box1.inside(Point(1,3)), "Wrong inside() in dim2::Box.");
check(!box1.inside(Point(0,3)), "Wrong inside() in dim2::Box.");
Box box2(Point(2,2));
check(!box2.empty(), "Wrong empty() in dim2::Box.");
box2.bottomLeft(Point(2,0));
box2.topRight(Point(5,3));
Box box3 = box1 & box2;
check(!box3.empty() &&
box3.left()==2 && box3.bottom()==2 &&
box3.right()==3 && box3.top()==3,
"Wrong intersection of two dim2::Box objects.");
box1.add(box2);
check(!box1.empty() &&
box1.left()==1 && box1.bottom()==0 &&
box1.right()==5 && box1.top()==4,
"Wrong addition of two dim2::Box objects.");
return 0;
}

View File

@@ -0,0 +1,396 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <vector>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/graph.h>
#include <lemon/concept_check.h>
#include <lemon/list_graph.h>
#include <lemon/edge_set.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
void checkSmartArcSet() {
checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >();
typedef ListDigraph Digraph;
typedef SmartArcSet<Digraph> ArcSet;
Digraph digraph;
Digraph::Node
n1 = digraph.addNode(),
n2 = digraph.addNode();
Digraph::Arc ga1 = digraph.addArc(n1, n2);
::lemon::ignore_unused_variable_warning(ga1);
ArcSet arc_set(digraph);
Digraph::Arc ga2 = digraph.addArc(n2, n1);
::lemon::ignore_unused_variable_warning(ga2);
checkGraphNodeList(arc_set, 2);
checkGraphArcList(arc_set, 0);
Digraph::Node
n3 = digraph.addNode();
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 0);
ArcSet::Arc a1 = arc_set.addArc(n1, n2);
check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc");
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 1);
checkGraphOutArcList(arc_set, n1, 1);
checkGraphOutArcList(arc_set, n2, 0);
checkGraphOutArcList(arc_set, n3, 0);
checkGraphInArcList(arc_set, n1, 0);
checkGraphInArcList(arc_set, n2, 1);
checkGraphInArcList(arc_set, n3, 0);
checkGraphConArcList(arc_set, 1);
ArcSet::Arc a2 = arc_set.addArc(n2, n1),
a3 = arc_set.addArc(n2, n3),
a4 = arc_set.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a2,a3,a4);
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 4);
checkGraphOutArcList(arc_set, n1, 1);
checkGraphOutArcList(arc_set, n2, 3);
checkGraphOutArcList(arc_set, n3, 0);
checkGraphInArcList(arc_set, n1, 1);
checkGraphInArcList(arc_set, n2, 1);
checkGraphInArcList(arc_set, n3, 2);
checkGraphConArcList(arc_set, 4);
checkNodeIds(arc_set);
checkArcIds(arc_set);
checkGraphNodeMap(arc_set);
checkGraphArcMap(arc_set);
check(arc_set.valid(), "Wrong validity");
digraph.erase(n1);
check(!arc_set.valid(), "Wrong validity");
}
void checkListArcSet() {
checkConcept<concepts::Digraph, SmartArcSet<ListDigraph> >();
typedef ListDigraph Digraph;
typedef ListArcSet<Digraph> ArcSet;
Digraph digraph;
Digraph::Node
n1 = digraph.addNode(),
n2 = digraph.addNode();
Digraph::Arc ga1 = digraph.addArc(n1, n2);
::lemon::ignore_unused_variable_warning(ga1);
ArcSet arc_set(digraph);
Digraph::Arc ga2 = digraph.addArc(n2, n1);
::lemon::ignore_unused_variable_warning(ga2);
checkGraphNodeList(arc_set, 2);
checkGraphArcList(arc_set, 0);
Digraph::Node
n3 = digraph.addNode();
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 0);
ArcSet::Arc a1 = arc_set.addArc(n1, n2);
check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc");
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 1);
checkGraphOutArcList(arc_set, n1, 1);
checkGraphOutArcList(arc_set, n2, 0);
checkGraphOutArcList(arc_set, n3, 0);
checkGraphInArcList(arc_set, n1, 0);
checkGraphInArcList(arc_set, n2, 1);
checkGraphInArcList(arc_set, n3, 0);
checkGraphConArcList(arc_set, 1);
ArcSet::Arc a2 = arc_set.addArc(n2, n1),
a3 = arc_set.addArc(n2, n3),
a4 = arc_set.addArc(n2, n3);
::lemon::ignore_unused_variable_warning(a2,a3,a4);
checkGraphNodeList(arc_set, 3);
checkGraphArcList(arc_set, 4);
checkGraphOutArcList(arc_set, n1, 1);
checkGraphOutArcList(arc_set, n2, 3);
checkGraphOutArcList(arc_set, n3, 0);
checkGraphInArcList(arc_set, n1, 1);
checkGraphInArcList(arc_set, n2, 1);
checkGraphInArcList(arc_set, n3, 2);
checkGraphConArcList(arc_set, 4);
checkNodeIds(arc_set);
checkArcIds(arc_set);
checkGraphNodeMap(arc_set);
checkGraphArcMap(arc_set);
digraph.erase(n1);
checkGraphNodeList(arc_set, 2);
checkGraphArcList(arc_set, 2);
checkGraphOutArcList(arc_set, n2, 2);
checkGraphOutArcList(arc_set, n3, 0);
checkGraphInArcList(arc_set, n2, 0);
checkGraphInArcList(arc_set, n3, 2);
checkNodeIds(arc_set);
checkArcIds(arc_set);
checkGraphNodeMap(arc_set);
checkGraphArcMap(arc_set);
checkGraphConArcList(arc_set, 2);
}
void checkSmartEdgeSet() {
checkConcept<concepts::Digraph, SmartEdgeSet<ListDigraph> >();
typedef ListDigraph Digraph;
typedef SmartEdgeSet<Digraph> EdgeSet;
Digraph digraph;
Digraph::Node
n1 = digraph.addNode(),
n2 = digraph.addNode();
Digraph::Arc ga1 = digraph.addArc(n1, n2);
::lemon::ignore_unused_variable_warning(ga1);
EdgeSet edge_set(digraph);
Digraph::Arc ga2 = digraph.addArc(n2, n1);
::lemon::ignore_unused_variable_warning(ga2);
checkGraphNodeList(edge_set, 2);
checkGraphArcList(edge_set, 0);
checkGraphEdgeList(edge_set, 0);
Digraph::Node
n3 = digraph.addNode();
checkGraphNodeList(edge_set, 3);
checkGraphArcList(edge_set, 0);
checkGraphEdgeList(edge_set, 0);
EdgeSet::Edge e1 = edge_set.addEdge(n1, n2);
check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) ||
(edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge");
checkGraphNodeList(edge_set, 3);
checkGraphArcList(edge_set, 2);
checkGraphEdgeList(edge_set, 1);
checkGraphOutArcList(edge_set, n1, 1);
checkGraphOutArcList(edge_set, n2, 1);
checkGraphOutArcList(edge_set, n3, 0);
checkGraphInArcList(edge_set, n1, 1);
checkGraphInArcList(edge_set, n2, 1);
checkGraphInArcList(edge_set, n3, 0);
checkGraphIncEdgeList(edge_set, n1, 1);
checkGraphIncEdgeList(edge_set, n2, 1);
checkGraphIncEdgeList(edge_set, n3, 0);
checkGraphConEdgeList(edge_set, 1);
checkGraphConArcList(edge_set, 2);
EdgeSet::Edge e2 = edge_set.addEdge(n2, n1),
e3 = edge_set.addEdge(n2, n3),
e4 = edge_set.addEdge(n2, n3);
::lemon::ignore_unused_variable_warning(e2,e3,e4);
checkGraphNodeList(edge_set, 3);
checkGraphEdgeList(edge_set, 4);
checkGraphOutArcList(edge_set, n1, 2);
checkGraphOutArcList(edge_set, n2, 4);
checkGraphOutArcList(edge_set, n3, 2);
checkGraphInArcList(edge_set, n1, 2);
checkGraphInArcList(edge_set, n2, 4);
checkGraphInArcList(edge_set, n3, 2);
checkGraphIncEdgeList(edge_set, n1, 2);
checkGraphIncEdgeList(edge_set, n2, 4);
checkGraphIncEdgeList(edge_set, n3, 2);
checkGraphConEdgeList(edge_set, 4);
checkGraphConArcList(edge_set, 8);
checkArcDirections(edge_set);
checkNodeIds(edge_set);
checkArcIds(edge_set);
checkEdgeIds(edge_set);
checkGraphNodeMap(edge_set);
checkGraphArcMap(edge_set);
checkGraphEdgeMap(edge_set);
check(edge_set.valid(), "Wrong validity");
digraph.erase(n1);
check(!edge_set.valid(), "Wrong validity");
}
void checkListEdgeSet() {
checkConcept<concepts::Digraph, ListEdgeSet<ListDigraph> >();
typedef ListDigraph Digraph;
typedef ListEdgeSet<Digraph> EdgeSet;
Digraph digraph;
Digraph::Node
n1 = digraph.addNode(),
n2 = digraph.addNode();
Digraph::Arc ga1 = digraph.addArc(n1, n2);
::lemon::ignore_unused_variable_warning(ga1);
EdgeSet edge_set(digraph);
Digraph::Arc ga2 = digraph.addArc(n2, n1);
::lemon::ignore_unused_variable_warning(ga2);
checkGraphNodeList(edge_set, 2);
checkGraphArcList(edge_set, 0);
checkGraphEdgeList(edge_set, 0);
Digraph::Node
n3 = digraph.addNode();
checkGraphNodeList(edge_set, 3);
checkGraphArcList(edge_set, 0);
checkGraphEdgeList(edge_set, 0);
EdgeSet::Edge e1 = edge_set.addEdge(n1, n2);
check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) ||
(edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge");
checkGraphNodeList(edge_set, 3);
checkGraphArcList(edge_set, 2);
checkGraphEdgeList(edge_set, 1);
checkGraphOutArcList(edge_set, n1, 1);
checkGraphOutArcList(edge_set, n2, 1);
checkGraphOutArcList(edge_set, n3, 0);
checkGraphInArcList(edge_set, n1, 1);
checkGraphInArcList(edge_set, n2, 1);
checkGraphInArcList(edge_set, n3, 0);
checkGraphIncEdgeList(edge_set, n1, 1);
checkGraphIncEdgeList(edge_set, n2, 1);
checkGraphIncEdgeList(edge_set, n3, 0);
checkGraphConEdgeList(edge_set, 1);
checkGraphConArcList(edge_set, 2);
EdgeSet::Edge e2 = edge_set.addEdge(n2, n1),
e3 = edge_set.addEdge(n2, n3),
e4 = edge_set.addEdge(n2, n3);
::lemon::ignore_unused_variable_warning(e2,e3,e4);
checkGraphNodeList(edge_set, 3);
checkGraphEdgeList(edge_set, 4);
checkGraphOutArcList(edge_set, n1, 2);
checkGraphOutArcList(edge_set, n2, 4);
checkGraphOutArcList(edge_set, n3, 2);
checkGraphInArcList(edge_set, n1, 2);
checkGraphInArcList(edge_set, n2, 4);
checkGraphInArcList(edge_set, n3, 2);
checkGraphIncEdgeList(edge_set, n1, 2);
checkGraphIncEdgeList(edge_set, n2, 4);
checkGraphIncEdgeList(edge_set, n3, 2);
checkGraphConEdgeList(edge_set, 4);
checkGraphConArcList(edge_set, 8);
checkArcDirections(edge_set);
checkNodeIds(edge_set);
checkArcIds(edge_set);
checkEdgeIds(edge_set);
checkGraphNodeMap(edge_set);
checkGraphArcMap(edge_set);
checkGraphEdgeMap(edge_set);
digraph.erase(n1);
checkGraphNodeList(edge_set, 2);
checkGraphArcList(edge_set, 4);
checkGraphEdgeList(edge_set, 2);
checkGraphOutArcList(edge_set, n2, 2);
checkGraphOutArcList(edge_set, n3, 2);
checkGraphInArcList(edge_set, n2, 2);
checkGraphInArcList(edge_set, n3, 2);
checkGraphIncEdgeList(edge_set, n2, 2);
checkGraphIncEdgeList(edge_set, n3, 2);
checkNodeIds(edge_set);
checkArcIds(edge_set);
checkEdgeIds(edge_set);
checkGraphNodeMap(edge_set);
checkGraphArcMap(edge_set);
checkGraphEdgeMap(edge_set);
checkGraphConEdgeList(edge_set, 2);
checkGraphConArcList(edge_set, 4);
}
int main() {
checkSmartArcSet();
checkListArcSet();
checkSmartEdgeSet();
checkListEdgeSet();
return 0;
}

View File

@@ -0,0 +1,90 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <lemon/error.h>
#include "test_tools.h"
using namespace lemon;
#ifdef LEMON_ENABLE_ASSERTS
#undef LEMON_ENABLE_ASSERTS
#endif
#ifdef LEMON_DISABLE_ASSERTS
#undef LEMON_DISABLE_ASSERTS
#endif
#ifdef NDEBUG
#undef NDEBUG
#endif
//checking disabled asserts
#define LEMON_DISABLE_ASSERTS
#include <lemon/assert.h>
void no_assertion_text_disable() {
LEMON_ASSERT(true, "This is a fault message");
}
void assertion_text_disable() {
LEMON_ASSERT(false, "This is a fault message");
}
void check_assertion_disable() {
no_assertion_text_disable();
assertion_text_disable();
}
#undef LEMON_DISABLE_ASSERTS
//checking custom assert handler
#define LEMON_ASSERT_CUSTOM
static int cnt = 0;
void my_assert_handler(const char*, int, const char*,
const char*, const char*) {
++cnt;
}
#define LEMON_CUSTOM_ASSERT_HANDLER my_assert_handler
#include <lemon/assert.h>
void no_assertion_text_custom() {
LEMON_ASSERT(true, "This is a fault message");
}
void assertion_text_custom() {
LEMON_ASSERT(false, "This is a fault message");
}
void check_assertion_custom() {
no_assertion_text_custom();
assertion_text_custom();
check(cnt == 1, "The custom assert handler does not work");
}
#undef LEMON_ASSERT_CUSTOM
int main() {
check_assertion_disable();
check_assertion_custom();
return 0;
}

View File

@@ -0,0 +1,225 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/euler.h>
#include <lemon/list_graph.h>
#include <lemon/adaptors.h>
#include "test_tools.h"
using namespace lemon;
template <typename Digraph>
void checkDiEulerIt(const Digraph& g,
const typename Digraph::Node& start = INVALID)
{
typename Digraph::template ArcMap<int> visitationNumber(g, 0);
DiEulerIt<Digraph> e(g, start);
if (e == INVALID) return;
typename Digraph::Node firstNode = g.source(e);
typename Digraph::Node lastNode = g.target(e);
if (start != INVALID) {
check(firstNode == start, "checkDiEulerIt: Wrong first node");
}
for (; e != INVALID; ++e) {
if (e != INVALID) lastNode = g.target(e);
++visitationNumber[e];
}
check(firstNode == lastNode,
"checkDiEulerIt: First and last nodes are not the same");
for (typename Digraph::ArcIt a(g); a != INVALID; ++a)
{
check(visitationNumber[a] == 1,
"checkDiEulerIt: Not visited or multiple times visited arc found");
}
}
template <typename Graph>
void checkEulerIt(const Graph& g,
const typename Graph::Node& start = INVALID)
{
typename Graph::template EdgeMap<int> visitationNumber(g, 0);
EulerIt<Graph> e(g, start);
if (e == INVALID) return;
typename Graph::Node firstNode = g.source(typename Graph::Arc(e));
typename Graph::Node lastNode = g.target(typename Graph::Arc(e));
if (start != INVALID) {
check(firstNode == start, "checkEulerIt: Wrong first node");
}
for (; e != INVALID; ++e) {
if (e != INVALID) lastNode = g.target(typename Graph::Arc(e));
++visitationNumber[e];
}
check(firstNode == lastNode,
"checkEulerIt: First and last nodes are not the same");
for (typename Graph::EdgeIt e(g); e != INVALID; ++e)
{
check(visitationNumber[e] == 1,
"checkEulerIt: Not visited or multiple times visited edge found");
}
}
int main()
{
typedef ListDigraph Digraph;
typedef Undirector<Digraph> Graph;
{
Digraph d;
Graph g(d);
checkDiEulerIt(d);
checkDiEulerIt(g);
checkEulerIt(g);
check(eulerian(d), "This graph is Eulerian");
check(eulerian(g), "This graph is Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n = d.addNode();
::lemon::ignore_unused_variable_warning(n);
checkDiEulerIt(d);
checkDiEulerIt(g);
checkEulerIt(g);
check(eulerian(d), "This graph is Eulerian");
check(eulerian(g), "This graph is Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n = d.addNode();
d.addArc(n, n);
checkDiEulerIt(d);
checkDiEulerIt(g);
checkEulerIt(g);
check(eulerian(d), "This graph is Eulerian");
check(eulerian(g), "This graph is Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
d.addArc(n1, n2);
d.addArc(n2, n1);
d.addArc(n2, n3);
d.addArc(n3, n2);
checkDiEulerIt(d);
checkDiEulerIt(d, n2);
checkDiEulerIt(g);
checkDiEulerIt(g, n2);
checkEulerIt(g);
checkEulerIt(g, n2);
check(eulerian(d), "This graph is Eulerian");
check(eulerian(g), "This graph is Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
Digraph::Node n4 = d.addNode();
Digraph::Node n5 = d.addNode();
Digraph::Node n6 = d.addNode();
d.addArc(n1, n2);
d.addArc(n2, n4);
d.addArc(n1, n3);
d.addArc(n3, n4);
d.addArc(n4, n1);
d.addArc(n3, n5);
d.addArc(n5, n2);
d.addArc(n4, n6);
d.addArc(n2, n6);
d.addArc(n6, n1);
d.addArc(n6, n3);
checkDiEulerIt(d);
checkDiEulerIt(d, n1);
checkDiEulerIt(d, n5);
checkDiEulerIt(g);
checkDiEulerIt(g, n1);
checkDiEulerIt(g, n5);
checkEulerIt(g);
checkEulerIt(g, n1);
checkEulerIt(g, n5);
check(eulerian(d), "This graph is Eulerian");
check(eulerian(g), "This graph is Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n0 = d.addNode();
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
Digraph::Node n4 = d.addNode();
Digraph::Node n5 = d.addNode();
::lemon::ignore_unused_variable_warning(n0,n4,n5);
d.addArc(n1, n2);
d.addArc(n2, n3);
d.addArc(n3, n1);
checkDiEulerIt(d);
checkDiEulerIt(d, n2);
checkDiEulerIt(g);
checkDiEulerIt(g, n2);
checkEulerIt(g);
checkEulerIt(g, n2);
check(!eulerian(d), "This graph is not Eulerian");
check(!eulerian(g), "This graph is not Eulerian");
}
{
Digraph d;
Graph g(d);
Digraph::Node n1 = d.addNode();
Digraph::Node n2 = d.addNode();
Digraph::Node n3 = d.addNode();
d.addArc(n1, n2);
d.addArc(n2, n3);
check(!eulerian(d), "This graph is not Eulerian");
check(!eulerian(g), "This graph is not Eulerian");
}
return 0;
}

View File

@@ -0,0 +1,527 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <queue>
#include <cstdlib>
#include <lemon/fractional_matching.h>
#include <lemon/smart_graph.h>
#include <lemon/concepts/graph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/math.h>
#include "test_tools.h"
using namespace std;
using namespace lemon;
GRAPH_TYPEDEFS(SmartGraph);
const int lgfn = 4;
const std::string lgf[lgfn] = {
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"7 4 0 984\n"
"0 7 1 73\n"
"7 1 2 204\n"
"2 3 3 583\n"
"2 7 4 565\n"
"2 1 5 582\n"
"0 4 6 551\n"
"2 5 7 385\n"
"1 5 8 561\n"
"5 3 9 484\n"
"7 5 10 904\n"
"3 6 11 47\n"
"7 6 12 888\n"
"3 0 13 747\n"
"6 1 14 310\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"2 5 0 710\n"
"0 5 1 241\n"
"2 4 2 856\n"
"2 6 3 762\n"
"4 1 4 747\n"
"6 1 5 962\n"
"4 7 6 723\n"
"1 7 7 661\n"
"2 3 8 376\n"
"1 0 9 416\n"
"6 7 10 391\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"6 2 0 553\n"
"0 7 1 653\n"
"6 3 2 22\n"
"4 7 3 846\n"
"7 2 4 981\n"
"7 6 5 250\n"
"5 2 6 539\n",
"@nodes\n"
"label\n"
"0\n"
"@edges\n"
" label weight\n"
"0 0 0 100\n"
};
void checkMaxFractionalMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
Graph g;
Node n;
Edge e;
MaxFractionalMatching<Graph> mat_test(g);
const MaxFractionalMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.start();
mat_test.start(true);
mat_test.startPerfect();
mat_test.startPerfect(true);
mat_test.run();
mat_test.run(true);
mat_test.runPerfect();
mat_test.runPerfect(true);
const_mat_test.matchingSize();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxFractionalMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.barrier(n);
}
void checkMaxWeightedFractionalMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef Graph::EdgeMap<int> WeightMap;
Graph g;
Node n;
Edge e;
WeightMap w(g);
MaxWeightedFractionalMatching<Graph> mat_test(g, w);
const MaxWeightedFractionalMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.start();
mat_test.run();
const_mat_test.matchingWeight();
const_mat_test.matchingSize();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxWeightedFractionalMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.dualValue();
const_mat_test.nodeValue(n);
}
void checkMaxWeightedPerfectFractionalMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef Graph::EdgeMap<int> WeightMap;
Graph g;
Node n;
Edge e;
WeightMap w(g);
MaxWeightedPerfectFractionalMatching<Graph> mat_test(g, w);
const MaxWeightedPerfectFractionalMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.start();
mat_test.run();
const_mat_test.matchingWeight();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxWeightedPerfectFractionalMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.dualValue();
const_mat_test.nodeValue(n);
}
void checkFractionalMatching(const SmartGraph& graph,
const MaxFractionalMatching<SmartGraph>& mfm,
bool allow_loops = true) {
int pv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
int indeg = 0;
for (InArcIt a(graph, n); a != INVALID; ++a) {
if (mfm.matching(graph.source(a)) == a) {
++indeg;
}
}
if (mfm.matching(n) != INVALID) {
check(indeg == 1, "Invalid matching");
++pv;
} else {
check(indeg == 0, "Invalid matching");
}
}
check(pv == mfm.matchingSize(), "Wrong matching size");
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
(e == mfm.matching(graph.v(e)) ? 1 : 0) ==
mfm.matching(e), "Invalid matching");
}
SmartGraph::NodeMap<bool> processed(graph, false);
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (processed[n]) continue;
processed[n] = true;
if (mfm.matching(n) == INVALID) continue;
int num = 1;
Node v = graph.target(mfm.matching(n));
while (v != n) {
processed[v] = true;
++num;
v = graph.target(mfm.matching(v));
}
check(num == 2 || num % 2 == 1, "Wrong cycle size");
check(allow_loops || num != 1, "Wrong cycle size");
}
int anum = 0, bnum = 0;
SmartGraph::NodeMap<bool> neighbours(graph, false);
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (!mfm.barrier(n)) continue;
++anum;
for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
Node u = graph.source(a);
if (!allow_loops && u == n) continue;
if (!neighbours[u]) {
neighbours[u] = true;
++bnum;
}
}
}
check(anum - bnum + mfm.matchingSize() == countNodes(graph),
"Wrong barrier");
}
void checkPerfectFractionalMatching(const SmartGraph& graph,
const MaxFractionalMatching<SmartGraph>& mfm,
bool perfect, bool allow_loops = true) {
if (perfect) {
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
int indeg = 0;
for (InArcIt a(graph, n); a != INVALID; ++a) {
if (mfm.matching(graph.source(a)) == a) {
++indeg;
}
}
check(mfm.matching(n) != INVALID, "Invalid matching");
check(indeg == 1, "Invalid matching");
}
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
check((e == mfm.matching(graph.u(e)) ? 1 : 0) +
(e == mfm.matching(graph.v(e)) ? 1 : 0) ==
mfm.matching(e), "Invalid matching");
}
} else {
int anum = 0, bnum = 0;
SmartGraph::NodeMap<bool> neighbours(graph, false);
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (!mfm.barrier(n)) continue;
++anum;
for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) {
Node u = graph.source(a);
if (!allow_loops && u == n) continue;
if (!neighbours[u]) {
neighbours[u] = true;
++bnum;
}
}
}
check(anum - bnum > 0, "Wrong barrier");
}
}
void checkWeightedFractionalMatching(const SmartGraph& graph,
const SmartGraph::EdgeMap<int>& weight,
const MaxWeightedFractionalMatching<SmartGraph>& mwfm,
bool allow_loops = true) {
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
if (graph.u(e) == graph.v(e) && !allow_loops) continue;
int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e))
- weight[e] * mwfm.dualScale;
check(rw >= 0, "Negative reduced weight");
check(rw == 0 || !mwfm.matching(e),
"Non-zero reduced weight on matching edge");
}
int pv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
int indeg = 0;
for (InArcIt a(graph, n); a != INVALID; ++a) {
if (mwfm.matching(graph.source(a)) == a) {
++indeg;
}
}
check(indeg <= 1, "Invalid matching");
if (mwfm.matching(n) != INVALID) {
check(mwfm.nodeValue(n) >= 0, "Invalid node value");
check(indeg == 1, "Invalid matching");
pv += weight[mwfm.matching(n)];
SmartGraph::Node o = graph.target(mwfm.matching(n));
::lemon::ignore_unused_variable_warning(o);
} else {
check(mwfm.nodeValue(n) == 0, "Invalid matching");
check(indeg == 0, "Invalid matching");
}
}
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
check((e == mwfm.matching(graph.u(e)) ? 1 : 0) +
(e == mwfm.matching(graph.v(e)) ? 1 : 0) ==
mwfm.matching(e), "Invalid matching");
}
int dv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
dv += mwfm.nodeValue(n);
}
check(pv * mwfm.dualScale == dv * 2, "Wrong duality");
SmartGraph::NodeMap<bool> processed(graph, false);
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (processed[n]) continue;
processed[n] = true;
if (mwfm.matching(n) == INVALID) continue;
int num = 1;
Node v = graph.target(mwfm.matching(n));
while (v != n) {
processed[v] = true;
++num;
v = graph.target(mwfm.matching(v));
}
check(num == 2 || num % 2 == 1, "Wrong cycle size");
check(allow_loops || num != 1, "Wrong cycle size");
}
return;
}
void checkWeightedPerfectFractionalMatching(const SmartGraph& graph,
const SmartGraph::EdgeMap<int>& weight,
const MaxWeightedPerfectFractionalMatching<SmartGraph>& mwpfm,
bool allow_loops = true) {
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
if (graph.u(e) == graph.v(e) && !allow_loops) continue;
int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e))
- weight[e] * mwpfm.dualScale;
check(rw >= 0, "Negative reduced weight");
check(rw == 0 || !mwpfm.matching(e),
"Non-zero reduced weight on matching edge");
}
int pv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
int indeg = 0;
for (InArcIt a(graph, n); a != INVALID; ++a) {
if (mwpfm.matching(graph.source(a)) == a) {
++indeg;
}
}
check(mwpfm.matching(n) != INVALID, "Invalid perfect matching");
check(indeg == 1, "Invalid perfect matching");
pv += weight[mwpfm.matching(n)];
SmartGraph::Node o = graph.target(mwpfm.matching(n));
::lemon::ignore_unused_variable_warning(o);
}
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) +
(e == mwpfm.matching(graph.v(e)) ? 1 : 0) ==
mwpfm.matching(e), "Invalid matching");
}
int dv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
dv += mwpfm.nodeValue(n);
}
check(pv * mwpfm.dualScale == dv * 2, "Wrong duality");
SmartGraph::NodeMap<bool> processed(graph, false);
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (processed[n]) continue;
processed[n] = true;
if (mwpfm.matching(n) == INVALID) continue;
int num = 1;
Node v = graph.target(mwpfm.matching(n));
while (v != n) {
processed[v] = true;
++num;
v = graph.target(mwpfm.matching(v));
}
check(num == 2 || num % 2 == 1, "Wrong cycle size");
check(allow_loops || num != 1, "Wrong cycle size");
}
return;
}
int main() {
for (int i = 0; i < lgfn; ++i) {
SmartGraph graph;
SmartGraph::EdgeMap<int> weight(graph);
istringstream lgfs(lgf[i]);
graphReader(graph, lgfs).
edgeMap("weight", weight).run();
bool perfect_with_loops;
{
MaxFractionalMatching<SmartGraph> mfm(graph, true);
mfm.run();
checkFractionalMatching(graph, mfm, true);
perfect_with_loops = mfm.matchingSize() == countNodes(graph);
}
bool perfect_without_loops;
{
MaxFractionalMatching<SmartGraph> mfm(graph, false);
mfm.run();
checkFractionalMatching(graph, mfm, false);
perfect_without_loops = mfm.matchingSize() == countNodes(graph);
}
{
MaxFractionalMatching<SmartGraph> mfm(graph, true);
bool result = mfm.runPerfect();
checkPerfectFractionalMatching(graph, mfm, result, true);
check(result == perfect_with_loops, "Wrong perfect matching");
}
{
MaxFractionalMatching<SmartGraph> mfm(graph, false);
bool result = mfm.runPerfect();
checkPerfectFractionalMatching(graph, mfm, result, false);
check(result == perfect_without_loops, "Wrong perfect matching");
}
{
MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, true);
mwfm.run();
checkWeightedFractionalMatching(graph, weight, mwfm, true);
}
{
MaxWeightedFractionalMatching<SmartGraph> mwfm(graph, weight, false);
mwfm.run();
checkWeightedFractionalMatching(graph, weight, mwfm, false);
}
{
MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight,
true);
bool perfect = mwpfm.run();
check(perfect == (mwpfm.matchingSize() == countNodes(graph)),
"Perfect matching found");
check(perfect == perfect_with_loops, "Wrong perfect matching");
if (perfect) {
checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, true);
}
}
{
MaxWeightedPerfectFractionalMatching<SmartGraph> mwpfm(graph, weight,
false);
bool perfect = mwpfm.run();
check(perfect == (mwpfm.matchingSize() == countNodes(graph)),
"Perfect matching found");
check(perfect == perfect_without_loops, "Wrong perfect matching");
if (perfect) {
checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, false);
}
}
}
return 0;
}

View File

@@ -0,0 +1,142 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include "test_tools.h"
#include <lemon/smart_graph.h>
#include <lemon/concepts/graph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/gomory_hu.h>
#include <cstdlib>
using namespace std;
using namespace lemon;
typedef SmartGraph Graph;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"@arcs\n"
" label capacity\n"
"0 1 0 1\n"
"1 2 1 1\n"
"2 3 2 1\n"
"0 3 4 5\n"
"0 3 5 10\n"
"0 3 6 7\n"
"4 2 7 1\n"
"@attributes\n"
"source 0\n"
"target 3\n";
void checkGomoryHuCompile()
{
typedef int Value;
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef concepts::ReadMap<Edge, Value> CapMap;
typedef concepts::ReadWriteMap<Node, bool> CutMap;
Graph g;
Node n;
CapMap cap;
CutMap cut;
Value v;
int d;
::lemon::ignore_unused_variable_warning(v,d);
GomoryHu<Graph, CapMap> gh_test(g, cap);
const GomoryHu<Graph, CapMap>&
const_gh_test = gh_test;
gh_test.run();
n = const_gh_test.predNode(n);
v = const_gh_test.predValue(n);
d = const_gh_test.rootDist(n);
v = const_gh_test.minCutValue(n, n);
v = const_gh_test.minCutMap(n, n, cut);
}
GRAPH_TYPEDEFS(Graph);
typedef Graph::EdgeMap<int> IntEdgeMap;
typedef Graph::NodeMap<bool> BoolNodeMap;
int cutValue(const Graph& graph, const BoolNodeMap& cut,
const IntEdgeMap& capacity) {
int sum = 0;
for (EdgeIt e(graph); e != INVALID; ++e) {
Node s = graph.u(e);
Node t = graph.v(e);
if (cut[s] != cut[t]) {
sum += capacity[e];
}
}
return sum;
}
int main() {
Graph graph;
IntEdgeMap capacity(graph);
std::istringstream input(test_lgf);
GraphReader<Graph>(graph, input).
edgeMap("capacity", capacity).run();
GomoryHu<Graph> ght(graph, capacity);
ght.run();
for (NodeIt u(graph); u != INVALID; ++u) {
for (NodeIt v(graph); v != u; ++v) {
Preflow<Graph, IntEdgeMap> pf(graph, capacity, u, v);
pf.runMinCut();
BoolNodeMap cm(graph);
ght.minCutMap(u, v, cm);
check(pf.flowValue() == ght.minCutValue(u, v), "Wrong cut 1");
check(cm[u] != cm[v], "Wrong cut 2");
check(pf.flowValue() == cutValue(graph, cm, capacity), "Wrong cut 3");
int sum=0;
for(GomoryHu<Graph>::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a)
sum+=capacity[a];
check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt");
sum=0;
for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,true);n!=INVALID;++n)
sum++;
for(GomoryHu<Graph>::MinCutNodeIt n(ght, u, v,false);n!=INVALID;++n)
sum++;
check(sum == countNodes(graph), "Problem with MinCutNodeIt");
}
}
return 0;
}

View File

@@ -0,0 +1,388 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/static_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/error.h>
#include "test_tools.h"
using namespace std;
using namespace lemon;
template <typename GR>
void digraph_copy_test() {
const int nn = 10;
// Build a digraph
SmartDigraph from;
SmartDigraph::NodeMap<int> fnm(from);
SmartDigraph::ArcMap<int> fam(from);
SmartDigraph::Node fn = INVALID;
SmartDigraph::Arc fa = INVALID;
std::vector<SmartDigraph::Node> fnv;
for (int i = 0; i < nn; ++i) {
SmartDigraph::Node node = from.addNode();
fnv.push_back(node);
fnm[node] = i * i;
if (i == 0) fn = node;
}
for (int i = 0; i < nn; ++i) {
for (int j = 0; j < nn; ++j) {
SmartDigraph::Arc arc = from.addArc(fnv[i], fnv[j]);
fam[arc] = i + j * j;
if (i == 0 && j == 0) fa = arc;
}
}
// Test digraph copy
GR to;
typename GR::template NodeMap<int> tnm(to);
typename GR::template ArcMap<int> tam(to);
typename GR::Node tn;
typename GR::Arc ta;
SmartDigraph::NodeMap<typename GR::Node> nr(from);
SmartDigraph::ArcMap<typename GR::Arc> er(from);
typename GR::template NodeMap<SmartDigraph::Node> ncr(to);
typename GR::template ArcMap<SmartDigraph::Arc> ecr(to);
digraphCopy(from, to).
nodeMap(fnm, tnm).arcMap(fam, tam).
nodeRef(nr).arcRef(er).
nodeCrossRef(ncr).arcCrossRef(ecr).
node(fn, tn).arc(fa, ta).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
for (SmartDigraph::NodeIt it(from); it != INVALID; ++it) {
check(ncr[nr[it]] == it, "Wrong copy.");
check(fnm[it] == tnm[nr[it]], "Wrong copy.");
}
for (SmartDigraph::ArcIt it(from); it != INVALID; ++it) {
check(ecr[er[it]] == it, "Wrong copy.");
check(fam[it] == tam[er[it]], "Wrong copy.");
check(nr[from.source(it)] == to.source(er[it]), "Wrong copy.");
check(nr[from.target(it)] == to.target(er[it]), "Wrong copy.");
}
for (typename GR::NodeIt it(to); it != INVALID; ++it) {
check(nr[ncr[it]] == it, "Wrong copy.");
}
for (typename GR::ArcIt it(to); it != INVALID; ++it) {
check(er[ecr[it]] == it, "Wrong copy.");
}
check(tn == nr[fn], "Wrong copy.");
check(ta == er[fa], "Wrong copy.");
// Test repeated copy
digraphCopy(from, to).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
}
template <typename GR>
void graph_copy_test() {
const int nn = 10;
// Build a graph
SmartGraph from;
SmartGraph::NodeMap<int> fnm(from);
SmartGraph::ArcMap<int> fam(from);
SmartGraph::EdgeMap<int> fem(from);
SmartGraph::Node fn = INVALID;
SmartGraph::Arc fa = INVALID;
SmartGraph::Edge fe = INVALID;
std::vector<SmartGraph::Node> fnv;
for (int i = 0; i < nn; ++i) {
SmartGraph::Node node = from.addNode();
fnv.push_back(node);
fnm[node] = i * i;
if (i == 0) fn = node;
}
for (int i = 0; i < nn; ++i) {
for (int j = 0; j < nn; ++j) {
SmartGraph::Edge edge = from.addEdge(fnv[i], fnv[j]);
fem[edge] = i * i + j * j;
fam[from.direct(edge, true)] = i + j * j;
fam[from.direct(edge, false)] = i * i + j;
if (i == 0 && j == 0) fa = from.direct(edge, true);
if (i == 0 && j == 0) fe = edge;
}
}
// Test graph copy
GR to;
typename GR::template NodeMap<int> tnm(to);
typename GR::template ArcMap<int> tam(to);
typename GR::template EdgeMap<int> tem(to);
typename GR::Node tn;
typename GR::Arc ta;
typename GR::Edge te;
SmartGraph::NodeMap<typename GR::Node> nr(from);
SmartGraph::ArcMap<typename GR::Arc> ar(from);
SmartGraph::EdgeMap<typename GR::Edge> er(from);
typename GR::template NodeMap<SmartGraph::Node> ncr(to);
typename GR::template ArcMap<SmartGraph::Arc> acr(to);
typename GR::template EdgeMap<SmartGraph::Edge> ecr(to);
graphCopy(from, to).
nodeMap(fnm, tnm).arcMap(fam, tam).edgeMap(fem, tem).
nodeRef(nr).arcRef(ar).edgeRef(er).
nodeCrossRef(ncr).arcCrossRef(acr).edgeCrossRef(ecr).
node(fn, tn).arc(fa, ta).edge(fe, te).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countEdges(from) == countEdges(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
for (SmartGraph::NodeIt it(from); it != INVALID; ++it) {
check(ncr[nr[it]] == it, "Wrong copy.");
check(fnm[it] == tnm[nr[it]], "Wrong copy.");
}
for (SmartGraph::ArcIt it(from); it != INVALID; ++it) {
check(acr[ar[it]] == it, "Wrong copy.");
check(fam[it] == tam[ar[it]], "Wrong copy.");
check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy.");
check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy.");
}
for (SmartGraph::EdgeIt it(from); it != INVALID; ++it) {
check(ecr[er[it]] == it, "Wrong copy.");
check(fem[it] == tem[er[it]], "Wrong copy.");
check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]),
"Wrong copy.");
check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]),
"Wrong copy.");
check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])),
"Wrong copy.");
}
for (typename GR::NodeIt it(to); it != INVALID; ++it) {
check(nr[ncr[it]] == it, "Wrong copy.");
}
for (typename GR::ArcIt it(to); it != INVALID; ++it) {
check(ar[acr[it]] == it, "Wrong copy.");
}
for (typename GR::EdgeIt it(to); it != INVALID; ++it) {
check(er[ecr[it]] == it, "Wrong copy.");
}
check(tn == nr[fn], "Wrong copy.");
check(ta == ar[fa], "Wrong copy.");
check(te == er[fe], "Wrong copy.");
// Test repeated copy
graphCopy(from, to).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countEdges(from) == countEdges(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
}
template <typename GR>
void bpgraph_copy_test() {
const int nn = 10;
// Build a graph
SmartBpGraph from;
SmartBpGraph::NodeMap<int> fnm(from);
SmartBpGraph::RedNodeMap<int> frnm(from);
SmartBpGraph::BlueNodeMap<int> fbnm(from);
SmartBpGraph::ArcMap<int> fam(from);
SmartBpGraph::EdgeMap<int> fem(from);
SmartBpGraph::Node fn = INVALID;
SmartBpGraph::RedNode frn = INVALID;
SmartBpGraph::BlueNode fbn = INVALID;
SmartBpGraph::Arc fa = INVALID;
SmartBpGraph::Edge fe = INVALID;
std::vector<SmartBpGraph::RedNode> frnv;
for (int i = 0; i < nn; ++i) {
SmartBpGraph::RedNode node = from.addRedNode();
frnv.push_back(node);
fnm[node] = i * i;
frnm[node] = i + i;
if (i == 0) {
fn = node;
frn = node;
}
}
std::vector<SmartBpGraph::BlueNode> fbnv;
for (int i = 0; i < nn; ++i) {
SmartBpGraph::BlueNode node = from.addBlueNode();
fbnv.push_back(node);
fnm[node] = i * i;
fbnm[node] = i + i;
if (i == 0) fbn = node;
}
for (int i = 0; i < nn; ++i) {
for (int j = 0; j < nn; ++j) {
SmartBpGraph::Edge edge = from.addEdge(frnv[i], fbnv[j]);
fem[edge] = i * i + j * j;
fam[from.direct(edge, true)] = i + j * j;
fam[from.direct(edge, false)] = i * i + j;
if (i == 0 && j == 0) fa = from.direct(edge, true);
if (i == 0 && j == 0) fe = edge;
}
}
// Test graph copy
GR to;
typename GR::template NodeMap<int> tnm(to);
typename GR::template RedNodeMap<int> trnm(to);
typename GR::template BlueNodeMap<int> tbnm(to);
typename GR::template ArcMap<int> tam(to);
typename GR::template EdgeMap<int> tem(to);
typename GR::Node tn;
typename GR::RedNode trn;
typename GR::BlueNode tbn;
typename GR::Arc ta;
typename GR::Edge te;
SmartBpGraph::NodeMap<typename GR::Node> nr(from);
SmartBpGraph::RedNodeMap<typename GR::RedNode> rnr(from);
SmartBpGraph::BlueNodeMap<typename GR::BlueNode> bnr(from);
SmartBpGraph::ArcMap<typename GR::Arc> ar(from);
SmartBpGraph::EdgeMap<typename GR::Edge> er(from);
typename GR::template NodeMap<SmartBpGraph::Node> ncr(to);
typename GR::template RedNodeMap<SmartBpGraph::RedNode> rncr(to);
typename GR::template BlueNodeMap<SmartBpGraph::BlueNode> bncr(to);
typename GR::template ArcMap<SmartBpGraph::Arc> acr(to);
typename GR::template EdgeMap<SmartBpGraph::Edge> ecr(to);
bpGraphCopy(from, to).
nodeMap(fnm, tnm).
redNodeMap(frnm, trnm).blueNodeMap(fbnm, tbnm).
arcMap(fam, tam).edgeMap(fem, tem).
nodeRef(nr).redRef(rnr).blueRef(bnr).
arcRef(ar).edgeRef(er).
nodeCrossRef(ncr).redCrossRef(rncr).blueCrossRef(bncr).
arcCrossRef(acr).edgeCrossRef(ecr).
node(fn, tn).redNode(frn, trn).blueNode(fbn, tbn).
arc(fa, ta).edge(fe, te).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countRedNodes(from) == countRedNodes(to), "Wrong copy.");
check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy.");
check(countEdges(from) == countEdges(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
for (SmartBpGraph::NodeIt it(from); it != INVALID; ++it) {
check(ncr[nr[it]] == it, "Wrong copy.");
check(fnm[it] == tnm[nr[it]], "Wrong copy.");
}
for (SmartBpGraph::RedNodeIt it(from); it != INVALID; ++it) {
check(ncr[nr[it]] == it, "Wrong copy.");
check(fnm[it] == tnm[nr[it]], "Wrong copy.");
check(rnr[it] == nr[it], "Wrong copy.");
check(rncr[rnr[it]] == it, "Wrong copy.");
check(frnm[it] == trnm[rnr[it]], "Wrong copy.");
check(to.red(rnr[it]), "Wrong copy.");
}
for (SmartBpGraph::BlueNodeIt it(from); it != INVALID; ++it) {
check(ncr[nr[it]] == it, "Wrong copy.");
check(fnm[it] == tnm[nr[it]], "Wrong copy.");
check(bnr[it] == nr[it], "Wrong copy.");
check(bncr[bnr[it]] == it, "Wrong copy.");
check(fbnm[it] == tbnm[bnr[it]], "Wrong copy.");
check(to.blue(bnr[it]), "Wrong copy.");
}
for (SmartBpGraph::ArcIt it(from); it != INVALID; ++it) {
check(acr[ar[it]] == it, "Wrong copy.");
check(fam[it] == tam[ar[it]], "Wrong copy.");
check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy.");
check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy.");
}
for (SmartBpGraph::EdgeIt it(from); it != INVALID; ++it) {
check(ecr[er[it]] == it, "Wrong copy.");
check(fem[it] == tem[er[it]], "Wrong copy.");
check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]),
"Wrong copy.");
check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]),
"Wrong copy.");
check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])),
"Wrong copy.");
}
for (typename GR::NodeIt it(to); it != INVALID; ++it) {
check(nr[ncr[it]] == it, "Wrong copy.");
}
for (typename GR::RedNodeIt it(to); it != INVALID; ++it) {
check(rncr[it] == ncr[it], "Wrong copy.");
check(rnr[rncr[it]] == it, "Wrong copy.");
}
for (typename GR::BlueNodeIt it(to); it != INVALID; ++it) {
check(bncr[it] == ncr[it], "Wrong copy.");
check(bnr[bncr[it]] == it, "Wrong copy.");
}
for (typename GR::ArcIt it(to); it != INVALID; ++it) {
check(ar[acr[it]] == it, "Wrong copy.");
}
for (typename GR::EdgeIt it(to); it != INVALID; ++it) {
check(er[ecr[it]] == it, "Wrong copy.");
}
check(tn == nr[fn], "Wrong copy.");
check(trn == rnr[frn], "Wrong copy.");
check(tbn == bnr[fbn], "Wrong copy.");
check(ta == ar[fa], "Wrong copy.");
check(te == er[fe], "Wrong copy.");
// Test repeated copy
bpGraphCopy(from, to).run();
check(countNodes(from) == countNodes(to), "Wrong copy.");
check(countRedNodes(from) == countRedNodes(to), "Wrong copy.");
check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy.");
check(countEdges(from) == countEdges(to), "Wrong copy.");
check(countArcs(from) == countArcs(to), "Wrong copy.");
}
int main() {
digraph_copy_test<SmartDigraph>();
digraph_copy_test<ListDigraph>();
digraph_copy_test<StaticDigraph>();
graph_copy_test<SmartGraph>();
graph_copy_test<ListGraph>();
bpgraph_copy_test<SmartBpGraph>();
bpgraph_copy_test<ListBpGraph>();
return 0;
}

View File

@@ -0,0 +1,603 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/concepts/graph.h>
#include <lemon/list_graph.h>
#include <lemon/smart_graph.h>
#include <lemon/full_graph.h>
#include <lemon/grid_graph.h>
#include <lemon/hypercube_graph.h>
#include "test_tools.h"
#include "graph_test.h"
using namespace lemon;
using namespace lemon::concepts;
template <class Graph>
void checkGraphBuild() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph G;
checkGraphNodeList(G, 0);
checkGraphEdgeList(G, 0);
checkGraphArcList(G, 0);
G.reserveNode(3);
G.reserveEdge(3);
Node
n1 = G.addNode(),
n2 = G.addNode(),
n3 = G.addNode();
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 0);
checkGraphArcList(G, 0);
Edge e1 = G.addEdge(n1, n2);
check((G.u(e1) == n1 && G.v(e1) == n2) || (G.u(e1) == n2 && G.v(e1) == n1),
"Wrong edge");
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 1);
checkGraphArcList(G, 2);
checkGraphIncEdgeArcLists(G, n1, 1);
checkGraphIncEdgeArcLists(G, n2, 1);
checkGraphIncEdgeArcLists(G, n3, 0);
checkGraphConEdgeList(G, 1);
checkGraphConArcList(G, 2);
Edge e2 = G.addEdge(n2, n1),
e3 = G.addEdge(n2, n3);
::lemon::ignore_unused_variable_warning(e2,e3);
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 3);
checkGraphIncEdgeArcLists(G, n3, 1);
checkGraphConEdgeList(G, 3);
checkGraphConArcList(G, 6);
checkArcDirections(G);
checkNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
}
template <class Graph>
void checkGraphAlter() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph G;
Node n1 = G.addNode(), n2 = G.addNode(),
n3 = G.addNode(), n4 = G.addNode();
Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4),
e5 = G.addEdge(n4, n3);
::lemon::ignore_unused_variable_warning(e1,e3,e4,e5);
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 5);
checkGraphArcList(G, 10);
// Check changeU() and changeV()
if (G.u(e2) == n2) {
G.changeU(e2, n3);
} else {
G.changeV(e2, n3);
}
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 5);
checkGraphArcList(G, 10);
checkGraphIncEdgeArcLists(G, n1, 3);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphIncEdgeArcLists(G, n3, 3);
checkGraphIncEdgeArcLists(G, n4, 2);
checkGraphConEdgeList(G, 5);
checkGraphConArcList(G, 10);
if (G.u(e2) == n1) {
G.changeU(e2, n2);
} else {
G.changeV(e2, n2);
}
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 5);
checkGraphArcList(G, 10);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 3);
checkGraphIncEdgeArcLists(G, n3, 3);
checkGraphIncEdgeArcLists(G, n4, 2);
checkGraphConEdgeList(G, 5);
checkGraphConArcList(G, 10);
// Check contract()
G.contract(n1, n4, false);
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 5);
checkGraphArcList(G, 10);
checkGraphIncEdgeArcLists(G, n1, 4);
checkGraphIncEdgeArcLists(G, n2, 3);
checkGraphIncEdgeArcLists(G, n3, 3);
checkGraphConEdgeList(G, 5);
checkGraphConArcList(G, 10);
G.contract(n2, n3);
checkGraphNodeList(G, 2);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
checkGraphIncEdgeArcLists(G, n1, 4);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphConEdgeList(G, 3);
checkGraphConArcList(G, 6);
}
template <class Graph>
void checkGraphErase() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph G;
Node n1 = G.addNode(), n2 = G.addNode(),
n3 = G.addNode(), n4 = G.addNode();
Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4),
e5 = G.addEdge(n4, n3);
::lemon::ignore_unused_variable_warning(e1,e3,e4,e5);
// Check edge deletion
G.erase(e2);
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 4);
checkGraphArcList(G, 8);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 2);
checkGraphIncEdgeArcLists(G, n3, 2);
checkGraphIncEdgeArcLists(G, n4, 2);
checkGraphConEdgeList(G, 4);
checkGraphConArcList(G, 8);
// Check node deletion
G.erase(n3);
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 2);
checkGraphArcList(G, 4);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 1);
checkGraphIncEdgeArcLists(G, n4, 1);
checkGraphConEdgeList(G, 2);
checkGraphConArcList(G, 4);
}
template <class Graph>
void checkGraphSnapshot() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph G;
Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode();
Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1),
e3 = G.addEdge(n2, n3);
::lemon::ignore_unused_variable_warning(e1,e2,e3);
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
typename Graph::Snapshot snapshot(G);
Node n = G.addNode();
G.addEdge(n3, n);
G.addEdge(n, n3);
G.addEdge(n3, n2);
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 6);
checkGraphArcList(G, 12);
snapshot.restore();
checkGraphNodeList(G, 3);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
checkGraphIncEdgeArcLists(G, n1, 2);
checkGraphIncEdgeArcLists(G, n2, 3);
checkGraphIncEdgeArcLists(G, n3, 1);
checkGraphConEdgeList(G, 3);
checkGraphConArcList(G, 6);
checkNodeIds(G);
checkEdgeIds(G);
checkArcIds(G);
checkGraphNodeMap(G);
checkGraphEdgeMap(G);
checkGraphArcMap(G);
G.addNode();
snapshot.save(G);
G.addEdge(G.addNode(), G.addNode());
snapshot.restore();
snapshot.save(G);
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
G.addEdge(G.addNode(), G.addNode());
snapshot.restore();
checkGraphNodeList(G, 4);
checkGraphEdgeList(G, 3);
checkGraphArcList(G, 6);
}
void checkFullGraph(int num) {
typedef FullGraph Graph;
GRAPH_TYPEDEFS(Graph);
Graph G(num);
check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2,
"Wrong size");
G.resize(num);
check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2,
"Wrong size");
checkGraphNodeList(G, num);
checkGraphEdgeList(G, num * (num - 1) / 2);
for (NodeIt n(G); n != INVALID; ++n) {
checkGraphOutArcList(G, n, num - 1);
checkGraphInArcList(G, n, num - 1);
checkGraphIncEdgeList(G, n, num - 1);
}
checkGraphConArcList(G, num * (num - 1));
checkGraphConEdgeList(G, num * (num - 1) / 2);
checkArcDirections(G);
checkNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
for (int i = 0; i < G.nodeNum(); ++i) {
check(G.index(G(i)) == i, "Wrong index");
}
for (NodeIt u(G); u != INVALID; ++u) {
for (NodeIt v(G); v != INVALID; ++v) {
Edge e = G.edge(u, v);
Arc a = G.arc(u, v);
if (u == v) {
check(e == INVALID, "Wrong edge lookup");
check(a == INVALID, "Wrong arc lookup");
} else {
check((G.u(e) == u && G.v(e) == v) ||
(G.u(e) == v && G.v(e) == u), "Wrong edge lookup");
check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup");
}
}
}
}
void checkConcepts() {
{ // Checking graph components
checkConcept<BaseGraphComponent, BaseGraphComponent >();
checkConcept<IDableGraphComponent<>,
IDableGraphComponent<> >();
checkConcept<IterableGraphComponent<>,
IterableGraphComponent<> >();
checkConcept<MappableGraphComponent<>,
MappableGraphComponent<> >();
}
{ // Checking skeleton graph
checkConcept<Graph, Graph>();
}
{ // Checking ListGraph
checkConcept<Graph, ListGraph>();
checkConcept<AlterableGraphComponent<>, ListGraph>();
checkConcept<ExtendableGraphComponent<>, ListGraph>();
checkConcept<ClearableGraphComponent<>, ListGraph>();
checkConcept<ErasableGraphComponent<>, ListGraph>();
}
{ // Checking SmartGraph
checkConcept<Graph, SmartGraph>();
checkConcept<AlterableGraphComponent<>, SmartGraph>();
checkConcept<ExtendableGraphComponent<>, SmartGraph>();
checkConcept<ClearableGraphComponent<>, SmartGraph>();
}
{ // Checking FullGraph
checkConcept<Graph, FullGraph>();
}
{ // Checking GridGraph
checkConcept<Graph, GridGraph>();
}
{ // Checking HypercubeGraph
checkConcept<Graph, HypercubeGraph>();
}
}
template <typename Graph>
void checkGraphValidity() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph g;
Node
n1 = g.addNode(),
n2 = g.addNode(),
n3 = g.addNode();
Edge
e1 = g.addEdge(n1, n2),
e2 = g.addEdge(n2, n3);
::lemon::ignore_unused_variable_warning(e2);
check(g.valid(n1), "Wrong validity check");
check(g.valid(e1), "Wrong validity check");
check(g.valid(g.direct(e1, true)), "Wrong validity check");
check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
}
template <typename Graph>
void checkGraphValidityErase() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph g;
Node
n1 = g.addNode(),
n2 = g.addNode(),
n3 = g.addNode();
Edge
e1 = g.addEdge(n1, n2),
e2 = g.addEdge(n2, n3);
check(g.valid(n1), "Wrong validity check");
check(g.valid(e1), "Wrong validity check");
check(g.valid(g.direct(e1, true)), "Wrong validity check");
g.erase(n1);
check(!g.valid(n1), "Wrong validity check");
check(g.valid(n2), "Wrong validity check");
check(g.valid(n3), "Wrong validity check");
check(!g.valid(e1), "Wrong validity check");
check(g.valid(e2), "Wrong validity check");
check(!g.valid(g.nodeFromId(-1)), "Wrong validity check");
check(!g.valid(g.edgeFromId(-1)), "Wrong validity check");
check(!g.valid(g.arcFromId(-1)), "Wrong validity check");
}
void checkGridGraph(int width, int height) {
typedef GridGraph Graph;
GRAPH_TYPEDEFS(Graph);
Graph G(width, height);
check(G.width() == width, "Wrong column number");
check(G.height() == height, "Wrong row number");
G.resize(width, height);
check(G.width() == width, "Wrong column number");
check(G.height() == height, "Wrong row number");
for (int i = 0; i < width; ++i) {
for (int j = 0; j < height; ++j) {
check(G.col(G(i, j)) == i, "Wrong column");
check(G.row(G(i, j)) == j, "Wrong row");
check(G.pos(G(i, j)).x == i, "Wrong column");
check(G.pos(G(i, j)).y == j, "Wrong row");
}
}
for (int j = 0; j < height; ++j) {
for (int i = 0; i < width - 1; ++i) {
check(G.source(G.right(G(i, j))) == G(i, j), "Wrong right");
check(G.target(G.right(G(i, j))) == G(i + 1, j), "Wrong right");
}
check(G.right(G(width - 1, j)) == INVALID, "Wrong right");
}
for (int j = 0; j < height; ++j) {
for (int i = 1; i < width; ++i) {
check(G.source(G.left(G(i, j))) == G(i, j), "Wrong left");
check(G.target(G.left(G(i, j))) == G(i - 1, j), "Wrong left");
}
check(G.left(G(0, j)) == INVALID, "Wrong left");
}
for (int i = 0; i < width; ++i) {
for (int j = 0; j < height - 1; ++j) {
check(G.source(G.up(G(i, j))) == G(i, j), "Wrong up");
check(G.target(G.up(G(i, j))) == G(i, j + 1), "Wrong up");
}
check(G.up(G(i, height - 1)) == INVALID, "Wrong up");
}
for (int i = 0; i < width; ++i) {
for (int j = 1; j < height; ++j) {
check(G.source(G.down(G(i, j))) == G(i, j), "Wrong down");
check(G.target(G.down(G(i, j))) == G(i, j - 1), "Wrong down");
}
check(G.down(G(i, 0)) == INVALID, "Wrong down");
}
checkGraphNodeList(G, width * height);
checkGraphEdgeList(G, width * (height - 1) + (width - 1) * height);
checkGraphArcList(G, 2 * (width * (height - 1) + (width - 1) * height));
for (NodeIt n(G); n != INVALID; ++n) {
int nb = 4;
if (G.col(n) == 0) --nb;
if (G.col(n) == width - 1) --nb;
if (G.row(n) == 0) --nb;
if (G.row(n) == height - 1) --nb;
checkGraphOutArcList(G, n, nb);
checkGraphInArcList(G, n, nb);
checkGraphIncEdgeList(G, n, nb);
}
checkArcDirections(G);
checkGraphConArcList(G, 2 * (width * (height - 1) + (width - 1) * height));
checkGraphConEdgeList(G, width * (height - 1) + (width - 1) * height);
checkNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
}
void checkHypercubeGraph(int dim) {
GRAPH_TYPEDEFS(HypercubeGraph);
HypercubeGraph G(dim);
check(G.dimension() == dim, "Wrong dimension");
G.resize(dim);
check(G.dimension() == dim, "Wrong dimension");
checkGraphNodeList(G, 1 << dim);
checkGraphEdgeList(G, dim * (1 << (dim-1)));
checkGraphArcList(G, dim * (1 << dim));
Node n = G.nodeFromId(dim);
::lemon::ignore_unused_variable_warning(n);
for (NodeIt n(G); n != INVALID; ++n) {
checkGraphIncEdgeList(G, n, dim);
for (IncEdgeIt e(G, n); e != INVALID; ++e) {
check( (G.u(e) == n &&
G.id(G.v(e)) == (G.id(n) ^ (1 << G.dimension(e)))) ||
(G.v(e) == n &&
G.id(G.u(e)) == (G.id(n) ^ (1 << G.dimension(e)))),
"Wrong edge or wrong dimension");
}
checkGraphOutArcList(G, n, dim);
for (OutArcIt a(G, n); a != INVALID; ++a) {
check(G.source(a) == n &&
G.id(G.target(a)) == (G.id(n) ^ (1 << G.dimension(a))),
"Wrong arc or wrong dimension");
}
checkGraphInArcList(G, n, dim);
for (InArcIt a(G, n); a != INVALID; ++a) {
check(G.target(a) == n &&
G.id(G.source(a)) == (G.id(n) ^ (1 << G.dimension(a))),
"Wrong arc or wrong dimension");
}
}
checkGraphConArcList(G, (1 << dim) * dim);
checkGraphConEdgeList(G, dim * (1 << (dim-1)));
checkArcDirections(G);
checkNodeIds(G);
checkArcIds(G);
checkEdgeIds(G);
checkGraphNodeMap(G);
checkGraphArcMap(G);
checkGraphEdgeMap(G);
}
void checkGraphs() {
{ // Checking ListGraph
checkGraphBuild<ListGraph>();
checkGraphAlter<ListGraph>();
checkGraphErase<ListGraph>();
checkGraphSnapshot<ListGraph>();
checkGraphValidityErase<ListGraph>();
}
{ // Checking SmartGraph
checkGraphBuild<SmartGraph>();
checkGraphSnapshot<SmartGraph>();
checkGraphValidity<SmartGraph>();
}
{ // Checking FullGraph
checkFullGraph(7);
checkFullGraph(8);
}
{ // Checking GridGraph
checkGridGraph(5, 8);
checkGridGraph(8, 5);
checkGridGraph(5, 5);
checkGridGraph(0, 0);
checkGridGraph(1, 1);
}
{ // Checking HypercubeGraph
checkHypercubeGraph(1);
checkHypercubeGraph(2);
checkHypercubeGraph(3);
checkHypercubeGraph(4);
}
}
int main() {
checkConcepts();
checkGraphs();
return 0;
}

View File

@@ -0,0 +1,421 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#ifndef LEMON_TEST_GRAPH_TEST_H
#define LEMON_TEST_GRAPH_TEST_H
#include <set>
#include <lemon/core.h>
#include <lemon/maps.h>
#include "test_tools.h"
namespace lemon {
template<class Graph>
void checkGraphNodeList(const Graph &G, int cnt)
{
typename Graph::NodeIt n(G);
for(int i=0;i<cnt;i++) {
check(n!=INVALID,"Wrong Node list linking.");
++n;
}
check(n==INVALID,"Wrong Node list linking.");
check(countNodes(G)==cnt,"Wrong Node number.");
}
template<class Graph>
void checkGraphRedNodeList(const Graph &G, int cnt)
{
typename Graph::RedNodeIt n(G);
for(int i=0;i<cnt;i++) {
check(n!=INVALID,"Wrong red Node list linking.");
check(G.red(n),"Wrong node set check.");
check(!G.blue(n),"Wrong node set check.");
typename Graph::Node nn = n;
check(G.asRedNodeUnsafe(nn) == n,"Wrong node conversion.");
check(G.asRedNode(nn) == n,"Wrong node conversion.");
check(G.asBlueNode(nn) == INVALID,"Wrong node conversion.");
++n;
}
check(n==INVALID,"Wrong red Node list linking.");
check(countRedNodes(G)==cnt,"Wrong red Node number.");
}
template<class Graph>
void checkGraphBlueNodeList(const Graph &G, int cnt)
{
typename Graph::BlueNodeIt n(G);
for(int i=0;i<cnt;i++) {
check(n!=INVALID,"Wrong blue Node list linking.");
check(G.blue(n),"Wrong node set check.");
check(!G.red(n),"Wrong node set check.");
typename Graph::Node nn = n;
check(G.asBlueNodeUnsafe(nn) == n,"Wrong node conversion.");
check(G.asBlueNode(nn) == n,"Wrong node conversion.");
check(G.asRedNode(nn) == INVALID,"Wrong node conversion.");
++n;
}
check(n==INVALID,"Wrong blue Node list linking.");
check(countBlueNodes(G)==cnt,"Wrong blue Node number.");
}
template<class Graph>
void checkGraphArcList(const Graph &G, int cnt)
{
typename Graph::ArcIt e(G);
for(int i=0;i<cnt;i++) {
check(e!=INVALID,"Wrong Arc list linking.");
check(G.oppositeNode(G.source(e), e) == G.target(e),
"Wrong opposite node");
check(G.oppositeNode(G.target(e), e) == G.source(e),
"Wrong opposite node");
++e;
}
check(e==INVALID,"Wrong Arc list linking.");
check(countArcs(G)==cnt,"Wrong Arc number.");
}
template<class Graph>
void checkGraphOutArcList(const Graph &G, typename Graph::Node n, int cnt)
{
typename Graph::OutArcIt e(G,n);
for(int i=0;i<cnt;i++) {
check(e!=INVALID,"Wrong OutArc list linking.");
check(n==G.source(e),"Wrong OutArc list linking.");
check(n==G.baseNode(e),"Wrong OutArc list linking.");
check(G.target(e)==G.runningNode(e),"Wrong OutArc list linking.");
++e;
}
check(e==INVALID,"Wrong OutArc list linking.");
check(countOutArcs(G,n)==cnt,"Wrong OutArc number.");
}
template<class Graph>
void checkGraphInArcList(const Graph &G, typename Graph::Node n, int cnt)
{
typename Graph::InArcIt e(G,n);
for(int i=0;i<cnt;i++) {
check(e!=INVALID,"Wrong InArc list linking.");
check(n==G.target(e),"Wrong InArc list linking.");
check(n==G.baseNode(e),"Wrong OutArc list linking.");
check(G.source(e)==G.runningNode(e),"Wrong OutArc list linking.");
++e;
}
check(e==INVALID,"Wrong InArc list linking.");
check(countInArcs(G,n)==cnt,"Wrong InArc number.");
}
template<class Graph>
void checkGraphEdgeList(const Graph &G, int cnt)
{
typename Graph::EdgeIt e(G);
for(int i=0;i<cnt;i++) {
check(e!=INVALID,"Wrong Edge list linking.");
check(G.oppositeNode(G.u(e), e) == G.v(e), "Wrong opposite node");
check(G.oppositeNode(G.v(e), e) == G.u(e), "Wrong opposite node");
++e;
}
check(e==INVALID,"Wrong Edge list linking.");
check(countEdges(G)==cnt,"Wrong Edge number.");
}
template<class Graph>
void checkGraphIncEdgeList(const Graph &G, typename Graph::Node n, int cnt)
{
typename Graph::IncEdgeIt e(G,n);
for(int i=0;i<cnt;i++) {
check(e!=INVALID,"Wrong IncEdge list linking.");
check(n==G.u(e) || n==G.v(e),"Wrong IncEdge list linking.");
check(n==G.baseNode(e),"Wrong OutArc list linking.");
check(G.u(e)==G.runningNode(e) || G.v(e)==G.runningNode(e),
"Wrong OutArc list linking.");
++e;
}
check(e==INVALID,"Wrong IncEdge list linking.");
check(countIncEdges(G,n)==cnt,"Wrong IncEdge number.");
}
template <class Graph>
void checkGraphIncEdgeArcLists(const Graph &G, typename Graph::Node n,
int cnt)
{
checkGraphIncEdgeList(G, n, cnt);
checkGraphOutArcList(G, n, cnt);
checkGraphInArcList(G, n, cnt);
}
template <class Graph>
void checkGraphConArcList(const Graph &G, int cnt) {
int i = 0;
for (typename Graph::NodeIt u(G); u != INVALID; ++u) {
for (typename Graph::NodeIt v(G); v != INVALID; ++v) {
for (ConArcIt<Graph> a(G, u, v); a != INVALID; ++a) {
check(G.source(a) == u, "Wrong iterator.");
check(G.target(a) == v, "Wrong iterator.");
++i;
}
}
}
check(cnt == i, "Wrong iterator.");
}
template <class Graph>
void checkGraphConEdgeList(const Graph &G, int cnt) {
int i = 0;
for (typename Graph::NodeIt u(G); u != INVALID; ++u) {
for (typename Graph::NodeIt v(G); v != INVALID; ++v) {
for (ConEdgeIt<Graph> e(G, u, v); e != INVALID; ++e) {
check((G.u(e) == u && G.v(e) == v) ||
(G.u(e) == v && G.v(e) == u), "Wrong iterator.");
i += u == v ? 2 : 1;
}
}
}
check(2 * cnt == i, "Wrong iterator.");
}
template <typename Graph>
void checkArcDirections(const Graph& G) {
for (typename Graph::ArcIt a(G); a != INVALID; ++a) {
check(G.source(a) == G.target(G.oppositeArc(a)), "Wrong direction");
check(G.target(a) == G.source(G.oppositeArc(a)), "Wrong direction");
check(G.direct(a, G.direction(a)) == a, "Wrong direction");
}
}
template <typename Graph>
void checkNodeIds(const Graph& G) {
typedef typename Graph::Node Node;
std::set<int> values;
for (typename Graph::NodeIt n(G); n != INVALID; ++n) {
check(G.nodeFromId(G.id(n)) == n, "Wrong id");
check(values.find(G.id(n)) == values.end(), "Wrong id");
check(G.id(n) <= G.maxNodeId(), "Wrong maximum id");
values.insert(G.id(n));
}
check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id");
}
template <typename Graph>
void checkRedNodeIds(const Graph& G) {
typedef typename Graph::RedNode RedNode;
std::set<int> values;
for (typename Graph::RedNodeIt n(G); n != INVALID; ++n) {
check(G.red(n), "Wrong partition");
check(values.find(G.id(n)) == values.end(), "Wrong id");
check(G.id(n) <= G.maxRedId(), "Wrong maximum id");
values.insert(G.id(n));
}
check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id");
}
template <typename Graph>
void checkBlueNodeIds(const Graph& G) {
typedef typename Graph::BlueNode BlueNode;
std::set<int> values;
for (typename Graph::BlueNodeIt n(G); n != INVALID; ++n) {
check(G.blue(n), "Wrong partition");
check(values.find(G.id(n)) == values.end(), "Wrong id");
check(G.id(n) <= G.maxBlueId(), "Wrong maximum id");
values.insert(G.id(n));
}
check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id");
}
template <typename Graph>
void checkArcIds(const Graph& G) {
typedef typename Graph::Arc Arc;
std::set<int> values;
for (typename Graph::ArcIt a(G); a != INVALID; ++a) {
check(G.arcFromId(G.id(a)) == a, "Wrong id");
check(values.find(G.id(a)) == values.end(), "Wrong id");
check(G.id(a) <= G.maxArcId(), "Wrong maximum id");
values.insert(G.id(a));
}
check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id");
}
template <typename Graph>
void checkEdgeIds(const Graph& G) {
typedef typename Graph::Edge Edge;
std::set<int> values;
for (typename Graph::EdgeIt e(G); e != INVALID; ++e) {
check(G.edgeFromId(G.id(e)) == e, "Wrong id");
check(values.find(G.id(e)) == values.end(), "Wrong id");
check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id");
values.insert(G.id(e));
}
check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id");
}
template <typename Graph>
void checkGraphNodeMap(const Graph& G) {
typedef typename Graph::Node Node;
typedef typename Graph::NodeIt NodeIt;
typedef typename Graph::template NodeMap<int> IntNodeMap;
IntNodeMap map(G, 42);
for (NodeIt it(G); it != INVALID; ++it) {
check(map[it] == 42, "Wrong map constructor.");
}
int s = 0;
for (NodeIt it(G); it != INVALID; ++it) {
map[it] = 0;
check(map[it] == 0, "Wrong operator[].");
map.set(it, s);
check(map[it] == s, "Wrong set.");
++s;
}
s = s * (s - 1) / 2;
for (NodeIt it(G); it != INVALID; ++it) {
s -= map[it];
}
check(s == 0, "Wrong sum.");
// map = constMap<Node>(12);
// for (NodeIt it(G); it != INVALID; ++it) {
// check(map[it] == 12, "Wrong operator[].");
// }
}
template <typename Graph>
void checkGraphRedNodeMap(const Graph& G) {
typedef typename Graph::Node Node;
typedef typename Graph::RedNodeIt RedNodeIt;
typedef typename Graph::template RedNodeMap<int> IntRedNodeMap;
IntRedNodeMap map(G, 42);
for (RedNodeIt it(G); it != INVALID; ++it) {
check(map[it] == 42, "Wrong map constructor.");
}
int s = 0;
for (RedNodeIt it(G); it != INVALID; ++it) {
map[it] = 0;
check(map[it] == 0, "Wrong operator[].");
map.set(it, s);
check(map[it] == s, "Wrong set.");
++s;
}
s = s * (s - 1) / 2;
for (RedNodeIt it(G); it != INVALID; ++it) {
s -= map[it];
}
check(s == 0, "Wrong sum.");
// map = constMap<Node>(12);
// for (NodeIt it(G); it != INVALID; ++it) {
// check(map[it] == 12, "Wrong operator[].");
// }
}
template <typename Graph>
void checkGraphBlueNodeMap(const Graph& G) {
typedef typename Graph::Node Node;
typedef typename Graph::BlueNodeIt BlueNodeIt;
typedef typename Graph::template BlueNodeMap<int> IntBlueNodeMap;
IntBlueNodeMap map(G, 42);
for (BlueNodeIt it(G); it != INVALID; ++it) {
check(map[it] == 42, "Wrong map constructor.");
}
int s = 0;
for (BlueNodeIt it(G); it != INVALID; ++it) {
map[it] = 0;
check(map[it] == 0, "Wrong operator[].");
map.set(it, s);
check(map[it] == s, "Wrong set.");
++s;
}
s = s * (s - 1) / 2;
for (BlueNodeIt it(G); it != INVALID; ++it) {
s -= map[it];
}
check(s == 0, "Wrong sum.");
// map = constMap<Node>(12);
// for (NodeIt it(G); it != INVALID; ++it) {
// check(map[it] == 12, "Wrong operator[].");
// }
}
template <typename Graph>
void checkGraphArcMap(const Graph& G) {
typedef typename Graph::Arc Arc;
typedef typename Graph::ArcIt ArcIt;
typedef typename Graph::template ArcMap<int> IntArcMap;
IntArcMap map(G, 42);
for (ArcIt it(G); it != INVALID; ++it) {
check(map[it] == 42, "Wrong map constructor.");
}
int s = 0;
for (ArcIt it(G); it != INVALID; ++it) {
map[it] = 0;
check(map[it] == 0, "Wrong operator[].");
map.set(it, s);
check(map[it] == s, "Wrong set.");
++s;
}
s = s * (s - 1) / 2;
for (ArcIt it(G); it != INVALID; ++it) {
s -= map[it];
}
check(s == 0, "Wrong sum.");
// map = constMap<Arc>(12);
// for (ArcIt it(G); it != INVALID; ++it) {
// check(map[it] == 12, "Wrong operator[].");
// }
}
template <typename Graph>
void checkGraphEdgeMap(const Graph& G) {
typedef typename Graph::Edge Edge;
typedef typename Graph::EdgeIt EdgeIt;
typedef typename Graph::template EdgeMap<int> IntEdgeMap;
IntEdgeMap map(G, 42);
for (EdgeIt it(G); it != INVALID; ++it) {
check(map[it] == 42, "Wrong map constructor.");
}
int s = 0;
for (EdgeIt it(G); it != INVALID; ++it) {
map[it] = 0;
check(map[it] == 0, "Wrong operator[].");
map.set(it, s);
check(map[it] == s, "Wrong set.");
++s;
}
s = s * (s - 1) / 2;
for (EdgeIt it(G); it != INVALID; ++it) {
s -= map[it];
}
check(s == 0, "Wrong sum.");
// map = constMap<Edge>(12);
// for (EdgeIt it(G); it != INVALID; ++it) {
// check(map[it] == 12, "Wrong operator[].");
// }
}
} //namespace lemon
#endif

View File

@@ -0,0 +1,217 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <cstdlib>
#include <ctime>
#include <lemon/random.h>
#include <lemon/list_graph.h>
#include <lemon/smart_graph.h>
#include <lemon/maps.h>
#include "graph_test.h"
#include "test_tools.h"
using namespace lemon;
template <typename Digraph>
void checkFindArcs() {
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
{
Digraph digraph;
for (int i = 0; i < 10; ++i) {
digraph.addNode();
}
RangeIdMap<Digraph, Node> nodes(digraph);
typename RangeIdMap<Digraph, Node>::InverseMap invNodes(nodes);
for (int i = 0; i < 100; ++i) {
int src = rnd[invNodes.size()];
int trg = rnd[invNodes.size()];
digraph.addArc(invNodes[src], invNodes[trg]);
}
typename Digraph::template ArcMap<bool> found(digraph, false);
RangeIdMap<Digraph, Arc> arcs(digraph);
for (NodeIt src(digraph); src != INVALID; ++src) {
for (NodeIt trg(digraph); trg != INVALID; ++trg) {
for (ConArcIt<Digraph> con(digraph, src, trg); con != INVALID; ++con) {
check(digraph.source(con) == src, "Wrong source.");
check(digraph.target(con) == trg, "Wrong target.");
check(found[con] == false, "The arc found already.");
found[con] = true;
}
}
}
for (ArcIt it(digraph); it != INVALID; ++it) {
check(found[it] == true, "The arc is not found.");
}
}
{
int num = 5;
Digraph fg;
std::vector<Node> nodes;
for (int i = 0; i < num; ++i) {
nodes.push_back(fg.addNode());
}
for (int i = 0; i < num * num; ++i) {
fg.addArc(nodes[i / num], nodes[i % num]);
}
check(countNodes(fg) == num, "Wrong node number.");
check(countArcs(fg) == num*num, "Wrong arc number.");
for (NodeIt src(fg); src != INVALID; ++src) {
for (NodeIt trg(fg); trg != INVALID; ++trg) {
ConArcIt<Digraph> con(fg, src, trg);
check(con != INVALID, "There is no connecting arc.");
check(fg.source(con) == src, "Wrong source.");
check(fg.target(con) == trg, "Wrong target.");
check(++con == INVALID, "There is more connecting arc.");
}
}
ArcLookUp<Digraph> al1(fg);
DynArcLookUp<Digraph> al2(fg);
AllArcLookUp<Digraph> al3(fg);
for (NodeIt src(fg); src != INVALID; ++src) {
for (NodeIt trg(fg); trg != INVALID; ++trg) {
Arc con1 = al1(src, trg);
Arc con2 = al2(src, trg);
Arc con3 = al3(src, trg);
Arc con4 = findArc(fg, src, trg);
check(con1 == con2 && con2 == con3 && con3 == con4,
"Different results.")
check(con1 != INVALID, "There is no connecting arc.");
check(fg.source(con1) == src, "Wrong source.");
check(fg.target(con1) == trg, "Wrong target.");
check(al3(src, trg, con3) == INVALID,
"There is more connecting arc.");
check(findArc(fg, src, trg, con4) == INVALID,
"There is more connecting arc.");
}
}
}
}
template <typename Graph>
void checkFindEdges() {
TEMPLATE_GRAPH_TYPEDEFS(Graph);
Graph graph;
for (int i = 0; i < 10; ++i) {
graph.addNode();
}
RangeIdMap<Graph, Node> nodes(graph);
typename RangeIdMap<Graph, Node>::InverseMap invNodes(nodes);
for (int i = 0; i < 100; ++i) {
int src = rnd[invNodes.size()];
int trg = rnd[invNodes.size()];
graph.addEdge(invNodes[src], invNodes[trg]);
}
typename Graph::template EdgeMap<int> found(graph, 0);
RangeIdMap<Graph, Edge> edges(graph);
for (NodeIt src(graph); src != INVALID; ++src) {
for (NodeIt trg(graph); trg != INVALID; ++trg) {
for (ConEdgeIt<Graph> con(graph, src, trg); con != INVALID; ++con) {
check( (graph.u(con) == src && graph.v(con) == trg) ||
(graph.v(con) == src && graph.u(con) == trg),
"Wrong end nodes.");
++found[con];
check(found[con] <= 2, "The edge found more than twice.");
}
}
}
for (EdgeIt it(graph); it != INVALID; ++it) {
check( (graph.u(it) != graph.v(it) && found[it] == 2) ||
(graph.u(it) == graph.v(it) && found[it] == 1),
"The edge is not found correctly.");
}
}
template <class Digraph>
void checkDeg()
{
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
const int nodeNum = 10;
const int arcNum = 100;
Digraph digraph;
InDegMap<Digraph> inDeg(digraph);
OutDegMap<Digraph> outDeg(digraph);
std::vector<Node> nodes(nodeNum);
for (int i = 0; i < nodeNum; ++i) {
nodes[i] = digraph.addNode();
}
std::vector<Arc> arcs(arcNum);
for (int i = 0; i < arcNum; ++i) {
arcs[i] = digraph.addArc(nodes[rnd[nodeNum]], nodes[rnd[nodeNum]]);
}
for (int i = 0; i < nodeNum; ++i) {
check(inDeg[nodes[i]] == countInArcs(digraph, nodes[i]),
"Wrong in degree map");
}
for (int i = 0; i < nodeNum; ++i) {
check(outDeg[nodes[i]] == countOutArcs(digraph, nodes[i]),
"Wrong out degree map");
}
}
template <class Digraph>
void checkSnapDeg()
{
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Digraph g;
Node n1=g.addNode();
Node n2=g.addNode();
InDegMap<Digraph> ind(g);
g.addArc(n1,n2);
typename Digraph::Snapshot snap(g);
OutDegMap<Digraph> outd(g);
check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value.");
check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value.");
g.addArc(n1,n2);
g.addArc(n2,n1);
check(ind[n1]==1 && ind[n2]==2, "Wrong InDegMap value.");
check(outd[n1]==2 && outd[n2]==1, "Wrong OutDegMap value.");
snap.restore();
check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value.");
check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value.");
}
int main() {
// Checking ConArcIt, ConEdgeIt, ArcLookUp, AllArcLookUp, and DynArcLookUp
checkFindArcs<ListDigraph>();
checkFindArcs<SmartDigraph>();
checkFindEdges<ListGraph>();
checkFindEdges<SmartGraph>();
// Checking In/OutDegMap (and Snapshot feature)
checkDeg<ListDigraph>();
checkDeg<SmartDigraph>();
checkSnapDeg<ListDigraph>();
checkSnapDeg<SmartDigraph>();
return 0;
}

View File

@@ -0,0 +1,164 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <sstream>
#include <lemon/smart_graph.h>
#include <lemon/adaptors.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/hao_orlin.h>
#include "test_tools.h"
using namespace lemon;
using namespace std;
const std::string lgf =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@edges\n"
" cap1 cap2 cap3\n"
"0 1 1 1 1 \n"
"0 2 2 2 4 \n"
"1 2 4 4 4 \n"
"3 4 1 1 1 \n"
"3 5 2 2 4 \n"
"4 5 4 4 4 \n"
"5 4 4 4 4 \n"
"2 3 1 6 6 \n"
"4 0 1 6 6 \n";
void checkHaoOrlinCompile()
{
typedef int Value;
typedef concepts::Digraph Digraph;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
typedef concepts::ReadMap<Arc, Value> CapMap;
typedef concepts::WriteMap<Node, bool> CutMap;
Digraph g;
Node n;
CapMap cap;
CutMap cut;
Value v;
::lemon::ignore_unused_variable_warning(v);
HaoOrlin<Digraph, CapMap> ho_test(g, cap);
const HaoOrlin<Digraph, CapMap>&
const_ho_test = ho_test;
ho_test.init();
ho_test.init(n);
ho_test.calculateOut();
ho_test.calculateIn();
ho_test.run();
ho_test.run(n);
v = const_ho_test.minCutValue();
v = const_ho_test.minCutMap(cut);
}
template <typename Graph, typename CapMap, typename CutMap>
typename CapMap::Value
cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut)
{
typename CapMap::Value sum = 0;
for (typename Graph::ArcIt a(graph); a != INVALID; ++a) {
if (cut[graph.source(a)] && !cut[graph.target(a)])
sum += cap[a];
}
return sum;
}
int main() {
SmartDigraph graph;
SmartDigraph::ArcMap<int> cap1(graph), cap2(graph), cap3(graph);
SmartDigraph::NodeMap<bool> cut(graph);
istringstream input(lgf);
digraphReader(graph, input)
.arcMap("cap1", cap1)
.arcMap("cap2", cap2)
.arcMap("cap3", cap3)
.run();
{
HaoOrlin<SmartDigraph> ho(graph, cap1);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 1, "Wrong cut value");
check(ho.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value");
}
{
HaoOrlin<SmartDigraph> ho(graph, cap2);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 1, "Wrong cut value");
check(ho.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value");
}
{
HaoOrlin<SmartDigraph> ho(graph, cap3);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 1, "Wrong cut value");
check(ho.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value");
}
typedef Undirector<SmartDigraph> UGraph;
UGraph ugraph(graph);
{
HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap1);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 2, "Wrong cut value");
check(ho.minCutValue() == cutValue(ugraph, cap1, cut), "Wrong cut value");
}
{
HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap2);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 5, "Wrong cut value");
check(ho.minCutValue() == cutValue(ugraph, cap2, cut), "Wrong cut value");
}
{
HaoOrlin<UGraph, SmartDigraph::ArcMap<int> > ho(ugraph, cap3);
ho.run();
ho.minCutMap(cut);
check(ho.minCutValue() == 5, "Wrong cut value");
check(ho.minCutValue() == cutValue(ugraph, cap3, cut), "Wrong cut value");
}
return 0;
}

View File

@@ -0,0 +1,310 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <lemon/concept_check.h>
#include <lemon/concepts/heap.h>
#include <lemon/smart_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/dijkstra.h>
#include <lemon/maps.h>
#include <lemon/bin_heap.h>
#include <lemon/quad_heap.h>
#include <lemon/dheap.h>
#include <lemon/fib_heap.h>
#include <lemon/pairing_heap.h>
#include <lemon/radix_heap.h>
#include <lemon/binomial_heap.h>
#include <lemon/bucket_heap.h>
#include "test_tools.h"
using namespace lemon;
using namespace lemon::concepts;
typedef ListDigraph Digraph;
DIGRAPH_TYPEDEFS(Digraph);
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"8\n"
"9\n"
"@arcs\n"
" label capacity\n"
"0 5 0 94\n"
"3 9 1 11\n"
"8 7 2 83\n"
"1 2 3 94\n"
"5 7 4 35\n"
"7 4 5 84\n"
"9 5 6 38\n"
"0 4 7 96\n"
"6 7 8 6\n"
"3 1 9 27\n"
"5 2 10 77\n"
"5 6 11 69\n"
"6 5 12 41\n"
"4 6 13 70\n"
"3 2 14 45\n"
"7 9 15 93\n"
"5 9 16 50\n"
"9 0 17 94\n"
"9 6 18 67\n"
"0 9 19 86\n"
"@attributes\n"
"source 3\n";
int test_seq[] = { 2, 28, 19, 27, 33, 25, 13, 41, 10, 26, 1, 9, 4, 34};
int test_inc[] = {20, 28, 34, 16, 0, 46, 44, 0, 42, 32, 14, 8, 6, 37};
int test_len = sizeof(test_seq) / sizeof(test_seq[0]);
template <typename Heap>
void heapSortTest() {
RangeMap<int> map(test_len, -1);
Heap heap(map);
std::vector<int> v(test_len);
for (int i = 0; i < test_len; ++i) {
v[i] = test_seq[i];
heap.push(i, v[i]);
}
std::sort(v.begin(), v.end());
for (int i = 0; i < test_len; ++i) {
check(v[i] == heap.prio(), "Wrong order in heap sort.");
heap.pop();
}
}
template <typename Heap>
void heapIncreaseTest() {
RangeMap<int> map(test_len, -1);
Heap heap(map);
std::vector<int> v(test_len);
for (int i = 0; i < test_len; ++i) {
v[i] = test_seq[i];
heap.push(i, v[i]);
}
for (int i = 0; i < test_len; ++i) {
v[i] += test_inc[i];
heap.increase(i, v[i]);
}
std::sort(v.begin(), v.end());
for (int i = 0; i < test_len; ++i) {
check(v[i] == heap.prio(), "Wrong order in heap increase test.");
heap.pop();
}
}
template <typename Heap>
void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length,
Node source) {
typename Dijkstra<Digraph, IntArcMap>::template SetStandardHeap<Heap>::
Create dijkstra(digraph, length);
dijkstra.run(source);
for(ArcIt a(digraph); a != INVALID; ++a) {
Node s = digraph.source(a);
Node t = digraph.target(a);
if (dijkstra.reached(s)) {
check( dijkstra.dist(t) - dijkstra.dist(s) <= length[a],
"Error in shortest path tree.");
}
}
for(NodeIt n(digraph); n != INVALID; ++n) {
if ( dijkstra.reached(n) && dijkstra.predArc(n) != INVALID ) {
Arc a = dijkstra.predArc(n);
Node s = digraph.source(a);
check( dijkstra.dist(n) - dijkstra.dist(s) == length[a],
"Error in shortest path tree.");
}
}
}
int main() {
typedef int Item;
typedef int Prio;
typedef RangeMap<int> ItemIntMap;
Digraph digraph;
IntArcMap length(digraph);
Node source;
std::istringstream input(test_lgf);
digraphReader(digraph, input).
arcMap("capacity", length).
node("source", source).
run();
// BinHeap
{
typedef BinHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef BinHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// QuadHeap
{
typedef QuadHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef QuadHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// DHeap
{
typedef DHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef DHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// FibHeap
{
typedef FibHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef FibHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// PairingHeap
{
typedef PairingHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef PairingHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// RadixHeap
{
typedef RadixHeap<ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef RadixHeap<IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// BinomialHeap
{
typedef BinomialHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef BinomialHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
// BucketHeap, SimpleBucketHeap
{
typedef BucketHeap<ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef BucketHeap<IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
typedef SimpleBucketHeap<ItemIntMap> SimpleIntHeap;
heapSortTest<SimpleIntHeap>();
}
{
typedef FibHeap<Prio, ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef FibHeap<Prio, IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
{
typedef RadixHeap<ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef RadixHeap<IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
{
typedef BucketHeap<ItemIntMap> IntHeap;
checkConcept<Heap<Prio, ItemIntMap>, IntHeap>();
heapSortTest<IntHeap>();
heapIncreaseTest<IntHeap>();
typedef BucketHeap<IntNodeMap > NodeHeap;
checkConcept<Heap<Prio, IntNodeMap >, NodeHeap>();
dijkstraHeapTest<NodeHeap>(digraph, length, source);
}
return 0;
}

View File

@@ -0,0 +1,147 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <vector>
#include "test_tools.h"
#include <lemon/maps.h>
#include <lemon/kruskal.h>
#include <lemon/list_graph.h>
#include <lemon/concepts/maps.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/graph.h>
using namespace std;
using namespace lemon;
void checkCompileKruskal()
{
concepts::WriteMap<concepts::Digraph::Arc,bool> w;
concepts::WriteMap<concepts::Graph::Edge,bool> uw;
concepts::ReadMap<concepts::Digraph::Arc,int> r;
concepts::ReadMap<concepts::Graph::Edge,int> ur;
concepts::Digraph g;
concepts::Graph ug;
kruskal(g, r, w);
kruskal(ug, ur, uw);
std::vector<std::pair<concepts::Digraph::Arc, int> > rs;
std::vector<std::pair<concepts::Graph::Edge, int> > urs;
kruskal(g, rs, w);
kruskal(ug, urs, uw);
std::vector<concepts::Digraph::Arc> ws;
std::vector<concepts::Graph::Edge> uws;
kruskal(g, r, ws.begin());
kruskal(ug, ur, uws.begin());
}
int main() {
typedef ListGraph::Node Node;
typedef ListGraph::Edge Edge;
typedef ListGraph::NodeIt NodeIt;
typedef ListGraph::ArcIt ArcIt;
ListGraph G;
Node s=G.addNode();
Node v1=G.addNode();
Node v2=G.addNode();
Node v3=G.addNode();
Node v4=G.addNode();
Node t=G.addNode();
Edge e1 = G.addEdge(s, v1);
Edge e2 = G.addEdge(s, v2);
Edge e3 = G.addEdge(v1, v2);
Edge e4 = G.addEdge(v2, v1);
Edge e5 = G.addEdge(v1, v3);
Edge e6 = G.addEdge(v3, v2);
Edge e7 = G.addEdge(v2, v4);
Edge e8 = G.addEdge(v4, v3);
Edge e9 = G.addEdge(v3, t);
Edge e10 = G.addEdge(v4, t);
typedef ListGraph::EdgeMap<int> ECostMap;
typedef ListGraph::EdgeMap<bool> EBoolMap;
ECostMap edge_cost_map(G, 2);
EBoolMap tree_map(G);
//Test with const map.
check(kruskal(G, ConstMap<ListGraph::Edge,int>(2), tree_map)==10,
"Total cost should be 10");
//Test with an edge map (filled with uniform costs).
check(kruskal(G, edge_cost_map, tree_map)==10,
"Total cost should be 10");
edge_cost_map[e1] = -10;
edge_cost_map[e2] = -9;
edge_cost_map[e3] = -8;
edge_cost_map[e4] = -7;
edge_cost_map[e5] = -6;
edge_cost_map[e6] = -5;
edge_cost_map[e7] = -4;
edge_cost_map[e8] = -3;
edge_cost_map[e9] = -2;
edge_cost_map[e10] = -1;
vector<Edge> tree_edge_vec(5);
//Test with a edge map and inserter.
check(kruskal(G, edge_cost_map,
tree_edge_vec.begin())
==-31,
"Total cost should be -31.");
tree_edge_vec.clear();
check(kruskal(G, edge_cost_map,
back_inserter(tree_edge_vec))
==-31,
"Total cost should be -31.");
// tree_edge_vec.clear();
// //The above test could also be coded like this:
// check(kruskal(G,
// makeKruskalMapInput(G, edge_cost_map),
// makeKruskalSequenceOutput(back_inserter(tree_edge_vec)))
// ==-31,
// "Total cost should be -31.");
check(tree_edge_vec.size()==5,"The tree should have 5 edges.");
check(tree_edge_vec[0]==e1 &&
tree_edge_vec[1]==e2 &&
tree_edge_vec[2]==e5 &&
tree_edge_vec[3]==e7 &&
tree_edge_vec[4]==e9,
"Wrong tree.");
return 0;
}

View File

@@ -0,0 +1,578 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <string>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/graph.h>
#include <lemon/concepts/bpgraph.h>
#include <lemon/list_graph.h>
#include <lemon/smart_graph.h>
#include <lemon/lgf_reader.h>
#include "test_tools.h"
struct ReaderConverter {
int operator()(const std::string& str) const {
return str.length();
}
};
struct WriterConverter {
std::string operator()(int value) const {
return std::string(value, '*');
}
};
void checkDigraphReaderCompile() {
typedef lemon::concepts::ExtendableDigraphComponent<
lemon::concepts::Digraph> Digraph;
Digraph digraph;
Digraph::NodeMap<int> node_map(digraph);
Digraph::ArcMap<int> arc_map(digraph);
Digraph::Node node;
Digraph::Arc arc;
int attr;
lemon::DigraphReader<Digraph> reader(digraph, "filename");
reader.nodeMap("node_map", node_map);
reader.nodeMap("node_map", node_map, ReaderConverter());
reader.arcMap("arc_map", arc_map);
reader.arcMap("arc_map", arc_map, ReaderConverter());
reader.attribute("attr", attr);
reader.attribute("attr", attr, ReaderConverter());
reader.node("node", node);
reader.arc("arc", arc);
reader.nodes("alt_nodes_caption");
reader.arcs("alt_arcs_caption");
reader.attributes("alt_attrs_caption");
reader.useNodes(node_map);
reader.useNodes(node_map, WriterConverter());
reader.useArcs(arc_map);
reader.useArcs(arc_map, WriterConverter());
reader.skipNodes();
reader.skipArcs();
reader.run();
lemon::DigraphReader<Digraph> reader2(digraph, std::cin);
}
void checkDigraphWriterCompile() {
typedef lemon::concepts::Digraph Digraph;
Digraph digraph;
Digraph::NodeMap<int> node_map(digraph);
Digraph::ArcMap<int> arc_map(digraph);
Digraph::Node node;
Digraph::Arc arc;
int attr;
lemon::DigraphWriter<Digraph> writer(digraph, "filename");
writer.nodeMap("node_map", node_map);
writer.nodeMap("node_map", node_map, WriterConverter());
writer.arcMap("arc_map", arc_map);
writer.arcMap("arc_map", arc_map, WriterConverter());
writer.attribute("attr", attr);
writer.attribute("attr", attr, WriterConverter());
writer.node("node", node);
writer.arc("arc", arc);
writer.nodes("alt_nodes_caption");
writer.arcs("alt_arcs_caption");
writer.attributes("alt_attrs_caption");
writer.skipNodes();
writer.skipArcs();
writer.run();
}
void checkGraphReaderCompile() {
typedef lemon::concepts::ExtendableGraphComponent<
lemon::concepts::Graph> Graph;
Graph graph;
Graph::NodeMap<int> node_map(graph);
Graph::ArcMap<int> arc_map(graph);
Graph::EdgeMap<int> edge_map(graph);
Graph::Node node;
Graph::Arc arc;
Graph::Edge edge;
int attr;
lemon::GraphReader<Graph> reader(graph, "filename");
reader.nodeMap("node_map", node_map);
reader.nodeMap("node_map", node_map, ReaderConverter());
reader.arcMap("arc_map", arc_map);
reader.arcMap("arc_map", arc_map, ReaderConverter());
reader.edgeMap("edge_map", edge_map);
reader.edgeMap("edge_map", edge_map, ReaderConverter());
reader.attribute("attr", attr);
reader.attribute("attr", attr, ReaderConverter());
reader.node("node", node);
reader.arc("arc", arc);
reader.nodes("alt_nodes_caption");
reader.edges("alt_edges_caption");
reader.attributes("alt_attrs_caption");
reader.useNodes(node_map);
reader.useNodes(node_map, WriterConverter());
reader.useEdges(edge_map);
reader.useEdges(edge_map, WriterConverter());
reader.skipNodes();
reader.skipEdges();
reader.run();
lemon::GraphReader<Graph> reader2(graph, std::cin);
}
void checkGraphWriterCompile() {
typedef lemon::concepts::Graph Graph;
Graph graph;
Graph::NodeMap<int> node_map(graph);
Graph::ArcMap<int> arc_map(graph);
Graph::EdgeMap<int> edge_map(graph);
Graph::Node node;
Graph::Arc arc;
Graph::Edge edge;
int attr;
lemon::GraphWriter<Graph> writer(graph, "filename");
writer.nodeMap("node_map", node_map);
writer.nodeMap("node_map", node_map, WriterConverter());
writer.arcMap("arc_map", arc_map);
writer.arcMap("arc_map", arc_map, WriterConverter());
writer.edgeMap("edge_map", edge_map);
writer.edgeMap("edge_map", edge_map, WriterConverter());
writer.attribute("attr", attr);
writer.attribute("attr", attr, WriterConverter());
writer.node("node", node);
writer.arc("arc", arc);
writer.edge("edge", edge);
writer.nodes("alt_nodes_caption");
writer.edges("alt_edges_caption");
writer.attributes("alt_attrs_caption");
writer.skipNodes();
writer.skipEdges();
writer.run();
lemon::GraphWriter<Graph> writer2(graph, std::cout);
}
void checkBpGraphReaderCompile() {
typedef lemon::concepts::ExtendableBpGraphComponent<
lemon::concepts::BpGraph> BpGraph;
BpGraph graph;
BpGraph::NodeMap<int> node_map(graph);
BpGraph::RedNodeMap<int> red_node_map(graph);
BpGraph::BlueNodeMap<int> blue_node_map(graph);
BpGraph::ArcMap<int> arc_map(graph);
BpGraph::EdgeMap<int> edge_map(graph);
BpGraph::Node node;
BpGraph::RedNode red_node;
BpGraph::BlueNode blue_node;
BpGraph::Arc arc;
BpGraph::Edge edge;
int attr;
lemon::BpGraphReader<BpGraph> reader(graph, "filename");
reader.nodeMap("node_map", node_map);
reader.nodeMap("node_map", node_map, ReaderConverter());
reader.redNodeMap("red_node_map", red_node_map);
reader.redNodeMap("red_node_map", red_node_map, ReaderConverter());
reader.blueNodeMap("blue_node_map", blue_node_map);
reader.blueNodeMap("blue_node_map", blue_node_map, ReaderConverter());
reader.arcMap("arc_map", arc_map);
reader.arcMap("arc_map", arc_map, ReaderConverter());
reader.edgeMap("edge_map", edge_map);
reader.edgeMap("edge_map", edge_map, ReaderConverter());
reader.attribute("attr", attr);
reader.attribute("attr", attr, ReaderConverter());
reader.node("node", node);
reader.redNode("red_node", red_node);
reader.blueNode("blue_node", blue_node);
reader.arc("arc", arc);
reader.nodes("alt_nodes_caption");
reader.edges("alt_edges_caption");
reader.attributes("alt_attrs_caption");
reader.useNodes(node_map);
reader.useNodes(node_map, WriterConverter());
reader.useEdges(edge_map);
reader.useEdges(edge_map, WriterConverter());
reader.skipNodes();
reader.skipEdges();
reader.run();
lemon::BpGraphReader<BpGraph> reader2(graph, std::cin);
}
void checkBpGraphWriterCompile() {
typedef lemon::concepts::BpGraph BpGraph;
BpGraph graph;
BpGraph::NodeMap<int> node_map(graph);
BpGraph::RedNodeMap<int> red_node_map(graph);
BpGraph::BlueNodeMap<int> blue_node_map(graph);
BpGraph::ArcMap<int> arc_map(graph);
BpGraph::EdgeMap<int> edge_map(graph);
BpGraph::Node node;
BpGraph::RedNode red_node;
BpGraph::BlueNode blue_node;
BpGraph::Arc arc;
BpGraph::Edge edge;
int attr;
lemon::BpGraphWriter<BpGraph> writer(graph, "filename");
writer.nodeMap("node_map", node_map);
writer.nodeMap("node_map", node_map, WriterConverter());
writer.redNodeMap("red_node_map", red_node_map);
writer.redNodeMap("red_node_map", red_node_map, WriterConverter());
writer.blueNodeMap("blue_node_map", blue_node_map);
writer.blueNodeMap("blue_node_map", blue_node_map, WriterConverter());
writer.arcMap("arc_map", arc_map);
writer.arcMap("arc_map", arc_map, WriterConverter());
writer.edgeMap("edge_map", edge_map);
writer.edgeMap("edge_map", edge_map, WriterConverter());
writer.attribute("attr", attr);
writer.attribute("attr", attr, WriterConverter());
writer.node("node", node);
writer.redNode("red_node", red_node);
writer.blueNode("blue_node", blue_node);
writer.arc("arc", arc);
writer.nodes("alt_nodes_caption");
writer.edges("alt_edges_caption");
writer.attributes("alt_attrs_caption");
writer.skipNodes();
writer.skipEdges();
writer.run();
lemon::BpGraphWriter<BpGraph> writer2(graph, std::cout);
}
void checkDigraphReaderWriter() {
typedef lemon::SmartDigraph Digraph;
Digraph digraph;
Digraph::Node n1 = digraph.addNode();
Digraph::Node n2 = digraph.addNode();
Digraph::Node n3 = digraph.addNode();
Digraph::Arc a1 = digraph.addArc(n1, n2);
Digraph::Arc a2 = digraph.addArc(n2, n3);
Digraph::NodeMap<int> node_map(digraph);
node_map[n1] = 11;
node_map[n2] = 12;
node_map[n3] = 13;
Digraph::ArcMap<int> arc_map(digraph);
arc_map[a1] = 21;
arc_map[a2] = 22;
int attr = 100;
std::ostringstream os;
lemon::DigraphWriter<Digraph> writer(digraph, os);
writer.nodeMap("node_map1", node_map);
writer.nodeMap("node_map2", node_map, WriterConverter());
writer.arcMap("arc_map1", arc_map);
writer.arcMap("arc_map2", arc_map, WriterConverter());
writer.node("node", n2);
writer.arc("arc", a1);
writer.attribute("attr1", attr);
writer.attribute("attr2", attr, WriterConverter());
writer.run();
typedef lemon::ListDigraph ExpDigraph;
ExpDigraph exp_digraph;
ExpDigraph::NodeMap<int> exp_node_map1(exp_digraph);
ExpDigraph::NodeMap<int> exp_node_map2(exp_digraph);
ExpDigraph::ArcMap<int> exp_arc_map1(exp_digraph);
ExpDigraph::ArcMap<int> exp_arc_map2(exp_digraph);
ExpDigraph::Node exp_n2;
ExpDigraph::Arc exp_a1;
int exp_attr1;
int exp_attr2;
std::istringstream is(os.str());
lemon::DigraphReader<ExpDigraph> reader(exp_digraph, is);
reader.nodeMap("node_map1", exp_node_map1);
reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
reader.arcMap("arc_map1", exp_arc_map1);
reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
reader.node("node", exp_n2);
reader.arc("arc", exp_a1);
reader.attribute("attr1", exp_attr1);
reader.attribute("attr2", exp_attr2, ReaderConverter());
reader.run();
check(lemon::countNodes(exp_digraph) == 3, "Wrong number of nodes");
check(lemon::countArcs(exp_digraph) == 2, "Wrong number of arcs");
check(exp_node_map1[exp_n2] == 12, "Wrong map value");
check(exp_node_map2[exp_n2] == 12, "Wrong map value");
check(exp_arc_map1[exp_a1] == 21, "Wrong map value");
check(exp_arc_map2[exp_a1] == 21, "Wrong map value");
check(exp_attr1 == 100, "Wrong attr value");
check(exp_attr2 == 100, "Wrong attr value");
}
void checkGraphReaderWriter() {
typedef lemon::SmartGraph Graph;
Graph graph;
Graph::Node n1 = graph.addNode();
Graph::Node n2 = graph.addNode();
Graph::Node n3 = graph.addNode();
Graph::Edge e1 = graph.addEdge(n1, n2);
Graph::Edge e2 = graph.addEdge(n2, n3);
Graph::NodeMap<int> node_map(graph);
node_map[n1] = 11;
node_map[n2] = 12;
node_map[n3] = 13;
Graph::EdgeMap<int> edge_map(graph);
edge_map[e1] = 21;
edge_map[e2] = 22;
Graph::ArcMap<int> arc_map(graph);
arc_map[graph.direct(e1, true)] = 211;
arc_map[graph.direct(e1, false)] = 212;
arc_map[graph.direct(e2, true)] = 221;
arc_map[graph.direct(e2, false)] = 222;
int attr = 100;
std::ostringstream os;
lemon::GraphWriter<Graph> writer(graph, os);
writer.nodeMap("node_map1", node_map);
writer.nodeMap("node_map2", node_map, WriterConverter());
writer.edgeMap("edge_map1", edge_map);
writer.edgeMap("edge_map2", edge_map, WriterConverter());
writer.arcMap("arc_map1", arc_map);
writer.arcMap("arc_map2", arc_map, WriterConverter());
writer.node("node", n2);
writer.edge("edge", e1);
writer.arc("arc", graph.direct(e1, false));
writer.attribute("attr1", attr);
writer.attribute("attr2", attr, WriterConverter());
writer.run();
typedef lemon::ListGraph ExpGraph;
ExpGraph exp_graph;
ExpGraph::NodeMap<int> exp_node_map1(exp_graph);
ExpGraph::NodeMap<int> exp_node_map2(exp_graph);
ExpGraph::EdgeMap<int> exp_edge_map1(exp_graph);
ExpGraph::EdgeMap<int> exp_edge_map2(exp_graph);
ExpGraph::ArcMap<int> exp_arc_map1(exp_graph);
ExpGraph::ArcMap<int> exp_arc_map2(exp_graph);
ExpGraph::Node exp_n2;
ExpGraph::Edge exp_e1;
ExpGraph::Arc exp_a1;
int exp_attr1;
int exp_attr2;
std::istringstream is(os.str());
lemon::GraphReader<ExpGraph> reader(exp_graph, is);
reader.nodeMap("node_map1", exp_node_map1);
reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
reader.edgeMap("edge_map1", exp_edge_map1);
reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter());
reader.arcMap("arc_map1", exp_arc_map1);
reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
reader.node("node", exp_n2);
reader.edge("edge", exp_e1);
reader.arc("arc", exp_a1);
reader.attribute("attr1", exp_attr1);
reader.attribute("attr2", exp_attr2, ReaderConverter());
reader.run();
check(lemon::countNodes(exp_graph) == 3, "Wrong number of nodes");
check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges");
check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs");
check(exp_node_map1[exp_n2] == 12, "Wrong map value");
check(exp_node_map2[exp_n2] == 12, "Wrong map value");
check(exp_edge_map1[exp_e1] == 21, "Wrong map value");
check(exp_edge_map2[exp_e1] == 21, "Wrong map value");
check(exp_arc_map1[exp_a1] == 212, "Wrong map value");
check(exp_arc_map2[exp_a1] == 212, "Wrong map value");
check(exp_attr1 == 100, "Wrong attr value");
check(exp_attr2 == 100, "Wrong attr value");
}
void checkBpGraphReaderWriter() {
typedef lemon::SmartBpGraph Graph;
Graph graph;
Graph::RedNode rn1 = graph.addRedNode();
Graph::RedNode rn2 = graph.addRedNode();
Graph::RedNode rn3 = graph.addRedNode();
Graph::BlueNode bn1 = graph.addBlueNode();
Graph::BlueNode bn2 = graph.addBlueNode();
Graph::Node n = bn1;
Graph::Edge e1 = graph.addEdge(rn1, bn1);
Graph::Edge e2 = graph.addEdge(rn2, bn1);
Graph::NodeMap<int> node_map(graph);
node_map[rn1] = 11;
node_map[rn2] = 12;
node_map[rn3] = 13;
node_map[bn1] = 14;
node_map[bn2] = 15;
Graph::NodeMap<int> red_node_map(graph);
red_node_map[rn1] = 411;
red_node_map[rn2] = 412;
red_node_map[rn3] = 413;
Graph::NodeMap<int> blue_node_map(graph);
blue_node_map[bn1] = 414;
blue_node_map[bn2] = 415;
Graph::EdgeMap<int> edge_map(graph);
edge_map[e1] = 21;
edge_map[e2] = 22;
Graph::ArcMap<int> arc_map(graph);
arc_map[graph.direct(e1, true)] = 211;
arc_map[graph.direct(e1, false)] = 212;
arc_map[graph.direct(e2, true)] = 221;
arc_map[graph.direct(e2, false)] = 222;
int attr = 100;
std::ostringstream os;
lemon::BpGraphWriter<Graph> writer(graph, os);
writer.nodeMap("node_map1", node_map);
writer.nodeMap("node_map2", node_map, WriterConverter());
writer.nodeMap("red_node_map1", red_node_map);
writer.nodeMap("red_node_map2", red_node_map, WriterConverter());
writer.nodeMap("blue_node_map1", blue_node_map);
writer.nodeMap("blue_node_map2", blue_node_map, WriterConverter());
writer.edgeMap("edge_map1", edge_map);
writer.edgeMap("edge_map2", edge_map, WriterConverter());
writer.arcMap("arc_map1", arc_map);
writer.arcMap("arc_map2", arc_map, WriterConverter());
writer.node("node", n);
writer.redNode("red_node", rn1);
writer.blueNode("blue_node", bn2);
writer.edge("edge", e1);
writer.arc("arc", graph.direct(e1, false));
writer.attribute("attr1", attr);
writer.attribute("attr2", attr, WriterConverter());
writer.run();
typedef lemon::ListBpGraph ExpGraph;
ExpGraph exp_graph;
ExpGraph::NodeMap<int> exp_node_map1(exp_graph);
ExpGraph::NodeMap<int> exp_node_map2(exp_graph);
ExpGraph::RedNodeMap<int> exp_red_node_map1(exp_graph);
ExpGraph::RedNodeMap<int> exp_red_node_map2(exp_graph);
ExpGraph::BlueNodeMap<int> exp_blue_node_map1(exp_graph);
ExpGraph::BlueNodeMap<int> exp_blue_node_map2(exp_graph);
ExpGraph::EdgeMap<int> exp_edge_map1(exp_graph);
ExpGraph::EdgeMap<int> exp_edge_map2(exp_graph);
ExpGraph::ArcMap<int> exp_arc_map1(exp_graph);
ExpGraph::ArcMap<int> exp_arc_map2(exp_graph);
ExpGraph::Node exp_n;
ExpGraph::RedNode exp_rn1;
ExpGraph::BlueNode exp_bn2;
ExpGraph::Edge exp_e1;
ExpGraph::Arc exp_a1;
int exp_attr1;
int exp_attr2;
std::istringstream is(os.str());
lemon::BpGraphReader<ExpGraph> reader(exp_graph, is);
reader.nodeMap("node_map1", exp_node_map1);
reader.nodeMap("node_map2", exp_node_map2, ReaderConverter());
reader.redNodeMap("red_node_map1", exp_red_node_map1);
reader.redNodeMap("red_node_map2", exp_red_node_map2, ReaderConverter());
reader.blueNodeMap("blue_node_map1", exp_blue_node_map1);
reader.blueNodeMap("blue_node_map2", exp_blue_node_map2, ReaderConverter());
reader.edgeMap("edge_map1", exp_edge_map1);
reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter());
reader.arcMap("arc_map1", exp_arc_map1);
reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter());
reader.node("node", exp_n);
reader.redNode("red_node", exp_rn1);
reader.blueNode("blue_node", exp_bn2);
reader.edge("edge", exp_e1);
reader.arc("arc", exp_a1);
reader.attribute("attr1", exp_attr1);
reader.attribute("attr2", exp_attr2, ReaderConverter());
reader.run();
check(lemon::countNodes(exp_graph) == 5, "Wrong number of nodes");
check(lemon::countRedNodes(exp_graph) == 3, "Wrong number of red nodes");
check(lemon::countBlueNodes(exp_graph) == 2, "Wrong number of blue nodes");
check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges");
check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs");
check(exp_node_map1[exp_n] == 14, "Wrong map value");
check(exp_node_map2[exp_n] == 14, "Wrong map value");
check(exp_red_node_map1[exp_rn1] == 411, "Wrong map value");
check(exp_red_node_map2[exp_rn1] == 411, "Wrong map value");
check(exp_blue_node_map1[exp_bn2] == 415, "Wrong map value");
check(exp_blue_node_map2[exp_bn2] == 415, "Wrong map value");
check(exp_edge_map1[exp_e1] == 21, "Wrong map value");
check(exp_edge_map2[exp_e1] == 21, "Wrong map value");
check(exp_arc_map1[exp_a1] == 212, "Wrong map value");
check(exp_arc_map2[exp_a1] == 212, "Wrong map value");
check(exp_attr1 == 100, "Wrong attr value");
check(exp_attr2 == 100, "Wrong attr value");
}
int main() {
{ // Check digrpah
checkDigraphReaderWriter();
}
{ // Check graph
checkGraphReaderWriter();
}
{ // Check bipartite graph
checkBpGraphReaderWriter();
}
return 0;
}

View File

@@ -0,0 +1,169 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"@arcs\n"
" label\n"
"0 1 0\n"
"1 0 1\n"
"@attributes\n"
"source 0\n"
"target 1\n";
char test_lgf_nomap[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"@arcs\n"
" -\n"
"0 1\n";
char test_lgf_bad1[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"@arcs\n"
" - another\n"
"0 1\n";
char test_lgf_bad2[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"@arcs\n"
" label -\n"
"0 1\n";
int main()
{
{
ListDigraph d;
ListDigraph::Node s,t;
ListDigraph::ArcMap<int> label(d);
std::istringstream input(test_lgf);
digraphReader(d, input).
node("source", s).
node("target", t).
arcMap("label", label).
run();
check(countNodes(d) == 2,"There should be 2 nodes");
check(countArcs(d) == 2,"There should be 2 arcs");
}
{
ListGraph g;
ListGraph::Node s,t;
ListGraph::EdgeMap<int> label(g);
std::istringstream input(test_lgf);
graphReader(g, input).
node("source", s).
node("target", t).
edgeMap("label", label).
run();
check(countNodes(g) == 2,"There should be 2 nodes");
check(countEdges(g) == 2,"There should be 2 arcs");
}
{
ListDigraph d;
std::istringstream input(test_lgf_nomap);
digraphReader(d, input).
run();
check(countNodes(d) == 2,"There should be 2 nodes");
check(countArcs(d) == 1,"There should be 1 arc");
}
{
ListGraph g;
std::istringstream input(test_lgf_nomap);
graphReader(g, input).
run();
check(countNodes(g) == 2,"There should be 2 nodes");
check(countEdges(g) == 1,"There should be 1 edge");
}
{
ListDigraph d;
std::istringstream input(test_lgf_bad1);
bool ok=false;
try {
digraphReader(d, input).
run();
}
catch (FormatError&)
{
ok = true;
}
check(ok,"FormatError exception should have occured");
}
{
ListGraph g;
std::istringstream input(test_lgf_bad1);
bool ok=false;
try {
graphReader(g, input).
run();
}
catch (FormatError&)
{
ok = true;
}
check(ok,"FormatError exception should have occured");
}
{
ListDigraph d;
std::istringstream input(test_lgf_bad2);
bool ok=false;
try {
digraphReader(d, input).
run();
}
catch (FormatError&)
{
ok = true;
}
check(ok,"FormatError exception should have occured");
}
{
ListGraph g;
std::istringstream input(test_lgf_bad2);
bool ok=false;
try {
graphReader(g, input).
run();
}
catch (FormatError&)
{
ok = true;
}
check(ok,"FormatError exception should have occured");
}
}

View File

@@ -0,0 +1,470 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <sstream>
#include <lemon/lp_skeleton.h>
#include "test_tools.h"
#include <lemon/tolerance.h>
#include <lemon/config.h>
#ifdef LEMON_HAVE_GLPK
#include <lemon/glpk.h>
#endif
#ifdef LEMON_HAVE_CPLEX
#include <lemon/cplex.h>
#endif
#ifdef LEMON_HAVE_SOPLEX
#include <lemon/soplex.h>
#endif
#ifdef LEMON_HAVE_CLP
#include <lemon/clp.h>
#endif
#ifdef LEMON_HAVE_LP
#include <lemon/lp.h>
#endif
using namespace lemon;
int countCols(LpBase & lp) {
int count=0;
for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count;
return count;
}
int countRows(LpBase & lp) {
int count=0;
for (LpBase::RowIt r(lp); r!=INVALID; ++r) ++count;
return count;
}
void lpTest(LpSolver& lp)
{
typedef LpSolver LP;
// Test LpBase::clear()
check(countRows(lp)==0, "Wrong number of rows");
check(countCols(lp)==0, "Wrong number of cols");
lp.addCol(); lp.addRow(); lp.addRow();
check(countRows(lp)==2, "Wrong number of rows");
check(countCols(lp)==1, "Wrong number of cols");
lp.clear();
check(countRows(lp)==0, "Wrong number of rows");
check(countCols(lp)==0, "Wrong number of cols");
lp.addCol(); lp.addCol(); lp.addCol(); lp.addRow();
check(countRows(lp)==1, "Wrong number of rows");
check(countCols(lp)==3, "Wrong number of cols");
lp.clear();
std::vector<LP::Col> x(10);
// for(int i=0;i<10;i++) x.push_back(lp.addCol());
lp.addColSet(x);
lp.colLowerBound(x,1);
lp.colUpperBound(x,1);
lp.colBounds(x,1,2);
std::vector<LP::Col> y(10);
lp.addColSet(y);
lp.colLowerBound(y,1);
lp.colUpperBound(y,1);
lp.colBounds(y,1,2);
std::map<int,LP::Col> z;
z.insert(std::make_pair(12,INVALID));
z.insert(std::make_pair(2,INVALID));
z.insert(std::make_pair(7,INVALID));
z.insert(std::make_pair(5,INVALID));
lp.addColSet(z);
lp.colLowerBound(z,1);
lp.colUpperBound(z,1);
lp.colBounds(z,1,2);
{
LP::Expr e,f,g;
LP::Col p1,p2,p3,p4,p5;
LP::Constr c;
p1=lp.addCol();
p2=lp.addCol();
p3=lp.addCol();
p4=lp.addCol();
p5=lp.addCol();
e[p1]=2;
*e=12;
e[p1]+=2;
*e+=12;
e[p1]-=2;
*e-=12;
e=2;
e=2.2;
e=p1;
e=f;
e+=2;
e+=2.2;
e+=p1;
e+=f;
e-=2;
e-=2.2;
e-=p1;
e-=f;
e*=2;
e*=2.2;
e/=2;
e/=2.2;
e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+
(f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+
(f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+
2.2*f+f*2.2+f/2.2+
2*f+f*2+f/2+
2.2*p1+p1*2.2+p1/2.2+
2*p1+p1*2+p1/2
);
c = (e <= f );
c = (e <= 2.2);
c = (e <= 2 );
c = (e <= p1 );
c = (2.2<= f );
c = (2 <= f );
c = (p1 <= f );
c = (p1 <= p2 );
c = (p1 <= 2.2);
c = (p1 <= 2 );
c = (2.2<= p2 );
c = (2 <= p2 );
c = (e >= f );
c = (e >= 2.2);
c = (e >= 2 );
c = (e >= p1 );
c = (2.2>= f );
c = (2 >= f );
c = (p1 >= f );
c = (p1 >= p2 );
c = (p1 >= 2.2);
c = (p1 >= 2 );
c = (2.2>= p2 );
c = (2 >= p2 );
c = (e == f );
c = (e == 2.2);
c = (e == 2 );
c = (e == p1 );
c = (2.2== f );
c = (2 == f );
c = (p1 == f );
//c = (p1 == p2 );
c = (p1 == 2.2);
c = (p1 == 2 );
c = (2.2== p2 );
c = (2 == p2 );
c = ((2 <= e) <= 3);
c = ((2 <= p1) <= 3);
c = ((2 >= e) >= 3);
c = ((2 >= p1) >= 3);
{ //Tests for #430
LP::Col v=lp.addCol();
LP::Constr c = v >= -3;
c = c <= 4;
LP::Constr c2;
#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 3 )
c2 = ( -3 <= v ) <= 4;
#else
c2 = -3 <= v <= 4;
#endif
}
e[x[3]]=2;
e[x[3]]=4;
e[x[3]]=1;
*e=12;
lp.addRow(-LP::INF,e,23);
lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23);
lp.addRow(-LP::INF,3.0*(x[1]+x[2]*2-5*x[3]+12-x[4]/3)+2*x[4]-4,23);
lp.addRow(x[1]+x[3]<=x[5]-3);
lp.addRow((-7<=x[1]+x[3]-12)<=3);
lp.addRow(x[1]<=x[5]);
std::ostringstream buf;
e=((p1+p2)+(p1-0.99*p2));
//e.prettyPrint(std::cout);
//(e<=2).prettyPrint(std::cout);
double tolerance=0.001;
e.simplify(tolerance);
buf << "Coeff. of p2 should be 0.01";
check(e[p2]>0, buf.str());
tolerance=0.02;
e.simplify(tolerance);
buf << "Coeff. of p2 should be 0";
check(const_cast<const LpSolver::Expr&>(e)[p2]==0, buf.str());
//Test for clone/new
LP* lpnew = lp.newSolver();
LP* lpclone = lp.cloneSolver();
delete lpnew;
delete lpclone;
}
{
LP::DualExpr e,f,g;
LP::Row p1 = INVALID, p2 = INVALID;
e[p1]=2;
e[p1]+=2;
e[p1]-=2;
e=p1;
e=f;
e+=p1;
e+=f;
e-=p1;
e-=f;
e*=2;
e*=2.2;
e/=2;
e/=2.2;
e=((p1+p2)+(p1-p2)+
(p1+f)+(f+p1)+(f+g)+
(p1-f)+(f-p1)+(f-g)+
2.2*f+f*2.2+f/2.2+
2*f+f*2+f/2+
2.2*p1+p1*2.2+p1/2.2+
2*p1+p1*2+p1/2
);
}
}
void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat,
double exp_opt) {
using std::string;
lp.solve();
std::ostringstream buf;
buf << "PrimalType should be: " << int(stat) << int(lp.primalType());
check(lp.primalType()==stat, buf.str());
if (stat == LpSolver::OPTIMAL) {
std::ostringstream sbuf;
sbuf << "Wrong optimal value (" << lp.primal() <<") with "
<< lp.solverName() <<"\n the right optimum is " << exp_opt;
check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str());
}
}
void aTest(LpSolver & lp)
{
typedef LpSolver LP;
//The following example is very simple
typedef LpSolver::Row Row;
typedef LpSolver::Col Col;
Col x1 = lp.addCol();
Col x2 = lp.addCol();
//Constraints
Row upright=lp.addRow(x1+2*x2 <=1);
lp.addRow(x1+x2 >=-1);
lp.addRow(x1-x2 <=1);
lp.addRow(x1-x2 >=-1);
//Nonnegativity of the variables
lp.colLowerBound(x1, 0);
lp.colLowerBound(x2, 0);
//Objective function
lp.obj(x1+x2);
lp.sense(lp.MAX);
//Testing the problem retrieving routines
check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!");
check(lp.sense() == lp.MAX,"This is a maximization!");
check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!");
check(lp.colLowerBound(x1)==0,
"The lower bound for variable x1 should be 0.");
check(lp.colUpperBound(x1)==LpSolver::INF,
"The upper bound for variable x1 should be infty.");
check(lp.rowLowerBound(upright) == -LpSolver::INF,
"The lower bound for the first row should be -infty.");
check(lp.rowUpperBound(upright)==1,
"The upper bound for the first row should be 1.");
LpSolver::Expr e = lp.row(upright);
check(e[x1] == 1, "The first coefficient should 1.");
check(e[x2] == 2, "The second coefficient should 1.");
lp.row(upright, x1+x2 <=1);
e = lp.row(upright);
check(e[x1] == 1, "The first coefficient should 1.");
check(e[x2] == 1, "The second coefficient should 1.");
LpSolver::DualExpr de = lp.col(x1);
check( de[upright] == 1, "The first coefficient should 1.");
LpSolver* clp = lp.cloneSolver();
//Testing the problem retrieving routines
check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!");
check(clp->sense() == clp->MAX,"This is a maximization!");
check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!");
// std::cout<<lp.colLowerBound(x1)<<std::endl;
check(clp->colLowerBound(x1)==0,
"The lower bound for variable x1 should be 0.");
check(clp->colUpperBound(x1)==LpSolver::INF,
"The upper bound for variable x1 should be infty.");
check(lp.rowLowerBound(upright)==-LpSolver::INF,
"The lower bound for the first row should be -infty.");
check(lp.rowUpperBound(upright)==1,
"The upper bound for the first row should be 1.");
e = clp->row(upright);
check(e[x1] == 1, "The first coefficient should 1.");
check(e[x2] == 1, "The second coefficient should 1.");
de = clp->col(x1);
check(de[upright] == 1, "The first coefficient should 1.");
delete clp;
//Maximization of x1+x2
//over the triangle with vertices (0,0) (0,1) (1,0)
double expected_opt=1;
solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
//Minimization
lp.sense(lp.MIN);
expected_opt=0;
solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
//Vertex (-1,0) instead of (0,0)
lp.colLowerBound(x1, -LpSolver::INF);
expected_opt=-1;
solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
//Erase one constraint and return to maximization
lp.erase(upright);
lp.sense(lp.MAX);
expected_opt=LpSolver::INF;
solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt);
//Infeasibilty
lp.addRow(x1+x2 <=-2);
solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt);
}
template<class LP>
void cloneTest()
{
//Test for clone/new
LP* lp = new LP();
LP* lpnew = lp->newSolver();
LP* lpclone = lp->cloneSolver();
delete lp;
delete lpnew;
delete lpclone;
}
int main()
{
LpSkeleton lp_skel;
lpTest(lp_skel);
#ifdef LEMON_HAVE_LP
{
Lp lp,lp2;
lpTest(lp);
aTest(lp2);
cloneTest<Lp>();
}
#endif
#ifdef LEMON_HAVE_GLPK
{
GlpkLp lp_glpk1,lp_glpk2;
lpTest(lp_glpk1);
aTest(lp_glpk2);
cloneTest<GlpkLp>();
}
#endif
#ifdef LEMON_HAVE_CPLEX
try {
CplexLp lp_cplex1,lp_cplex2;
lpTest(lp_cplex1);
aTest(lp_cplex2);
cloneTest<CplexLp>();
} catch (CplexEnv::LicenseError& error) {
check(false, error.what());
}
#endif
#ifdef LEMON_HAVE_SOPLEX
{
SoplexLp lp_soplex1,lp_soplex2;
lpTest(lp_soplex1);
aTest(lp_soplex2);
cloneTest<SoplexLp>();
}
#endif
#ifdef LEMON_HAVE_CLP
{
ClpLp lp_clp1,lp_clp2;
lpTest(lp_clp1);
aTest(lp_clp2);
cloneTest<ClpLp>();
}
#endif
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,449 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <sstream>
#include <vector>
#include <queue>
#include <cstdlib>
#include <lemon/matching.h>
#include <lemon/smart_graph.h>
#include <lemon/concepts/graph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/math.h>
#include "test_tools.h"
using namespace std;
using namespace lemon;
GRAPH_TYPEDEFS(SmartGraph);
const int lgfn = 3;
const std::string lgf[lgfn] = {
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"7 4 0 984\n"
"0 7 1 73\n"
"7 1 2 204\n"
"2 3 3 583\n"
"2 7 4 565\n"
"2 1 5 582\n"
"0 4 6 551\n"
"2 5 7 385\n"
"1 5 8 561\n"
"5 3 9 484\n"
"7 5 10 904\n"
"3 6 11 47\n"
"7 6 12 888\n"
"3 0 13 747\n"
"6 1 14 310\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"2 5 0 710\n"
"0 5 1 241\n"
"2 4 2 856\n"
"2 6 3 762\n"
"4 1 4 747\n"
"6 1 5 962\n"
"4 7 6 723\n"
"1 7 7 661\n"
"2 3 8 376\n"
"1 0 9 416\n"
"6 7 10 391\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@edges\n"
" label weight\n"
"6 2 0 553\n"
"0 7 1 653\n"
"6 3 2 22\n"
"4 7 3 846\n"
"7 2 4 981\n"
"7 6 5 250\n"
"5 2 6 539\n",
};
void checkMaxMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef Graph::EdgeMap<bool> MatMap;
Graph g;
Node n;
Edge e;
MatMap mat(g);
MaxMatching<Graph> mat_test(g);
const MaxMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.greedyInit();
mat_test.matchingInit(mat);
mat_test.startSparse();
mat_test.startDense();
mat_test.run();
const_mat_test.matchingSize();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.mate(n);
MaxMatching<Graph>::Status stat =
const_mat_test.status(n);
::lemon::ignore_unused_variable_warning(stat);
const MaxMatching<Graph>::StatusMap& smap =
const_mat_test.statusMap();
stat = smap[n];
const_mat_test.barrier(n);
}
void checkMaxWeightedMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef Graph::EdgeMap<int> WeightMap;
Graph g;
Node n;
Edge e;
WeightMap w(g);
MaxWeightedMatching<Graph> mat_test(g, w);
const MaxWeightedMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.start();
mat_test.run();
const_mat_test.matchingWeight();
const_mat_test.matchingSize();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxWeightedMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.mate(n);
int k = 0;
const_mat_test.dualValue();
const_mat_test.nodeValue(n);
const_mat_test.blossomNum();
const_mat_test.blossomSize(k);
const_mat_test.blossomValue(k);
}
void checkMaxWeightedPerfectMatchingCompile()
{
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef Graph::EdgeMap<int> WeightMap;
Graph g;
Node n;
Edge e;
WeightMap w(g);
MaxWeightedPerfectMatching<Graph> mat_test(g, w);
const MaxWeightedPerfectMatching<Graph>&
const_mat_test = mat_test;
mat_test.init();
mat_test.start();
mat_test.run();
const_mat_test.matchingWeight();
const_mat_test.matching(e);
const_mat_test.matching(n);
const MaxWeightedPerfectMatching<Graph>::MatchingMap& mmap =
const_mat_test.matchingMap();
e = mmap[n];
const_mat_test.mate(n);
int k = 0;
const_mat_test.dualValue();
const_mat_test.nodeValue(n);
const_mat_test.blossomNum();
const_mat_test.blossomSize(k);
const_mat_test.blossomValue(k);
}
void checkMatching(const SmartGraph& graph,
const MaxMatching<SmartGraph>& mm) {
int num = 0;
IntNodeMap comp_index(graph);
UnionFind<IntNodeMap> comp(comp_index);
int barrier_num = 0;
for (NodeIt n(graph); n != INVALID; ++n) {
check(mm.status(n) == MaxMatching<SmartGraph>::EVEN ||
mm.matching(n) != INVALID, "Wrong Gallai-Edmonds decomposition");
if (mm.status(n) == MaxMatching<SmartGraph>::ODD) {
++barrier_num;
} else {
comp.insert(n);
}
}
for (EdgeIt e(graph); e != INVALID; ++e) {
if (mm.matching(e)) {
check(e == mm.matching(graph.u(e)), "Wrong matching");
check(e == mm.matching(graph.v(e)), "Wrong matching");
++num;
}
check(mm.status(graph.u(e)) != MaxMatching<SmartGraph>::EVEN ||
mm.status(graph.v(e)) != MaxMatching<SmartGraph>::MATCHED,
"Wrong Gallai-Edmonds decomposition");
check(mm.status(graph.v(e)) != MaxMatching<SmartGraph>::EVEN ||
mm.status(graph.u(e)) != MaxMatching<SmartGraph>::MATCHED,
"Wrong Gallai-Edmonds decomposition");
if (mm.status(graph.u(e)) != MaxMatching<SmartGraph>::ODD &&
mm.status(graph.v(e)) != MaxMatching<SmartGraph>::ODD) {
comp.join(graph.u(e), graph.v(e));
}
}
std::set<int> comp_root;
int odd_comp_num = 0;
for (NodeIt n(graph); n != INVALID; ++n) {
if (mm.status(n) != MaxMatching<SmartGraph>::ODD) {
int root = comp.find(n);
if (comp_root.find(root) == comp_root.end()) {
comp_root.insert(root);
if (comp.size(n) % 2 == 1) {
++odd_comp_num;
}
}
}
}
check(mm.matchingSize() == num, "Wrong matching");
check(2 * num == countNodes(graph) - (odd_comp_num - barrier_num),
"Wrong matching");
return;
}
void checkWeightedMatching(const SmartGraph& graph,
const SmartGraph::EdgeMap<int>& weight,
const MaxWeightedMatching<SmartGraph>& mwm) {
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
if (graph.u(e) == graph.v(e)) continue;
int rw = mwm.nodeValue(graph.u(e)) + mwm.nodeValue(graph.v(e));
for (int i = 0; i < mwm.blossomNum(); ++i) {
bool s = false, t = false;
for (MaxWeightedMatching<SmartGraph>::BlossomIt n(mwm, i);
n != INVALID; ++n) {
if (graph.u(e) == n) s = true;
if (graph.v(e) == n) t = true;
}
if (s == true && t == true) {
rw += mwm.blossomValue(i);
}
}
rw -= weight[e] * mwm.dualScale;
check(rw >= 0, "Negative reduced weight");
check(rw == 0 || !mwm.matching(e),
"Non-zero reduced weight on matching edge");
}
int pv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
if (mwm.matching(n) != INVALID) {
check(mwm.nodeValue(n) >= 0, "Invalid node value");
pv += weight[mwm.matching(n)];
SmartGraph::Node o = graph.target(mwm.matching(n));
check(mwm.mate(n) == o, "Invalid matching");
check(mwm.matching(n) == graph.oppositeArc(mwm.matching(o)),
"Invalid matching");
} else {
check(mwm.mate(n) == INVALID, "Invalid matching");
check(mwm.nodeValue(n) == 0, "Invalid matching");
}
}
int dv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
dv += mwm.nodeValue(n);
}
for (int i = 0; i < mwm.blossomNum(); ++i) {
check(mwm.blossomValue(i) >= 0, "Invalid blossom value");
check(mwm.blossomSize(i) % 2 == 1, "Even blossom size");
dv += mwm.blossomValue(i) * ((mwm.blossomSize(i) - 1) / 2);
}
check(pv * mwm.dualScale == dv * 2, "Wrong duality");
return;
}
void checkWeightedPerfectMatching(const SmartGraph& graph,
const SmartGraph::EdgeMap<int>& weight,
const MaxWeightedPerfectMatching<SmartGraph>& mwpm) {
for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) {
if (graph.u(e) == graph.v(e)) continue;
int rw = mwpm.nodeValue(graph.u(e)) + mwpm.nodeValue(graph.v(e));
for (int i = 0; i < mwpm.blossomNum(); ++i) {
bool s = false, t = false;
for (MaxWeightedPerfectMatching<SmartGraph>::BlossomIt n(mwpm, i);
n != INVALID; ++n) {
if (graph.u(e) == n) s = true;
if (graph.v(e) == n) t = true;
}
if (s == true && t == true) {
rw += mwpm.blossomValue(i);
}
}
rw -= weight[e] * mwpm.dualScale;
check(rw >= 0, "Negative reduced weight");
check(rw == 0 || !mwpm.matching(e),
"Non-zero reduced weight on matching edge");
}
int pv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
check(mwpm.matching(n) != INVALID, "Non perfect");
pv += weight[mwpm.matching(n)];
SmartGraph::Node o = graph.target(mwpm.matching(n));
check(mwpm.mate(n) == o, "Invalid matching");
check(mwpm.matching(n) == graph.oppositeArc(mwpm.matching(o)),
"Invalid matching");
}
int dv = 0;
for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) {
dv += mwpm.nodeValue(n);
}
for (int i = 0; i < mwpm.blossomNum(); ++i) {
check(mwpm.blossomValue(i) >= 0, "Invalid blossom value");
check(mwpm.blossomSize(i) % 2 == 1, "Even blossom size");
dv += mwpm.blossomValue(i) * ((mwpm.blossomSize(i) - 1) / 2);
}
check(pv * mwpm.dualScale == dv * 2, "Wrong duality");
return;
}
int main() {
for (int i = 0; i < lgfn; ++i) {
SmartGraph graph;
SmartGraph::EdgeMap<int> weight(graph);
istringstream lgfs(lgf[i]);
graphReader(graph, lgfs).
edgeMap("weight", weight).run();
bool perfect;
{
MaxMatching<SmartGraph> mm(graph);
mm.run();
checkMatching(graph, mm);
perfect = 2 * mm.matchingSize() == countNodes(graph);
}
{
MaxWeightedMatching<SmartGraph> mwm(graph, weight);
mwm.run();
checkWeightedMatching(graph, weight, mwm);
}
{
MaxWeightedMatching<SmartGraph> mwm(graph, weight);
mwm.init();
mwm.start();
checkWeightedMatching(graph, weight, mwm);
}
{
MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight);
bool result = mwpm.run();
check(result == perfect, "Perfect matching found");
if (perfect) {
checkWeightedPerfectMatching(graph, weight, mwpm);
}
}
{
MaxWeightedPerfectMatching<SmartGraph> mwpm(graph, weight);
mwpm.init();
bool result = mwpm.start();
check(result == perfect, "Perfect matching found");
if (perfect) {
checkWeightedPerfectMatching(graph, weight, mwpm);
}
}
}
return 0;
}

View File

@@ -0,0 +1,162 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include "test_tools.h"
#include <lemon/smart_graph.h>
#include <lemon/max_cardinality_search.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/maps.h>
#include <lemon/concepts/heap.h>
#include <lemon/lgf_reader.h>
using namespace lemon;
using namespace std;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"@arcs\n"
" label capacity\n"
"0 1 0 2\n"
"1 0 1 2\n"
"2 1 2 1\n"
"2 3 3 3\n"
"3 2 4 3\n"
"3 1 5 5\n"
"@attributes\n"
"s 0\n"
"x 1\n"
"y 2\n"
"z 3\n";
void checkMaxCardSearchCompile() {
typedef concepts::Digraph Digraph;
typedef int Value;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
typedef concepts::ReadMap<Arc,Value> CapMap;
typedef concepts::ReadWriteMap<Node,Value> CardMap;
typedef concepts::ReadWriteMap<Node,bool> ProcMap;
typedef Digraph::NodeMap<int> HeapCrossRef;
Digraph g;
Node n,s;
CapMap cap;
CardMap card;
ProcMap proc;
HeapCrossRef crossref(g);
typedef MaxCardinalitySearch<Digraph,CapMap>
::SetCapacityMap<CapMap>
::SetCardinalityMap<CardMap>
::SetProcessedMap<ProcMap>
::SetStandardHeap<BinHeap<Value,HeapCrossRef> >
::Create MaxCardType;
MaxCardType maxcard(g,cap);
const MaxCardType& const_maxcard = maxcard;
const MaxCardType::Heap& heap_const = const_maxcard.heap();
MaxCardType::Heap& heap = const_cast<MaxCardType::Heap&>(heap_const);
maxcard.heap(heap,crossref);
maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc);
maxcard.init();
maxcard.addSource(s);
n = maxcard.nextNode();
maxcard.processNextNode();
maxcard.start();
maxcard.run(s);
maxcard.run();
}
void checkWithIntMap( std::istringstream& input)
{
typedef SmartDigraph Digraph;
typedef Digraph::Node Node;
typedef Digraph::ArcMap<int> CapMap;
Digraph g;
Node s,x,y,z,a;
CapMap cap(g);
DigraphReader<Digraph>(g,input).
arcMap("capacity", cap).
node("s",s).
node("x",x).
node("y",y).
node("z",z).
run();
MaxCardinalitySearch<Digraph,CapMap> maxcard(g,cap);
maxcard.init();
maxcard.addSource(s);
maxcard.start(x);
check(maxcard.processed(s) && !maxcard.processed(x) &&
!maxcard.processed(y), "Wrong processed()!");
a=maxcard.nextNode();
check(maxcard.processNextNode()==a,
"Wrong nextNode() or processNextNode() return value!");
check(maxcard.processed(a), "Wrong processNextNode()!");
maxcard.start();
check(maxcard.cardinality(x)==2 && maxcard.cardinality(y)>=4,
"Wrong cardinalities!");
}
void checkWithConst1Map(std::istringstream &input) {
typedef SmartDigraph Digraph;
typedef Digraph::Node Node;
Digraph g;
Node s,x,y,z;
DigraphReader<Digraph>(g,input).
node("s",s).
node("x",x).
node("y",y).
node("z",z).
run();
MaxCardinalitySearch<Digraph> maxcard(g);
maxcard.run(s);
check(maxcard.cardinality(x)==1 &&
maxcard.cardinality(y)+maxcard.cardinality(z)==3,
"Wrong cardinalities!");
}
int main() {
std::istringstream input1(test_lgf);
checkWithIntMap(input1);
std::istringstream input2(test_lgf);
checkWithConst1Map(input2);
}

View File

@@ -0,0 +1,188 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <sstream>
#include <lemon/list_graph.h>
#include <lemon/full_graph.h>
#include <lemon/grid_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/grosso_locatelli_pullan_mc.h>
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label max_clique\n"
"1 0\n"
"2 0\n"
"3 0\n"
"4 1\n"
"5 1\n"
"6 1\n"
"7 1\n"
"@edges\n"
" label\n"
"1 2 1\n"
"1 3 2\n"
"1 4 3\n"
"1 6 4\n"
"2 3 5\n"
"2 5 6\n"
"2 7 7\n"
"3 4 8\n"
"3 5 9\n"
"4 5 10\n"
"4 6 11\n"
"4 7 12\n"
"5 6 13\n"
"5 7 14\n"
"6 7 15\n";
// Check with general graphs
template <typename Param>
void checkMaxCliqueGeneral(Param rule) {
typedef ListGraph GR;
typedef GrossoLocatelliPullanMc<GR> McAlg;
typedef McAlg::CliqueNodeIt CliqueIt;
// Basic tests
{
GR g;
GR::NodeMap<bool> map(g);
McAlg mc(g);
mc.iterationLimit(50);
check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 0, "Wrong clique size");
check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt");
GR::Node u = g.addNode();
check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 1, "Wrong clique size");
mc.cliqueMap(map);
check(map[u], "Wrong clique map");
CliqueIt it1(mc);
check(static_cast<GR::Node>(it1) == u && ++it1 == INVALID,
"Wrong CliqueNodeIt");
GR::Node v = g.addNode();
check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 1, "Wrong clique size");
mc.cliqueMap(map);
check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map");
CliqueIt it2(mc);
check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt");
g.addEdge(u, v);
check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 2, "Wrong clique size");
mc.cliqueMap(map);
check(map[u] && map[v], "Wrong clique map");
CliqueIt it3(mc);
check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID,
"Wrong CliqueNodeIt");
}
// Test graph
{
GR g;
GR::NodeMap<bool> max_clique(g);
GR::NodeMap<bool> map(g);
std::istringstream input(test_lgf);
graphReader(g, input)
.nodeMap("max_clique", max_clique)
.run();
McAlg mc(g);
mc.iterationLimit(50);
check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 4, "Wrong clique size");
mc.cliqueMap(map);
for (GR::NodeIt n(g); n != INVALID; ++n) {
check(map[n] == max_clique[n], "Wrong clique map");
}
int cnt = 0;
for (CliqueIt n(mc); n != INVALID; ++n) {
cnt++;
check(map[n] && max_clique[n], "Wrong CliqueNodeIt");
}
check(cnt == 4, "Wrong CliqueNodeIt");
}
}
// Check with full graphs
template <typename Param>
void checkMaxCliqueFullGraph(Param rule) {
typedef FullGraph GR;
typedef GrossoLocatelliPullanMc<FullGraph> McAlg;
typedef McAlg::CliqueNodeIt CliqueIt;
for (int size = 0; size <= 40; size = size * 3 + 1) {
GR g(size);
GR::NodeMap<bool> map(g);
McAlg mc(g);
check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == size, "Wrong clique size");
mc.cliqueMap(map);
for (GR::NodeIt n(g); n != INVALID; ++n) {
check(map[n], "Wrong clique map");
}
int cnt = 0;
for (CliqueIt n(mc); n != INVALID; ++n) cnt++;
check(cnt == size, "Wrong CliqueNodeIt");
}
}
// Check with grid graphs
template <typename Param>
void checkMaxCliqueGridGraph(Param rule) {
GridGraph g(5, 7);
GridGraph::NodeMap<char> map(g);
GrossoLocatelliPullanMc<GridGraph> mc(g);
mc.iterationLimit(100);
check(mc.run(rule) == mc.ITERATION_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 2, "Wrong clique size");
mc.stepLimit(100);
check(mc.run(rule) == mc.STEP_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 2, "Wrong clique size");
mc.sizeLimit(2);
check(mc.run(rule) == mc.SIZE_LIMIT, "Wrong termination cause");
check(mc.cliqueSize() == 2, "Wrong clique size");
}
int main() {
checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::RANDOM);
checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::DEGREE_BASED);
checkMaxCliqueGeneral(GrossoLocatelliPullanMc<ListGraph>::PENALTY_BASED);
checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::RANDOM);
checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::DEGREE_BASED);
checkMaxCliqueFullGraph(GrossoLocatelliPullanMc<FullGraph>::PENALTY_BASED);
checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::RANDOM);
checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::DEGREE_BASED);
checkMaxCliqueGridGraph(GrossoLocatelliPullanMc<GridGraph>::PENALTY_BASED);
return 0;
}

View File

@@ -0,0 +1,395 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include "test_tools.h"
#include <lemon/smart_graph.h>
#include <lemon/preflow.h>
#include <lemon/edmonds_karp.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/elevator.h>
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"8\n"
"9\n"
"@arcs\n"
" label capacity\n"
"0 1 0 20\n"
"0 2 1 0\n"
"1 1 2 3\n"
"1 2 3 8\n"
"1 3 4 8\n"
"2 5 5 5\n"
"3 2 6 5\n"
"3 5 7 5\n"
"3 6 8 5\n"
"4 3 9 3\n"
"5 7 10 3\n"
"5 6 11 10\n"
"5 8 12 10\n"
"6 8 13 8\n"
"8 9 14 20\n"
"8 1 15 5\n"
"9 5 16 5\n"
"@attributes\n"
"source 1\n"
"target 8\n";
// Checks the general interface of a max flow algorithm
template <typename GR, typename CAP>
struct MaxFlowClassConcept
{
template <typename MF>
struct Constraints {
typedef typename GR::Node Node;
typedef typename GR::Arc Arc;
typedef typename CAP::Value Value;
typedef concepts::ReadWriteMap<Arc, Value> FlowMap;
typedef concepts::WriteMap<Node, bool> CutMap;
GR g;
Node n;
Arc e;
CAP cap;
FlowMap flow;
CutMap cut;
Value v;
bool b;
void constraints() {
checkConcept<concepts::Digraph, GR>();
const Constraints& me = *this;
typedef typename MF
::template SetFlowMap<FlowMap>
::Create MaxFlowType;
typedef typename MF::Create MaxFlowType2;
MaxFlowType max_flow(me.g, me.cap, me.n, me.n);
const MaxFlowType& const_max_flow = max_flow;
max_flow
.capacityMap(cap)
.flowMap(flow)
.source(n)
.target(n);
typename MaxFlowType::Tolerance tol = const_max_flow.tolerance();
max_flow.tolerance(tol);
max_flow.init();
max_flow.init(cap);
max_flow.run();
v = const_max_flow.flowValue();
v = const_max_flow.flow(e);
const FlowMap& fm = const_max_flow.flowMap();
b = const_max_flow.minCut(n);
const_max_flow.minCutMap(cut);
::lemon::ignore_unused_variable_warning(fm);
}
};
};
// Checks the specific parts of Preflow's interface
void checkPreflowCompile()
{
typedef int Value;
typedef concepts::Digraph Digraph;
typedef concepts::ReadMap<Digraph::Arc, Value> CapMap;
typedef Elevator<Digraph, Digraph::Node> Elev;
typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
Digraph g;
Digraph::Node n;
CapMap cap;
typedef Preflow<Digraph, CapMap>
::SetElevator<Elev>
::SetStandardElevator<LinkedElev>
::Create PreflowType;
PreflowType preflow_test(g, cap, n, n);
const PreflowType& const_preflow_test = preflow_test;
const PreflowType::Elevator& elev = const_preflow_test.elevator();
preflow_test.elevator(const_cast<PreflowType::Elevator&>(elev));
bool b = preflow_test.init(cap);
preflow_test.startFirstPhase();
preflow_test.startSecondPhase();
preflow_test.runMinCut();
::lemon::ignore_unused_variable_warning(b);
}
// Checks the specific parts of EdmondsKarp's interface
void checkEdmondsKarpCompile()
{
typedef int Value;
typedef concepts::Digraph Digraph;
typedef concepts::ReadMap<Digraph::Arc, Value> CapMap;
typedef Elevator<Digraph, Digraph::Node> Elev;
typedef LinkedElevator<Digraph, Digraph::Node> LinkedElev;
Digraph g;
Digraph::Node n;
CapMap cap;
EdmondsKarp<Digraph, CapMap> ek_test(g, cap, n, n);
ek_test.init(cap);
bool b = ek_test.checkedInit(cap);
b = ek_test.augment();
ek_test.start();
::lemon::ignore_unused_variable_warning(b);
}
template <typename T>
T cutValue (const SmartDigraph& g,
const SmartDigraph::NodeMap<bool>& cut,
const SmartDigraph::ArcMap<T>& cap) {
T c=0;
for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) {
if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e];
}
return c;
}
template <typename T>
bool checkFlow(const SmartDigraph& g,
const SmartDigraph::ArcMap<T>& flow,
const SmartDigraph::ArcMap<T>& cap,
SmartDigraph::Node s, SmartDigraph::Node t) {
for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) {
if (flow[e] < 0 || flow[e] > cap[e]) return false;
}
for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) {
if (n == s || n == t) continue;
T sum = 0;
for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) {
sum += flow[e];
}
for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) {
sum -= flow[e];
}
if (sum != 0) return false;
}
return true;
}
void initFlowTest()
{
DIGRAPH_TYPEDEFS(SmartDigraph);
SmartDigraph g;
SmartDigraph::ArcMap<int> cap(g),iflow(g);
Node s=g.addNode(); Node t=g.addNode();
Node n1=g.addNode(); Node n2=g.addNode();
Arc a;
a=g.addArc(s,n1); cap[a]=20; iflow[a]=20;
a=g.addArc(n1,n2); cap[a]=10; iflow[a]=0;
a=g.addArc(n2,t); cap[a]=20; iflow[a]=0;
Preflow<SmartDigraph> pre(g,cap,s,t);
pre.init(iflow);
pre.startFirstPhase();
check(pre.flowValue() == 10, "The incorrect max flow value.");
check(pre.minCut(s), "Wrong min cut (Node s).");
check(pre.minCut(n1), "Wrong min cut (Node n1).");
check(!pre.minCut(n2), "Wrong min cut (Node n2).");
check(!pre.minCut(t), "Wrong min cut (Node t).");
}
template <typename MF, typename SF>
void checkMaxFlowAlg() {
typedef SmartDigraph Digraph;
DIGRAPH_TYPEDEFS(Digraph);
typedef typename MF::Value Value;
typedef Digraph::ArcMap<Value> CapMap;
typedef CapMap FlowMap;
typedef BoolNodeMap CutMap;
Digraph g;
Node s, t;
CapMap cap(g);
std::istringstream input(test_lgf);
DigraphReader<Digraph>(g,input)
.arcMap("capacity", cap)
.node("source",s)
.node("target",t)
.run();
MF max_flow(g, cap, s, t);
max_flow.run();
check(checkFlow(g, max_flow.flowMap(), cap, s, t),
"The flow is not feasible.");
CutMap min_cut(g);
max_flow.minCutMap(min_cut);
Value min_cut_value = cutValue(g, min_cut, cap);
check(max_flow.flowValue() == min_cut_value,
"The max flow value is not equal to the min cut value.");
FlowMap flow(g);
for (ArcIt e(g); e != INVALID; ++e) flow[e] = max_flow.flowMap()[e];
Value flow_value = max_flow.flowValue();
for (ArcIt e(g); e != INVALID; ++e) cap[e] = 2 * cap[e];
max_flow.init(flow);
SF::startFirstPhase(max_flow); // start first phase of the algorithm
CutMap min_cut1(g);
max_flow.minCutMap(min_cut1);
min_cut_value = cutValue(g, min_cut1, cap);
check(max_flow.flowValue() == min_cut_value &&
min_cut_value == 2 * flow_value,
"The max flow value or the min cut value is wrong.");
SF::startSecondPhase(max_flow); // start second phase of the algorithm
check(checkFlow(g, max_flow.flowMap(), cap, s, t),
"The flow is not feasible.");
CutMap min_cut2(g);
max_flow.minCutMap(min_cut2);
min_cut_value = cutValue(g, min_cut2, cap);
check(max_flow.flowValue() == min_cut_value &&
min_cut_value == 2 * flow_value,
"The max flow value or the min cut value was not doubled");
max_flow.flowMap(flow);
NodeIt tmp1(g, s);
++tmp1;
if (tmp1 != INVALID) s = tmp1;
NodeIt tmp2(g, t);
++tmp2;
if (tmp2 != INVALID) t = tmp2;
max_flow.source(s);
max_flow.target(t);
max_flow.run();
CutMap min_cut3(g);
max_flow.minCutMap(min_cut3);
min_cut_value=cutValue(g, min_cut3, cap);
check(max_flow.flowValue() == min_cut_value,
"The max flow value or the min cut value is wrong.");
}
// Struct for calling start functions of a general max flow algorithm
template <typename MF>
struct GeneralStartFunctions {
static void startFirstPhase(MF& mf) {
mf.start();
}
static void startSecondPhase(MF& mf) {
::lemon::ignore_unused_variable_warning(mf);
}
};
// Struct for calling start functions of Preflow
template <typename MF>
struct PreflowStartFunctions {
static void startFirstPhase(MF& mf) {
mf.startFirstPhase();
}
static void startSecondPhase(MF& mf) {
mf.startSecondPhase();
}
};
int main() {
typedef concepts::Digraph GR;
typedef concepts::ReadMap<GR::Arc, int> CM1;
typedef concepts::ReadMap<GR::Arc, double> CM2;
// Check the interface of Preflow
checkConcept< MaxFlowClassConcept<GR, CM1>,
Preflow<GR, CM1> >();
checkConcept< MaxFlowClassConcept<GR, CM2>,
Preflow<GR, CM2> >();
// Check the interface of EdmondsKarp
checkConcept< MaxFlowClassConcept<GR, CM1>,
EdmondsKarp<GR, CM1> >();
checkConcept< MaxFlowClassConcept<GR, CM2>,
EdmondsKarp<GR, CM2> >();
// Check Preflow
typedef Preflow<SmartDigraph, SmartDigraph::ArcMap<int> > PType1;
typedef Preflow<SmartDigraph, SmartDigraph::ArcMap<float> > PType2;
checkMaxFlowAlg<PType1, PreflowStartFunctions<PType1> >();
checkMaxFlowAlg<PType2, PreflowStartFunctions<PType2> >();
initFlowTest();
// Check EdmondsKarp
typedef EdmondsKarp<SmartDigraph, SmartDigraph::ArcMap<int> > EKType1;
typedef EdmondsKarp<SmartDigraph, SmartDigraph::ArcMap<float> > EKType2;
checkMaxFlowAlg<EKType1, GeneralStartFunctions<EKType1> >();
checkMaxFlowAlg<EKType2, GeneralStartFunctions<EKType2> >();
initFlowTest();
return 0;
}

View File

@@ -0,0 +1,207 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <set>
#include <vector>
#include <iterator>
#include <lemon/smart_graph.h>
#include <lemon/min_cost_arborescence.h>
#include <lemon/lgf_reader.h>
#include <lemon/concepts/digraph.h>
#include "test_tools.h"
using namespace lemon;
using namespace std;
const char test_lgf[] =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"8\n"
"9\n"
"@arcs\n"
" label cost\n"
"1 8 0 107\n"
"0 3 1 70\n"
"2 1 2 46\n"
"4 1 3 28\n"
"4 4 4 91\n"
"3 9 5 76\n"
"9 8 6 61\n"
"8 1 7 39\n"
"9 8 8 74\n"
"8 0 9 39\n"
"4 3 10 45\n"
"2 2 11 34\n"
"0 1 12 100\n"
"6 3 13 95\n"
"4 1 14 22\n"
"1 1 15 31\n"
"7 2 16 51\n"
"2 6 17 29\n"
"8 3 18 115\n"
"6 9 19 32\n"
"1 1 20 60\n"
"0 3 21 40\n"
"@attributes\n"
"source 0\n";
void checkMinCostArborescenceCompile()
{
typedef double VType;
typedef concepts::Digraph Digraph;
typedef concepts::ReadMap<Digraph::Arc, VType> CostMap;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
typedef concepts::WriteMap<Digraph::Arc, bool> ArbMap;
typedef concepts::ReadWriteMap<Digraph::Node, Digraph::Arc> PredMap;
typedef MinCostArborescence<Digraph, CostMap>::
SetArborescenceMap<ArbMap>::
SetPredMap<PredMap>::Create MinCostArbType;
Digraph g;
Node s, n;
Arc e;
VType c;
bool b;
::lemon::ignore_unused_variable_warning(c,b);
int i;
CostMap cost;
ArbMap arb;
PredMap pred;
MinCostArbType mcarb_test(g, cost);
const MinCostArbType& const_mcarb_test = mcarb_test;
mcarb_test
.arborescenceMap(arb)
.predMap(pred)
.run(s);
mcarb_test.init();
mcarb_test.addSource(s);
mcarb_test.start();
n = mcarb_test.processNextNode();
b = const_mcarb_test.emptyQueue();
i = const_mcarb_test.queueSize();
c = const_mcarb_test.arborescenceCost();
b = const_mcarb_test.arborescence(e);
e = const_mcarb_test.pred(n);
const MinCostArbType::ArborescenceMap &am =
const_mcarb_test.arborescenceMap();
const MinCostArbType::PredMap &pm =
const_mcarb_test.predMap();
b = const_mcarb_test.reached(n);
b = const_mcarb_test.processed(n);
i = const_mcarb_test.dualNum();
c = const_mcarb_test.dualValue();
i = const_mcarb_test.dualSize(i);
c = const_mcarb_test.dualValue(i);
::lemon::ignore_unused_variable_warning(am);
::lemon::ignore_unused_variable_warning(pm);
}
int main() {
typedef SmartDigraph Digraph;
DIGRAPH_TYPEDEFS(Digraph);
typedef Digraph::ArcMap<double> CostMap;
Digraph digraph;
CostMap cost(digraph);
Node source;
std::istringstream is(test_lgf);
digraphReader(digraph, is).
arcMap("cost", cost).
node("source", source).run();
MinCostArborescence<Digraph, CostMap> mca(digraph, cost);
mca.run(source);
vector<pair<double, set<Node> > > dualSolution(mca.dualNum());
for (int i = 0; i < mca.dualNum(); ++i) {
dualSolution[i].first = mca.dualValue(i);
for (MinCostArborescence<Digraph, CostMap>::DualIt it(mca, i);
it != INVALID; ++it) {
dualSolution[i].second.insert(it);
}
}
for (ArcIt it(digraph); it != INVALID; ++it) {
if (mca.reached(digraph.source(it))) {
double sum = 0.0;
for (int i = 0; i < int(dualSolution.size()); ++i) {
if (dualSolution[i].second.find(digraph.target(it))
!= dualSolution[i].second.end() &&
dualSolution[i].second.find(digraph.source(it))
== dualSolution[i].second.end()) {
sum += dualSolution[i].first;
}
}
if (mca.arborescence(it)) {
check(sum == cost[it], "Invalid dual solution");
}
check(sum <= cost[it], "Invalid dual solution");
}
}
check(mca.dualValue() == mca.arborescenceCost(), "Invalid dual solution");
check(mca.reached(source), "Invalid arborescence");
for (ArcIt a(digraph); a != INVALID; ++a) {
check(!mca.reached(digraph.source(a)) ||
mca.reached(digraph.target(a)), "Invalid arborescence");
}
for (NodeIt n(digraph); n != INVALID; ++n) {
if (!mca.reached(n)) continue;
int cnt = 0;
for (InArcIt a(digraph, n); a != INVALID; ++a) {
if (mca.arborescence(a)) {
check(mca.pred(n) == a, "Invalid arborescence");
++cnt;
}
}
check((n == source ? cnt == 0 : cnt == 1), "Invalid arborescence");
}
Digraph::ArcMap<bool> arborescence(digraph);
check(mca.arborescenceCost() ==
minCostArborescence(digraph, cost, source, arborescence),
"Wrong result of the function interface");
return 0;
}

View File

@@ -0,0 +1,548 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <fstream>
#include <limits>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/network_simplex.h>
#include <lemon/capacity_scaling.h>
#include <lemon/cost_scaling.h>
#include <lemon/cycle_canceling.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/heap.h>
#include <lemon/concept_check.h>
#include "test_tools.h"
using namespace lemon;
// Test networks
char test_lgf[] =
"@nodes\n"
"label sup1 sup2 sup3 sup4 sup5 sup6\n"
" 1 20 27 0 30 20 30\n"
" 2 -4 0 0 0 -8 -3\n"
" 3 0 0 0 0 0 0\n"
" 4 0 0 0 0 0 0\n"
" 5 9 0 0 0 6 11\n"
" 6 -6 0 0 0 -5 -6\n"
" 7 0 0 0 0 0 0\n"
" 8 0 0 0 0 0 3\n"
" 9 3 0 0 0 0 0\n"
" 10 -2 0 0 0 -7 -2\n"
" 11 0 0 0 0 -10 0\n"
" 12 -20 -27 0 -30 -30 -20\n"
"\n"
"@arcs\n"
" cost cap low1 low2 low3\n"
" 1 2 70 11 0 8 8\n"
" 1 3 150 3 0 1 0\n"
" 1 4 80 15 0 2 2\n"
" 2 8 80 12 0 0 0\n"
" 3 5 140 5 0 3 1\n"
" 4 6 60 10 0 1 0\n"
" 4 7 80 2 0 0 0\n"
" 4 8 110 3 0 0 0\n"
" 5 7 60 14 0 0 0\n"
" 5 11 120 12 0 0 0\n"
" 6 3 0 3 0 0 0\n"
" 6 9 140 4 0 0 0\n"
" 6 10 90 8 0 0 0\n"
" 7 1 30 5 0 0 -5\n"
" 8 12 60 16 0 4 3\n"
" 9 12 50 6 0 0 0\n"
"10 12 70 13 0 5 2\n"
"10 2 100 7 0 0 0\n"
"10 7 60 10 0 0 -3\n"
"11 10 20 14 0 6 -20\n"
"12 11 30 10 0 0 -10\n"
"\n"
"@attributes\n"
"source 1\n"
"target 12\n";
char test_neg1_lgf[] =
"@nodes\n"
"label sup\n"
" 1 100\n"
" 2 0\n"
" 3 0\n"
" 4 -100\n"
" 5 0\n"
" 6 0\n"
" 7 0\n"
"@arcs\n"
" cost low1 low2\n"
"1 2 100 0 0\n"
"1 3 30 0 0\n"
"2 4 20 0 0\n"
"3 4 80 0 0\n"
"3 2 50 0 0\n"
"5 3 10 0 0\n"
"5 6 80 0 1000\n"
"6 7 30 0 -1000\n"
"7 5 -120 0 0\n";
char test_neg2_lgf[] =
"@nodes\n"
"label sup\n"
" 1 100\n"
" 2 -300\n"
"@arcs\n"
" cost\n"
"1 2 -1\n";
// Test data
typedef ListDigraph Digraph;
DIGRAPH_TYPEDEFS(ListDigraph);
Digraph gr;
Digraph::ArcMap<int> c(gr), l1(gr), l2(gr), l3(gr), u(gr);
Digraph::NodeMap<int> s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr);
ConstMap<Arc, int> cc(1), cu(std::numeric_limits<int>::max());
Node v, w;
Digraph neg1_gr;
Digraph::ArcMap<int> neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr);
ConstMap<Arc, int> neg1_u1(std::numeric_limits<int>::max()), neg1_u2(5000);
Digraph::NodeMap<int> neg1_s(neg1_gr);
Digraph neg2_gr;
Digraph::ArcMap<int> neg2_c(neg2_gr);
ConstMap<Arc, int> neg2_l(0), neg2_u(1000);
Digraph::NodeMap<int> neg2_s(neg2_gr);
enum SupplyType {
EQ,
GEQ,
LEQ
};
// Check the interface of an MCF algorithm
template <typename GR, typename Value, typename Cost>
class McfClassConcept
{
public:
template <typename MCF>
struct Constraints {
void constraints() {
checkConcept<concepts::Digraph, GR>();
const Constraints& me = *this;
MCF mcf(me.g);
const MCF& const_mcf = mcf;
b = mcf.reset().resetParams()
.lowerMap(me.lower)
.upperMap(me.upper)
.costMap(me.cost)
.supplyMap(me.sup)
.stSupply(me.n, me.n, me.k)
.run();
c = const_mcf.totalCost();
x = const_mcf.template totalCost<double>();
v = const_mcf.flow(me.a);
c = const_mcf.potential(me.n);
const_mcf.flowMap(fm);
const_mcf.potentialMap(pm);
}
typedef typename GR::Node Node;
typedef typename GR::Arc Arc;
typedef concepts::ReadMap<Node, Value> NM;
typedef concepts::ReadMap<Arc, Value> VAM;
typedef concepts::ReadMap<Arc, Cost> CAM;
typedef concepts::WriteMap<Arc, Value> FlowMap;
typedef concepts::WriteMap<Node, Cost> PotMap;
GR g;
VAM lower;
VAM upper;
CAM cost;
NM sup;
Node n;
Arc a;
Value k;
FlowMap fm;
PotMap pm;
bool b;
double x;
typename MCF::Value v;
typename MCF::Cost c;
};
};
// Check the feasibility of the given flow (primal soluiton)
template < typename GR, typename LM, typename UM,
typename SM, typename FM >
bool checkFlow( const GR& gr, const LM& lower, const UM& upper,
const SM& supply, const FM& flow,
SupplyType type = EQ )
{
TEMPLATE_DIGRAPH_TYPEDEFS(GR);
for (ArcIt e(gr); e != INVALID; ++e) {
if (flow[e] < lower[e] || flow[e] > upper[e]) return false;
}
for (NodeIt n(gr); n != INVALID; ++n) {
typename SM::Value sum = 0;
for (OutArcIt e(gr, n); e != INVALID; ++e)
sum += flow[e];
for (InArcIt e(gr, n); e != INVALID; ++e)
sum -= flow[e];
bool b = (type == EQ && sum == supply[n]) ||
(type == GEQ && sum >= supply[n]) ||
(type == LEQ && sum <= supply[n]);
if (!b) return false;
}
return true;
}
// Check the feasibility of the given potentials (dual soluiton)
// using the "Complementary Slackness" optimality condition
template < typename GR, typename LM, typename UM,
typename CM, typename SM, typename FM, typename PM >
bool checkPotential( const GR& gr, const LM& lower, const UM& upper,
const CM& cost, const SM& supply, const FM& flow,
const PM& pi, SupplyType type )
{
TEMPLATE_DIGRAPH_TYPEDEFS(GR);
bool opt = true;
for (ArcIt e(gr); opt && e != INVALID; ++e) {
typename CM::Value red_cost =
cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
opt = red_cost == 0 ||
(red_cost > 0 && flow[e] == lower[e]) ||
(red_cost < 0 && flow[e] == upper[e]);
}
for (NodeIt n(gr); opt && n != INVALID; ++n) {
typename SM::Value sum = 0;
for (OutArcIt e(gr, n); e != INVALID; ++e)
sum += flow[e];
for (InArcIt e(gr, n); e != INVALID; ++e)
sum -= flow[e];
if (type != LEQ) {
opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0);
} else {
opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0);
}
}
return opt;
}
// Check whether the dual cost is equal to the primal cost
template < typename GR, typename LM, typename UM,
typename CM, typename SM, typename PM >
bool checkDualCost( const GR& gr, const LM& lower, const UM& upper,
const CM& cost, const SM& supply, const PM& pi,
typename CM::Value total )
{
TEMPLATE_DIGRAPH_TYPEDEFS(GR);
typename CM::Value dual_cost = 0;
SM red_supply(gr);
for (NodeIt n(gr); n != INVALID; ++n) {
red_supply[n] = supply[n];
}
for (ArcIt a(gr); a != INVALID; ++a) {
if (lower[a] != 0) {
dual_cost += lower[a] * cost[a];
red_supply[gr.source(a)] -= lower[a];
red_supply[gr.target(a)] += lower[a];
}
}
for (NodeIt n(gr); n != INVALID; ++n) {
dual_cost -= red_supply[n] * pi[n];
}
for (ArcIt a(gr); a != INVALID; ++a) {
typename CM::Value red_cost =
cost[a] + pi[gr.source(a)] - pi[gr.target(a)];
dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0);
}
return dual_cost == total;
}
// Run a minimum cost flow algorithm and check the results
template < typename MCF, typename GR,
typename LM, typename UM,
typename CM, typename SM,
typename PT >
void checkMcf( const MCF& mcf, PT mcf_result,
const GR& gr, const LM& lower, const UM& upper,
const CM& cost, const SM& supply,
PT result, bool optimal, typename CM::Value total,
const std::string &test_id = "",
SupplyType type = EQ )
{
check(mcf_result == result, "Wrong result " + test_id);
if (optimal) {
typename GR::template ArcMap<typename SM::Value> flow(gr);
typename GR::template NodeMap<typename CM::Value> pi(gr);
mcf.flowMap(flow);
mcf.potentialMap(pi);
check(checkFlow(gr, lower, upper, supply, flow, type),
"The flow is not feasible " + test_id);
check(mcf.totalCost() == total, "The flow is not optimal " + test_id);
check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type),
"Wrong potentials " + test_id);
check(checkDualCost(gr, lower, upper, cost, supply, pi, total),
"Wrong dual cost " + test_id);
}
}
template < typename MCF, typename Param >
void runMcfGeqTests( Param param,
const std::string &test_str = "",
bool full_neg_cost_support = false )
{
MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr);
// Basic tests
mcf1.upperMap(u).costMap(c).supplyMap(s1);
checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1,
mcf1.OPTIMAL, true, 5240, test_str + "-1");
mcf1.stSupply(v, w, 27);
checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2,
mcf1.OPTIMAL, true, 7620, test_str + "-2");
mcf1.lowerMap(l2).supplyMap(s1);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1,
mcf1.OPTIMAL, true, 5970, test_str + "-3");
mcf1.stSupply(v, w, 27);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2,
mcf1.OPTIMAL, true, 8010, test_str + "-4");
mcf1.resetParams().supplyMap(s1);
checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1,
mcf1.OPTIMAL, true, 74, test_str + "-5");
mcf1.lowerMap(l2).stSupply(v, w, 27);
checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2,
mcf1.OPTIMAL, true, 94, test_str + "-6");
mcf1.reset();
checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3,
mcf1.OPTIMAL, true, 0, test_str + "-7");
mcf1.lowerMap(l2).upperMap(u);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3,
mcf1.INFEASIBLE, false, 0, test_str + "-8");
mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4);
checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4,
mcf1.OPTIMAL, true, 6360, test_str + "-9");
// Tests for the GEQ form
mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5);
checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5,
mcf1.OPTIMAL, true, 3530, test_str + "-10", GEQ);
mcf1.lowerMap(l2);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
mcf1.OPTIMAL, true, 4540, test_str + "-11", GEQ);
mcf1.supplyMap(s6);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
mcf1.INFEASIBLE, false, 0, test_str + "-12", GEQ);
// Tests with negative costs
mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s);
checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s,
mcf2.UNBOUNDED, false, 0, test_str + "-13");
mcf2.upperMap(neg1_u2);
checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s,
mcf2.OPTIMAL, true, -40000, test_str + "-14");
mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s);
checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s,
mcf2.UNBOUNDED, false, 0, test_str + "-15");
mcf3.costMap(neg2_c).supplyMap(neg2_s);
if (full_neg_cost_support) {
checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
mcf3.OPTIMAL, true, -300, test_str + "-16", GEQ);
} else {
checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
mcf3.UNBOUNDED, false, 0, test_str + "-17", GEQ);
}
mcf3.upperMap(neg2_u);
checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s,
mcf3.OPTIMAL, true, -300, test_str + "-18", GEQ);
// Tests for empty graph
Digraph gr0;
MCF mcf0(gr0);
mcf0.run(param);
check(mcf0.totalCost() == 0, "Wrong total cost");
}
template < typename MCF, typename Param >
void runMcfLeqTests( Param param,
const std::string &test_str = "" )
{
// Tests for the LEQ form
MCF mcf1(gr);
mcf1.supplyType(mcf1.LEQ);
mcf1.upperMap(u).costMap(c).supplyMap(s6);
checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6,
mcf1.OPTIMAL, true, 5080, test_str + "-19", LEQ);
mcf1.lowerMap(l2);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6,
mcf1.OPTIMAL, true, 5930, test_str + "-20", LEQ);
mcf1.supplyMap(s5);
checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5,
mcf1.INFEASIBLE, false, 0, test_str + "-21", LEQ);
}
int main()
{
// Read the test networks
std::istringstream input(test_lgf);
DigraphReader<Digraph>(gr, input)
.arcMap("cost", c)
.arcMap("cap", u)
.arcMap("low1", l1)
.arcMap("low2", l2)
.arcMap("low3", l3)
.nodeMap("sup1", s1)
.nodeMap("sup2", s2)
.nodeMap("sup3", s3)
.nodeMap("sup4", s4)
.nodeMap("sup5", s5)
.nodeMap("sup6", s6)
.node("source", v)
.node("target", w)
.run();
std::istringstream neg_inp1(test_neg1_lgf);
DigraphReader<Digraph>(neg1_gr, neg_inp1)
.arcMap("cost", neg1_c)
.arcMap("low1", neg1_l1)
.arcMap("low2", neg1_l2)
.nodeMap("sup", neg1_s)
.run();
std::istringstream neg_inp2(test_neg2_lgf);
DigraphReader<Digraph>(neg2_gr, neg_inp2)
.arcMap("cost", neg2_c)
.nodeMap("sup", neg2_s)
.run();
// Check the interface of NetworkSimplex
{
typedef concepts::Digraph GR;
checkConcept< McfClassConcept<GR, int, int>,
NetworkSimplex<GR> >();
checkConcept< McfClassConcept<GR, double, double>,
NetworkSimplex<GR, double> >();
checkConcept< McfClassConcept<GR, int, double>,
NetworkSimplex<GR, int, double> >();
}
// Check the interface of CapacityScaling
{
typedef concepts::Digraph GR;
checkConcept< McfClassConcept<GR, int, int>,
CapacityScaling<GR> >();
checkConcept< McfClassConcept<GR, double, double>,
CapacityScaling<GR, double> >();
checkConcept< McfClassConcept<GR, int, double>,
CapacityScaling<GR, int, double> >();
typedef CapacityScaling<GR>::
SetHeap<concepts::Heap<int, RangeMap<int> > >::Create CAS;
checkConcept< McfClassConcept<GR, int, int>, CAS >();
}
// Check the interface of CostScaling
{
typedef concepts::Digraph GR;
checkConcept< McfClassConcept<GR, int, int>,
CostScaling<GR> >();
checkConcept< McfClassConcept<GR, double, double>,
CostScaling<GR, double> >();
checkConcept< McfClassConcept<GR, int, double>,
CostScaling<GR, int, double> >();
typedef CostScaling<GR>::
SetLargeCost<double>::Create COS;
checkConcept< McfClassConcept<GR, int, int>, COS >();
}
// Check the interface of CycleCanceling
{
typedef concepts::Digraph GR;
checkConcept< McfClassConcept<GR, int, int>,
CycleCanceling<GR> >();
checkConcept< McfClassConcept<GR, double, double>,
CycleCanceling<GR, double> >();
checkConcept< McfClassConcept<GR, int, double>,
CycleCanceling<GR, int, double> >();
}
// Test NetworkSimplex
{
typedef NetworkSimplex<Digraph> MCF;
runMcfGeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE", true);
runMcfLeqTests<MCF>(MCF::FIRST_ELIGIBLE, "NS-FE");
runMcfGeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE", true);
runMcfLeqTests<MCF>(MCF::BEST_ELIGIBLE, "NS-BE");
runMcfGeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS", true);
runMcfLeqTests<MCF>(MCF::BLOCK_SEARCH, "NS-BS");
runMcfGeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL", true);
runMcfLeqTests<MCF>(MCF::CANDIDATE_LIST, "NS-CL");
runMcfGeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL", true);
runMcfLeqTests<MCF>(MCF::ALTERING_LIST, "NS-AL");
}
// Test CapacityScaling
{
typedef CapacityScaling<Digraph> MCF;
runMcfGeqTests<MCF>(0, "SSP");
runMcfGeqTests<MCF>(2, "CAS");
}
// Test CostScaling
{
typedef CostScaling<Digraph> MCF;
runMcfGeqTests<MCF>(MCF::PUSH, "COS-PR");
runMcfGeqTests<MCF>(MCF::AUGMENT, "COS-AR");
runMcfGeqTests<MCF>(MCF::PARTIAL_AUGMENT, "COS-PAR");
}
// Test CycleCanceling
{
typedef CycleCanceling<Digraph> MCF;
runMcfGeqTests<MCF>(MCF::SIMPLE_CYCLE_CANCELING, "SCC");
runMcfGeqTests<MCF>(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC");
runMcfGeqTests<MCF>(MCF::CANCEL_AND_TIGHTEN, "CAT");
}
return 0;
}

View File

@@ -0,0 +1,223 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <sstream>
#include <lemon/smart_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/path.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concept_check.h>
#include <lemon/karp_mmc.h>
#include <lemon/hartmann_orlin_mmc.h>
#include <lemon/howard_mmc.h>
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"@arcs\n"
" len1 len2 len3 len4 c1 c2 c3 c4\n"
"1 2 1 1 1 1 0 0 0 0\n"
"2 4 5 5 5 5 1 0 0 0\n"
"2 3 8 8 8 8 0 0 0 0\n"
"3 2 -2 0 0 0 1 0 0 0\n"
"3 4 4 4 4 4 0 0 0 0\n"
"3 7 -4 -4 -4 -4 0 0 0 0\n"
"4 1 2 2 2 2 0 0 0 0\n"
"4 3 3 3 3 3 1 0 0 0\n"
"4 4 3 3 0 0 0 0 1 0\n"
"5 2 4 4 4 4 0 0 0 0\n"
"5 6 3 3 3 3 0 1 0 0\n"
"6 5 2 2 2 2 0 1 0 0\n"
"6 4 -1 -1 -1 -1 0 0 0 0\n"
"6 7 1 1 1 1 0 0 0 0\n"
"7 7 4 4 4 -1 0 0 0 1\n";
// Check the interface of an MMC algorithm
template <typename GR, typename Cost>
struct MmcClassConcept
{
template <typename MMC>
struct Constraints {
void constraints() {
const Constraints& me = *this;
typedef typename MMC
::template SetPath<ListPath<GR> >
::template SetLargeCost<Cost>
::Create MmcAlg;
MmcAlg mmc(me.g, me.cost);
const MmcAlg& const_mmc = mmc;
typename MmcAlg::Tolerance tol = const_mmc.tolerance();
mmc.tolerance(tol);
b = mmc.cycle(p).run();
b = mmc.findCycleMean();
b = mmc.findCycle();
v = const_mmc.cycleCost();
i = const_mmc.cycleSize();
d = const_mmc.cycleMean();
p = const_mmc.cycle();
}
typedef concepts::ReadMap<typename GR::Arc, Cost> CM;
GR g;
CM cost;
ListPath<GR> p;
Cost v;
int i;
double d;
bool b;
};
};
// Perform a test with the given parameters
template <typename MMC>
void checkMmcAlg(const SmartDigraph& gr,
const SmartDigraph::ArcMap<int>& lm,
const SmartDigraph::ArcMap<int>& cm,
int cost, int size) {
MMC alg(gr, lm);
check(alg.findCycleMean(), "Wrong result");
check(alg.cycleMean() == static_cast<double>(cost) / size,
"Wrong cycle mean");
alg.findCycle();
check(alg.cycleCost() == cost && alg.cycleSize() == size,
"Wrong path");
SmartDigraph::ArcMap<int> cycle(gr, 0);
for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) {
++cycle[a];
}
for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) {
check(cm[a] == cycle[a], "Wrong path");
}
}
// Class for comparing types
template <typename T1, typename T2>
struct IsSameType {
static const int result = 0;
};
template <typename T>
struct IsSameType<T,T> {
static const int result = 1;
};
int main() {
#ifdef LEMON_HAVE_LONG_LONG
typedef long long long_int;
#else
typedef long long_int;
#endif
// Check the interface
{
typedef concepts::Digraph GR;
// KarpMmc
checkConcept< MmcClassConcept<GR, int>,
KarpMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
checkConcept< MmcClassConcept<GR, float>,
KarpMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
// HartmannOrlinMmc
checkConcept< MmcClassConcept<GR, int>,
HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
checkConcept< MmcClassConcept<GR, float>,
HartmannOrlinMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
// HowardMmc
checkConcept< MmcClassConcept<GR, int>,
HowardMmc<GR, concepts::ReadMap<GR::Arc, int> > >();
checkConcept< MmcClassConcept<GR, float>,
HowardMmc<GR, concepts::ReadMap<GR::Arc, float> > >();
check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, int> >
::LargeCost, long_int>::result == 1), "Wrong LargeCost type");
check((IsSameType<HowardMmc<GR, concepts::ReadMap<GR::Arc, float> >
::LargeCost, double>::result == 1), "Wrong LargeCost type");
}
// Run various tests
{
typedef SmartDigraph GR;
DIGRAPH_TYPEDEFS(GR);
GR gr;
IntArcMap l1(gr), l2(gr), l3(gr), l4(gr);
IntArcMap c1(gr), c2(gr), c3(gr), c4(gr);
std::istringstream input(test_lgf);
digraphReader(gr, input).
arcMap("len1", l1).
arcMap("len2", l2).
arcMap("len3", l3).
arcMap("len4", l4).
arcMap("c1", c1).
arcMap("c2", c2).
arcMap("c3", c3).
arcMap("c4", c4).
run();
// Karp
checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
checkMmcAlg<KarpMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
// HartmannOrlin
checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
checkMmcAlg<HartmannOrlinMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
// Howard
checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l1, c1, 6, 3);
checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l2, c2, 5, 2);
checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l3, c3, 0, 1);
checkMmcAlg<HowardMmc<GR, IntArcMap> >(gr, l4, c4, -1, 1);
// Howard with iteration limit
HowardMmc<GR, IntArcMap> mmc(gr, l1);
check((mmc.findCycleMean(2) == HowardMmc<GR, IntArcMap>::ITERATION_LIMIT),
"Wrong termination cause");
check((mmc.findCycleMean(4) == HowardMmc<GR, IntArcMap>::OPTIMAL),
"Wrong termination cause");
}
return 0;
}

View File

@@ -0,0 +1,171 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include "test_tools.h"
#include <lemon/config.h>
#ifdef LEMON_HAVE_CPLEX
#include <lemon/cplex.h>
#endif
#ifdef LEMON_HAVE_GLPK
#include <lemon/glpk.h>
#endif
#ifdef LEMON_HAVE_CBC
#include <lemon/cbc.h>
#endif
#ifdef LEMON_HAVE_MIP
#include <lemon/lp.h>
#endif
using namespace lemon;
void solveAndCheck(MipSolver& mip, MipSolver::ProblemType stat,
double exp_opt) {
using std::string;
mip.solve();
//int decimal,sign;
std::ostringstream buf;
buf << "Type should be: " << int(stat)<<" and it is "<<int(mip.type());
// itoa(stat,buf1, 10);
check(mip.type()==stat, buf.str());
if (stat == MipSolver::OPTIMAL) {
std::ostringstream sbuf;
sbuf << "Wrong optimal value ("<< mip.solValue()
<<" instead of " << exp_opt << ")";
check(std::abs(mip.solValue()-exp_opt) < 1e-3, sbuf.str());
//+ecvt(exp_opt,2)
}
}
void aTest(MipSolver& mip)
{
//The following example is very simple
typedef MipSolver::Row Row;
typedef MipSolver::Col Col;
Col x1 = mip.addCol();
Col x2 = mip.addCol();
//Objective function
mip.obj(x1);
mip.max();
//Unconstrained optimization
mip.solve();
//Check it out!
//Constraints
mip.addRow(2 * x1 + x2 <= 2);
Row y2 = mip.addRow(x1 - 2 * x2 <= 0);
//Nonnegativity of the variable x1
mip.colLowerBound(x1, 0);
//Maximization of x1
//over the triangle with vertices (0,0),(4/5,2/5),(0,2)
double expected_opt=4.0/5.0;
solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
//Restrict x2 to integer
mip.colType(x2,MipSolver::INTEGER);
expected_opt=1.0/2.0;
solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
//Restrict both to integer
mip.colType(x1,MipSolver::INTEGER);
expected_opt=0;
solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
//Erase a variable
mip.erase(x2);
mip.rowUpperBound(y2, 8);
expected_opt=1;
solveAndCheck(mip, MipSolver::OPTIMAL, expected_opt);
}
template<class MIP>
void cloneTest()
{
MIP* mip = new MIP();
MIP* mipnew = mip->newSolver();
MIP* mipclone = mip->cloneSolver();
delete mip;
delete mipnew;
delete mipclone;
}
int main()
{
#ifdef LEMON_HAVE_MIP
{
Mip mip1;
aTest(mip1);
cloneTest<Mip>();
}
#endif
#ifdef LEMON_HAVE_GLPK
{
GlpkMip mip1;
aTest(mip1);
cloneTest<GlpkMip>();
}
#endif
#ifdef LEMON_HAVE_CPLEX
try {
CplexMip mip2;
aTest(mip2);
cloneTest<CplexMip>();
} catch (CplexEnv::LicenseError& error) {
check(false, error.what());
}
#endif
#ifdef LEMON_HAVE_CBC
{
CbcMip mip1;
aTest(mip1);
cloneTest<CbcMip>();
}
#endif
return 0;
}

View File

@@ -0,0 +1,142 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <sstream>
#include <lemon/smart_graph.h>
#include <lemon/adaptors.h>
#include <lemon/concepts/graph.h>
#include <lemon/concepts/maps.h>
#include <lemon/lgf_reader.h>
#include <lemon/nagamochi_ibaraki.h>
#include "test_tools.h"
using namespace lemon;
using namespace std;
const std::string lgf =
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@edges\n"
" cap1 cap2 cap3\n"
"0 1 1 1 1 \n"
"0 2 2 2 4 \n"
"1 2 4 4 4 \n"
"3 4 1 1 1 \n"
"3 5 2 2 4 \n"
"4 5 4 4 4 \n"
"2 3 1 6 6 \n";
void checkNagamochiIbarakiCompile()
{
typedef int Value;
typedef concepts::Graph Graph;
typedef Graph::Node Node;
typedef Graph::Edge Edge;
typedef concepts::ReadMap<Edge, Value> CapMap;
typedef concepts::WriteMap<Node, bool> CutMap;
Graph g;
Node n;
CapMap cap;
CutMap cut;
Value v;
bool b;
::lemon::ignore_unused_variable_warning(v,b);
NagamochiIbaraki<Graph, CapMap> ni_test(g, cap);
const NagamochiIbaraki<Graph, CapMap>& const_ni_test = ni_test;
ni_test.init();
ni_test.start();
b = ni_test.processNextPhase();
ni_test.run();
v = const_ni_test.minCutValue();
v = const_ni_test.minCutMap(cut);
}
template <typename Graph, typename CapMap, typename CutMap>
typename CapMap::Value
cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut)
{
typename CapMap::Value sum = 0;
for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) {
if (cut[graph.u(e)] != cut[graph.v(e)]) {
sum += cap[e];
}
}
return sum;
}
int main() {
SmartGraph graph;
SmartGraph::EdgeMap<int> cap1(graph), cap2(graph), cap3(graph);
SmartGraph::NodeMap<bool> cut(graph);
istringstream input(lgf);
graphReader(graph, input)
.edgeMap("cap1", cap1)
.edgeMap("cap2", cap2)
.edgeMap("cap3", cap3)
.run();
{
NagamochiIbaraki<SmartGraph> ni(graph, cap1);
ni.run();
ni.minCutMap(cut);
check(ni.minCutValue() == 1, "Wrong cut value");
check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value");
}
{
NagamochiIbaraki<SmartGraph> ni(graph, cap2);
ni.run();
ni.minCutMap(cut);
check(ni.minCutValue() == 3, "Wrong cut value");
check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value");
}
{
NagamochiIbaraki<SmartGraph> ni(graph, cap3);
ni.run();
ni.minCutMap(cut);
check(ni.minCutValue() == 5, "Wrong cut value");
check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value");
}
{
NagamochiIbaraki<SmartGraph>::SetUnitCapacity::Create ni(graph);
ni.run();
ni.minCutMap(cut);
ConstMap<SmartGraph::Edge, int> cap4(1);
check(ni.minCutValue() == 1, "Wrong cut value");
check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value");
}
return 0;
}

View File

@@ -0,0 +1,339 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <string>
#include <iostream>
#include <lemon/concepts/path.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concept_check.h>
#include <lemon/path.h>
#include <lemon/list_graph.h>
#include "test_tools.h"
using namespace std;
using namespace lemon;
template <typename GR>
void checkConcepts() {
checkConcept<concepts::Path<GR>, concepts::Path<GR> >();
checkConcept<concepts::Path<GR>, Path<GR> >();
checkConcept<concepts::Path<GR>, SimplePath<GR> >();
checkConcept<concepts::Path<GR>, StaticPath<GR> >();
checkConcept<concepts::Path<GR>, ListPath<GR> >();
}
// Conecpt checking for path structures
void checkPathConcepts() {
checkConcepts<concepts::Digraph>();
checkConcepts<ListDigraph>();
}
// Check if proper copy consructor is called (use valgrind for testing)
template <typename GR, typename P1, typename P2>
void checkCopy(typename GR::Arc a) {
P1 p;
p.addBack(a);
P1 q;
q = p;
P1 r(p);
P2 q2;
q2 = p;
P2 r2(p);
}
// Tests for copy constructors and assignment operators of paths
void checkPathCopy() {
ListDigraph g;
ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode());
typedef Path<ListDigraph> Path1;
typedef SimplePath<ListDigraph> Path2;
typedef ListPath<ListDigraph> Path3;
typedef StaticPath<ListDigraph> Path4;
checkCopy<ListDigraph, Path1, Path2>(a);
checkCopy<ListDigraph, Path1, Path3>(a);
checkCopy<ListDigraph, Path1, Path4>(a);
checkCopy<ListDigraph, Path2, Path1>(a);
checkCopy<ListDigraph, Path2, Path3>(a);
checkCopy<ListDigraph, Path2, Path4>(a);
checkCopy<ListDigraph, Path3, Path1>(a);
checkCopy<ListDigraph, Path3, Path2>(a);
checkCopy<ListDigraph, Path3, Path4>(a);
}
// Class for testing path functions
class CheckPathFunctions {
typedef ListDigraph GR;
DIGRAPH_TYPEDEFS(GR);
GR gr;
const GR& cgr;
Node n1, n2, n3, n4;
Node tmp_n;
Arc a1, a2, a3, a4;
Arc tmp_a;
public:
CheckPathFunctions() : cgr(gr) {
n1 = gr.addNode();
n2 = gr.addNode();
n3 = gr.addNode();
n4 = gr.addNode();
a1 = gr.addArc(n1, n2);
a2 = gr.addArc(n2, n3);
a3 = gr.addArc(n3, n4);
a4 = gr.addArc(n4, n1);
}
void run() {
checkBackAndFrontInsertablePath<Path<GR> >();
checkBackAndFrontInsertablePath<ListPath<GR> >();
checkBackInsertablePath<SimplePath<GR> >();
checkListPathSplitAndSplice();
}
private:
template <typename P>
void checkBackInsertablePath() {
// Create and check empty path
P p;
const P& cp = p;
check(cp.empty(), "The path is not empty");
check(cp.length() == 0, "The path is not empty");
// check(cp.front() == INVALID, "Wrong front()");
// check(cp.back() == INVALID, "Wrong back()");
typename P::ArcIt ai(cp);
check(ai == INVALID, "Wrong ArcIt");
check(pathSource(cgr, cp) == INVALID, "Wrong pathSource()");
check(pathTarget(cgr, cp) == INVALID, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
PathNodeIt<P> ni(cgr, cp);
check(ni == INVALID, "Wrong PathNodeIt");
// Check single-arc path
p.addBack(a1);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 1, "Wrong length");
check(cp.front() == a1, "Wrong front()");
check(cp.back() == a1, "Wrong back()");
check(cp.nth(0) == a1, "Wrong nth()");
ai = cp.nthIt(0);
check((tmp_a = ai) == a1, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
typename P::ArcIt ai2(cp);
check((tmp_a = ai2) == a1, "Wrong ArcIt");
check(++ai2 == INVALID, "Wrong ArcIt");
check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
PathNodeIt<P> ni2(cgr, cp);
check((tmp_n = ni2) == n1, "Wrong PathNodeIt");
check((tmp_n = ++ni2) == n2, "Wrong PathNodeIt");
check(++ni2 == INVALID, "Wrong PathNodeIt");
// Check adding more arcs
p.addBack(a2);
p.addBack(a3);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 3, "Wrong length");
check(cp.front() == a1, "Wrong front()");
check(cp.back() == a3, "Wrong back()");
check(cp.nth(0) == a1, "Wrong nth()");
check(cp.nth(1) == a2, "Wrong nth()");
check(cp.nth(2) == a3, "Wrong nth()");
typename P::ArcIt ai3(cp);
check((tmp_a = ai3) == a1, "Wrong ArcIt");
check((tmp_a = ++ai3) == a2, "Wrong nthIt()");
check((tmp_a = ++ai3) == a3, "Wrong nthIt()");
check(++ai3 == INVALID, "Wrong nthIt()");
ai = cp.nthIt(0);
check((tmp_a = ai) == a1, "Wrong nthIt()");
check((tmp_a = ++ai) == a2, "Wrong nthIt()");
ai = cp.nthIt(2);
check((tmp_a = ai) == a3, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n4, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
PathNodeIt<P> ni3(cgr, cp);
check((tmp_n = ni3) == n1, "Wrong PathNodeIt");
check((tmp_n = ++ni3) == n2, "Wrong PathNodeIt");
check((tmp_n = ++ni3) == n3, "Wrong PathNodeIt");
check((tmp_n = ++ni3) == n4, "Wrong PathNodeIt");
check(++ni3 == INVALID, "Wrong PathNodeIt");
// Check arc removal and addition
p.eraseBack();
p.eraseBack();
p.addBack(a2);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 2, "Wrong length");
check(cp.front() == a1, "Wrong front()");
check(cp.back() == a2, "Wrong back()");
check(pathSource(cgr, cp) == n1, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
// Check clear()
p.clear();
check(cp.empty(), "The path is not empty");
check(cp.length() == 0, "The path is not empty");
// Check inconsistent path
p.addBack(a4);
p.addBack(a2);
p.addBack(a1);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 3, "Wrong length");
check(cp.front() == a4, "Wrong front()");
check(cp.back() == a1, "Wrong back()");
check(pathSource(cgr, cp) == n4, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
check(!checkPath(cgr, cp), "Wrong checkPath()");
}
template <typename P>
void checkBackAndFrontInsertablePath() {
// Include back insertable test cases
checkBackInsertablePath<P>();
// Check front and back insertion
P p;
const P& cp = p;
p.addFront(a4);
p.addBack(a1);
p.addFront(a3);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 3, "Wrong length");
check(cp.front() == a3, "Wrong front()");
check(cp.back() == a1, "Wrong back()");
check(cp.nth(0) == a3, "Wrong nth()");
check(cp.nth(1) == a4, "Wrong nth()");
check(cp.nth(2) == a1, "Wrong nth()");
typename P::ArcIt ai(cp);
check((tmp_a = ai) == a3, "Wrong ArcIt");
check((tmp_a = ++ai) == a4, "Wrong nthIt()");
check((tmp_a = ++ai) == a1, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
ai = cp.nthIt(0);
check((tmp_a = ai) == a3, "Wrong nthIt()");
check((tmp_a = ++ai) == a4, "Wrong nthIt()");
ai = cp.nthIt(2);
check((tmp_a = ai) == a1, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(pathSource(cgr, cp) == n3, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
// Check eraseFront()
p.eraseFront();
p.addBack(a2);
check(!cp.empty(), "Wrong empty()");
check(cp.length() == 3, "Wrong length");
check(cp.front() == a4, "Wrong front()");
check(cp.back() == a2, "Wrong back()");
check(cp.nth(0) == a4, "Wrong nth()");
check(cp.nth(1) == a1, "Wrong nth()");
check(cp.nth(2) == a2, "Wrong nth()");
typename P::ArcIt ai2(cp);
check((tmp_a = ai2) == a4, "Wrong ArcIt");
check((tmp_a = ++ai2) == a1, "Wrong nthIt()");
check((tmp_a = ++ai2) == a2, "Wrong nthIt()");
check(++ai2 == INVALID, "Wrong nthIt()");
ai = cp.nthIt(0);
check((tmp_a = ai) == a4, "Wrong nthIt()");
check((tmp_a = ++ai) == a1, "Wrong nthIt()");
ai = cp.nthIt(2);
check((tmp_a = ai) == a2, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(pathSource(cgr, cp) == n4, "Wrong pathSource()");
check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()");
check(checkPath(cgr, cp), "Wrong checkPath()");
}
void checkListPathSplitAndSplice() {
// Build a path with spliceFront() and spliceBack()
ListPath<GR> p1, p2, p3, p4;
p1.addBack(a3);
p1.addFront(a2);
p2.addBack(a1);
p1.spliceFront(p2);
p3.addFront(a4);
p1.spliceBack(p3);
check(p1.length() == 4, "Wrong length");
check(p1.front() == a1, "Wrong front()");
check(p1.back() == a4, "Wrong back()");
ListPath<GR>::ArcIt ai(p1);
check((tmp_a = ai) == a1, "Wrong ArcIt");
check((tmp_a = ++ai) == a2, "Wrong nthIt()");
check((tmp_a = ++ai) == a3, "Wrong nthIt()");
check((tmp_a = ++ai) == a4, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(checkPath(cgr, p1), "Wrong checkPath()");
// Check split()
p1.split(p1.nthIt(2), p2);
check(p1.length() == 2, "Wrong length");
ai = p1.nthIt(0);
check((tmp_a = ai) == a1, "Wrong ArcIt");
check((tmp_a = ++ai) == a2, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(checkPath(cgr, p1), "Wrong checkPath()");
check(p2.length() == 2, "Wrong length");
ai = p2.nthIt(0);
check((tmp_a = ai) == a3, "Wrong ArcIt");
check((tmp_a = ++ai) == a4, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(checkPath(cgr, p2), "Wrong checkPath()");
// Check split() and splice()
p1.spliceFront(p2);
p1.split(p1.nthIt(2), p2);
p2.split(p2.nthIt(1), p3);
p2.spliceBack(p1);
p2.splice(p2.nthIt(1), p3);
check(p2.length() == 4, "Wrong length");
check(p2.front() == a1, "Wrong front()");
check(p2.back() == a4, "Wrong back()");
ai = p2.nthIt(0);
check((tmp_a = ai) == a1, "Wrong ArcIt");
check((tmp_a = ++ai) == a2, "Wrong nthIt()");
check((tmp_a = ++ai) == a3, "Wrong nthIt()");
check((tmp_a = ++ai) == a4, "Wrong nthIt()");
check(++ai == INVALID, "Wrong nthIt()");
check(checkPath(cgr, p2), "Wrong checkPath()");
}
};
int main() {
checkPathConcepts();
checkPathCopy();
CheckPathFunctions cpf;
cpf.run();
return 0;
}

View File

@@ -0,0 +1,262 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <lemon/planarity.h>
#include <lemon/smart_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/connectivity.h>
#include <lemon/dim2.h>
#include "test_tools.h"
using namespace lemon;
using namespace lemon::dim2;
const int lgfn = 4;
const std::string lgf[lgfn] = {
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"@edges\n"
" label\n"
"0 1 0\n"
"0 2 0\n"
"0 3 0\n"
"0 4 0\n"
"1 2 0\n"
"1 3 0\n"
"1 4 0\n"
"2 3 0\n"
"2 4 0\n"
"3 4 0\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"@edges\n"
" label\n"
"0 1 0\n"
"0 2 0\n"
"0 3 0\n"
"0 4 0\n"
"1 2 0\n"
"1 3 0\n"
"2 3 0\n"
"2 4 0\n"
"3 4 0\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@edges\n"
" label\n"
"0 3 0\n"
"0 4 0\n"
"0 5 0\n"
"1 3 0\n"
"1 4 0\n"
"1 5 0\n"
"2 3 0\n"
"2 4 0\n"
"2 5 0\n",
"@nodes\n"
"label\n"
"0\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"@edges\n"
" label\n"
"0 3 0\n"
"0 4 0\n"
"0 5 0\n"
"1 3 0\n"
"1 4 0\n"
"1 5 0\n"
"2 3 0\n"
"2 5 0\n"
};
typedef SmartGraph Graph;
GRAPH_TYPEDEFS(Graph);
typedef PlanarEmbedding<SmartGraph> PE;
typedef PlanarDrawing<SmartGraph> PD;
typedef PlanarColoring<SmartGraph> PC;
void checkEmbedding(const Graph& graph, PE& pe) {
int face_num = 0;
Graph::ArcMap<int> face(graph, -1);
for (ArcIt a(graph); a != INVALID; ++a) {
if (face[a] == -1) {
Arc b = a;
while (face[b] == -1) {
face[b] = face_num;
b = pe.next(graph.oppositeArc(b));
}
check(face[b] == face_num, "Wrong face");
++face_num;
}
}
check(face_num + countNodes(graph) - countConnectedComponents(graph) ==
countEdges(graph) + 1, "Euler test does not passed");
}
void checkKuratowski(const Graph& graph, PE& pe) {
std::map<int, int> degs;
for (NodeIt n(graph); n != INVALID; ++n) {
int deg = 0;
for (IncEdgeIt e(graph, n); e != INVALID; ++e) {
if (pe.kuratowski(e)) {
++deg;
}
}
++degs[deg];
}
for (std::map<int, int>::iterator it = degs.begin(); it != degs.end(); ++it) {
check(it->first == 0 || it->first == 2 ||
(it->first == 3 && it->second == 6) ||
(it->first == 4 && it->second == 5),
"Wrong degree in Kuratowski graph");
}
// Not full test
check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph");
}
bool intersect(Point<int> e1, Point<int> e2, Point<int> f1, Point<int> f2) {
int l, r;
if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false;
if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false;
if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false;
if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false;
l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x);
r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x);
if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x);
r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x);
if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
return true;
}
bool collinear(Point<int> p, Point<int> q, Point<int> r) {
int v;
v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
if (v != 0) return false;
v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y);
if (v < 0) return false;
return true;
}
void checkDrawing(const Graph& graph, PD& pd) {
for (Graph::NodeIt n(graph); n != INVALID; ++n) {
Graph::NodeIt m(n);
for (++m; m != INVALID; ++m) {
check(pd[m] != pd[n], "Two nodes with identical coordinates");
}
}
for (Graph::EdgeIt e(graph); e != INVALID; ++e) {
for (Graph::EdgeIt f(e); f != e; ++f) {
Point<int> e1 = pd[graph.u(e)];
Point<int> e2 = pd[graph.v(e)];
Point<int> f1 = pd[graph.u(f)];
Point<int> f2 = pd[graph.v(f)];
if (graph.u(e) == graph.u(f)) {
check(!collinear(e1, e2, f2), "Wrong drawing");
} else if (graph.u(e) == graph.v(f)) {
check(!collinear(e1, e2, f1), "Wrong drawing");
} else if (graph.v(e) == graph.u(f)) {
check(!collinear(e2, e1, f2), "Wrong drawing");
} else if (graph.v(e) == graph.v(f)) {
check(!collinear(e2, e1, f1), "Wrong drawing");
} else {
check(!intersect(e1, e2, f1, f2), "Wrong drawing");
}
}
}
}
void checkColoring(const Graph& graph, PC& pc, int num) {
for (NodeIt n(graph); n != INVALID; ++n) {
check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num,
"Wrong coloring");
}
for (EdgeIt e(graph); e != INVALID; ++e) {
check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)),
"Wrong coloring");
}
}
int main() {
for (int i = 0; i < lgfn; ++i) {
std::istringstream lgfs(lgf[i]);
SmartGraph graph;
graphReader(graph, lgfs).run();
check(simpleGraph(graph), "Test graphs must be simple");
PE pe(graph);
bool planar = pe.run();
check(checkPlanarity(graph) == planar, "Planarity checking failed");
if (planar) {
checkEmbedding(graph, pe);
PlanarDrawing<Graph> pd(graph);
pd.run(pe.embeddingMap());
checkDrawing(graph, pd);
PlanarColoring<Graph> pc(graph);
pc.runFiveColoring(pe.embeddingMap());
checkColoring(graph, pc, 5);
} else {
checkKuratowski(graph, pe);
}
}
return 0;
}

View File

@@ -0,0 +1,266 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/time_measure.h>
#include <lemon/smart_graph.h>
#include <lemon/maps.h>
#include <lemon/radix_sort.h>
#include <lemon/math.h>
#include "test_tools.h"
#include <vector>
#include <list>
#include <algorithm>
using namespace lemon;
static const int n = 10000;
struct Negate {
typedef int argument_type;
typedef int result_type;
int operator()(int a) { return - a; }
};
int negate(int a) { return - a; }
template<class T>
bool isTheSame(T &a, T&b)
{
typename T::iterator ai=a.begin();
typename T::iterator bi=b.begin();
for(;ai!=a.end()||bi!=b.end();++ai,++bi)
if(*ai!=*bi) return false;
return ai==a.end()&&bi==b.end();
}
template<class T>
T listsort(typename T::iterator b, typename T::iterator e)
{
if(b==e) return T();
typename T::iterator bn=b;
if(++bn==e) {
T l;
l.push_back(*b);
return l;
}
typename T::iterator m=b;
bool x=false;
for(typename T::iterator i=b;i!=e;++i,x=!x)
if(x) ++m;
T l1(listsort<T>(b,m));
T l2(listsort<T>(m,e));
T l;
while((!l1.empty())&&(!l2.empty()))
if(l1.front()<=l2.front())
{
l.push_back(l1.front());
l1.pop_front();
}
else {
l.push_back(l2.front());
l2.pop_front();
}
while(!l1.empty())
{
l.push_back(l1.front());
l1.pop_front();
}
while(!l2.empty())
{
l.push_back(l2.front());
l2.pop_front();
}
return l;
}
template<class T>
void generateIntSequence(int n, T & data) {
int prime = 9973;
int root = 136, value = 1;
for (int i = 0; i < n; ++i) {
data.push_back(value - prime / 2);
value = (value * root) % prime;
}
}
template<class T>
void generateCharSequence(int n, T & data) {
int prime = 251;
int root = 3, value = root;
for (int i = 0; i < n; ++i) {
data.push_back(static_cast<unsigned char>(value));
value = (value * root) % prime;
}
}
void checkRadixSort() {
{
std::vector<int> data1;
generateIntSequence(n, data1);
std::vector<int> data2(data1);
std::sort(data1.begin(), data1.end());
radixSort(data2.begin(), data2.end());
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[i], "Test failed");
}
// radixSort(data2.begin(), data2.end(), Negate());
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
// radixSort(data2.begin(), data2.end(), negate);
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
}
{
std::vector<unsigned char> data1(n);
generateCharSequence(n, data1);
std::vector<unsigned char> data2(data1);
std::sort(data1.begin(), data1.end());
radixSort(data2.begin(), data2.end());
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[i], "Test failed");
}
}
{
std::list<int> data1;
generateIntSequence(n, data1);
std::list<int> data2(listsort<std::list<int> >(data1.begin(), data1.end()));
radixSort(data1.begin(), data1.end());
check(isTheSame(data1,data2), "Test failed");
// radixSort(data2.begin(), data2.end(), Negate());
// check(isTheSame(data1,data2), "Test failed");
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
// radixSort(data2.begin(), data2.end(), negate);
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
}
{
std::list<unsigned char> data1(n);
generateCharSequence(n, data1);
std::list<unsigned char> data2(listsort<std::list<unsigned char> >
(data1.begin(),
data1.end()));
radixSort(data1.begin(), data1.end());
check(isTheSame(data1,data2), "Test failed");
}
}
void checkStableRadixSort() {
{
std::vector<int> data1;
generateIntSequence(n, data1);
std::vector<int> data2(data1);
std::sort(data1.begin(), data1.end());
stableRadixSort(data2.begin(), data2.end());
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[i], "Test failed");
}
stableRadixSort(data2.begin(), data2.end(), Negate());
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[n - 1 - i], "Test failed");
}
stableRadixSort(data2.begin(), data2.end(), negate);
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[n - 1 - i], "Test failed");
}
}
{
std::vector<unsigned char> data1(n);
generateCharSequence(n, data1);
std::vector<unsigned char> data2(data1);
std::sort(data1.begin(), data1.end());
radixSort(data2.begin(), data2.end());
for (int i = 0; i < n; ++i) {
check(data1[i] == data2[i], "Test failed");
}
}
{
std::list<int> data1;
generateIntSequence(n, data1);
std::list<int> data2(listsort<std::list<int> >(data1.begin(),
data1.end()));
stableRadixSort(data1.begin(), data1.end());
check(isTheSame(data1,data2), "Test failed");
// stableRadixSort(data2.begin(), data2.end(), Negate());
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
// stableRadixSort(data2.begin(), data2.end(), negate);
// for (int i = 0; i < n; ++i) {
// check(data1[i] == data2[n - 1 - i], "Test failed");
// }
}
{
std::list<unsigned char> data1(n);
generateCharSequence(n, data1);
std::list<unsigned char> data2(listsort<std::list<unsigned char> >
(data1.begin(),
data1.end()));
radixSort(data1.begin(), data1.end());
check(isTheSame(data1,data2), "Test failed");
}
}
int main() {
checkRadixSort();
checkStableRadixSort();
return 0;
}

View File

@@ -0,0 +1,40 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/random.h>
#include "test_tools.h"
int seed_array[] = {1, 2};
int main()
{
double a=lemon::rnd();
check(a<1.0&&a>0.0,"This should be in [0,1)");
a=lemon::rnd.gauss();
a=lemon::rnd.gamma(3.45,0);
a=lemon::rnd.gamma(4);
//Does gamma work with integer k?
a=lemon::rnd.gamma(4.0,0);
a=lemon::rnd.poisson(.5);
lemon::rnd.seed(100);
lemon::rnd.seed(seed_array, seed_array +
(sizeof(seed_array) / sizeof(seed_array[0])));
return 0;
}

View File

@@ -0,0 +1,267 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <lemon/list_graph.h>
#include <lemon/lgf_reader.h>
#include <lemon/path.h>
#include <lemon/suurballe.h>
#include <lemon/concepts/digraph.h>
#include <lemon/concepts/heap.h>
#include "test_tools.h"
using namespace lemon;
char test_lgf[] =
"@nodes\n"
"label\n"
"1\n"
"2\n"
"3\n"
"4\n"
"5\n"
"6\n"
"7\n"
"8\n"
"9\n"
"10\n"
"11\n"
"12\n"
"@arcs\n"
" length\n"
" 1 2 70\n"
" 1 3 150\n"
" 1 4 80\n"
" 2 8 80\n"
" 3 5 140\n"
" 4 6 60\n"
" 4 7 80\n"
" 4 8 110\n"
" 5 7 60\n"
" 5 11 120\n"
" 6 3 0\n"
" 6 9 140\n"
" 6 10 90\n"
" 7 1 30\n"
" 8 12 60\n"
" 9 12 50\n"
"10 12 70\n"
"10 2 100\n"
"10 7 60\n"
"11 10 20\n"
"12 11 30\n"
"@attributes\n"
"source 1\n"
"target 12\n"
"@end\n";
// Check the interface of Suurballe
void checkSuurballeCompile()
{
typedef int VType;
typedef concepts::Digraph Digraph;
typedef Digraph::Node Node;
typedef Digraph::Arc Arc;
typedef concepts::ReadMap<Arc, VType> LengthMap;
typedef Suurballe<Digraph, LengthMap> ST;
typedef Suurballe<Digraph, LengthMap>
::SetFlowMap<ST::FlowMap>
::SetPotentialMap<ST::PotentialMap>
::SetPath<SimplePath<Digraph> >
::SetHeap<concepts::Heap<VType, Digraph::NodeMap<int> > >
::Create SuurballeType;
Digraph g;
Node n;
Arc e;
LengthMap len;
SuurballeType::FlowMap flow(g);
SuurballeType::PotentialMap pi(g);
SuurballeType suurb_test(g, len);
const SuurballeType& const_suurb_test = suurb_test;
suurb_test
.flowMap(flow)
.potentialMap(pi);
int k;
k = suurb_test.run(n, n);
k = suurb_test.run(n, n, k);
suurb_test.init(n);
suurb_test.fullInit(n);
suurb_test.start(n);
suurb_test.start(n, k);
k = suurb_test.findFlow(n);
k = suurb_test.findFlow(n, k);
suurb_test.findPaths();
int f;
VType c;
::lemon::ignore_unused_variable_warning(f,c);
c = const_suurb_test.totalLength();
f = const_suurb_test.flow(e);
const SuurballeType::FlowMap& fm =
const_suurb_test.flowMap();
c = const_suurb_test.potential(n);
const SuurballeType::PotentialMap& pm =
const_suurb_test.potentialMap();
k = const_suurb_test.pathNum();
Path<Digraph> p = const_suurb_test.path(k);
::lemon::ignore_unused_variable_warning(fm);
::lemon::ignore_unused_variable_warning(pm);
}
// Check the feasibility of the flow
template <typename Digraph, typename FlowMap>
bool checkFlow( const Digraph& gr, const FlowMap& flow,
typename Digraph::Node s, typename Digraph::Node t,
int value )
{
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
for (ArcIt e(gr); e != INVALID; ++e)
if (!(flow[e] == 0 || flow[e] == 1)) return false;
for (NodeIt n(gr); n != INVALID; ++n) {
int sum = 0;
for (OutArcIt e(gr, n); e != INVALID; ++e)
sum += flow[e];
for (InArcIt e(gr, n); e != INVALID; ++e)
sum -= flow[e];
if (n == s && sum != value) return false;
if (n == t && sum != -value) return false;
if (n != s && n != t && sum != 0) return false;
}
return true;
}
// Check the optimalitiy of the flow
template < typename Digraph, typename CostMap,
typename FlowMap, typename PotentialMap >
bool checkOptimality( const Digraph& gr, const CostMap& cost,
const FlowMap& flow, const PotentialMap& pi )
{
// Check the "Complementary Slackness" optimality condition
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
bool opt = true;
for (ArcIt e(gr); e != INVALID; ++e) {
typename CostMap::Value red_cost =
cost[e] + pi[gr.source(e)] - pi[gr.target(e)];
opt = (flow[e] == 0 && red_cost >= 0) ||
(flow[e] == 1 && red_cost <= 0);
if (!opt) break;
}
return opt;
}
// Check a path
template <typename Digraph, typename Path>
bool checkPath( const Digraph& gr, const Path& path,
typename Digraph::Node s, typename Digraph::Node t)
{
TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
Node n = s;
for (int i = 0; i < path.length(); ++i) {
if (gr.source(path.nth(i)) != n) return false;
n = gr.target(path.nth(i));
}
return n == t;
}
int main()
{
DIGRAPH_TYPEDEFS(ListDigraph);
// Read the test digraph
ListDigraph digraph;
ListDigraph::ArcMap<int> length(digraph);
Node s, t;
std::istringstream input(test_lgf);
DigraphReader<ListDigraph>(digraph, input).
arcMap("length", length).
node("source", s).
node("target", t).
run();
// Check run()
{
Suurballe<ListDigraph> suurballe(digraph, length);
// Find 2 paths
check(suurballe.run(s, t) == 2, "Wrong number of paths");
check(checkFlow(digraph, suurballe.flowMap(), s, t, 2),
"The flow is not feasible");
check(suurballe.totalLength() == 510, "The flow is not optimal");
check(checkOptimality(digraph, length, suurballe.flowMap(),
suurballe.potentialMap()),
"Wrong potentials");
for (int i = 0; i < suurballe.pathNum(); ++i)
check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
// Find 3 paths
check(suurballe.run(s, t, 3) == 3, "Wrong number of paths");
check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
"The flow is not feasible");
check(suurballe.totalLength() == 1040, "The flow is not optimal");
check(checkOptimality(digraph, length, suurballe.flowMap(),
suurballe.potentialMap()),
"Wrong potentials");
for (int i = 0; i < suurballe.pathNum(); ++i)
check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
// Find 5 paths (only 3 can be found)
check(suurballe.run(s, t, 5) == 3, "Wrong number of paths");
check(checkFlow(digraph, suurballe.flowMap(), s, t, 3),
"The flow is not feasible");
check(suurballe.totalLength() == 1040, "The flow is not optimal");
check(checkOptimality(digraph, length, suurballe.flowMap(),
suurballe.potentialMap()),
"Wrong potentials");
for (int i = 0; i < suurballe.pathNum(); ++i)
check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path");
}
// Check fullInit() + start()
{
Suurballe<ListDigraph> suurballe(digraph, length);
suurballe.fullInit(s);
// Find 2 paths
check(suurballe.start(t) == 2, "Wrong number of paths");
check(suurballe.totalLength() == 510, "The flow is not optimal");
// Find 3 paths
check(suurballe.start(t, 3) == 3, "Wrong number of paths");
check(suurballe.totalLength() == 1040, "The flow is not optimal");
// Find 5 paths (only 3 can be found)
check(suurballe.start(t, 5) == 3, "Wrong number of paths");
check(suurballe.totalLength() == 1040, "The flow is not optimal");
}
return 0;
}

View File

@@ -0,0 +1,50 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2010
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#ifndef LEMON_TEST_TEST_TOOLS_H
#define LEMON_TEST_TEST_TOOLS_H
///\ingroup misc
///\file
///\brief Some utilities to write test programs.
#include <iostream>
#include <stdlib.h>
///If \c rc is fail, writes an error message and exits.
///If \c rc is fail, writes an error message and exits.
///The error message contains the file name and the line number of the
///source code in a standard from, which makes it possible to go there
///using good source browsers like e.g. \c emacs.
///
///For example
///\code check(0==1,"This is obviously false.");\endcode will
///print something like this (and then exits).
///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim
#define check(rc, msg) \
{ \
if(!(rc)) { \
std::cerr << __FILE__ ":" << __LINE__ << ": error: " \
<< msg << std::endl; \
abort(); \
} else { } \
} \
#endif

View File

@@ -0,0 +1,25 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include "test_tools.h"
int main()
{
check(false, "Don't panic. Failing is the right behaviour here.");
return 0;
}

View File

@@ -0,0 +1,25 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include "test_tools.h"
int main()
{
check(true, "It should pass.");
return 0;
}

View File

@@ -0,0 +1,60 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/time_measure.h>
#include <lemon/concept_check.h>
using namespace lemon;
void f()
{
double d=0;
for(int i=0;i<1000;i++)
d+=0.1;
}
void g()
{
static Timer T;
for(int i=0;i<1000;i++)
{
TimeStamp x(T);
::lemon::ignore_unused_variable_warning(x);
}
}
int main()
{
Timer T;
unsigned int n;
for(n=0;T.realTime()<0.1;n++) ;
std::cout << T << " (" << n << " time queries)\n";
TimeStamp full;
TimeStamp t;
t=runningTimeTest(f,0.1,&n,&full);
std::cout << t << " (" << n << " tests)\n";
std::cout << "Total: " << full << "\n";
t=runningTimeTest(g,0.1,&n,&full);
std::cout << t << " (" << n << " tests)\n";
std::cout << "Total: " << full << "\n";
return 0;
}

View File

@@ -0,0 +1,287 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <iostream>
#include <lemon/full_graph.h>
#include <lemon/math.h>
#include <lemon/maps.h>
#include <lemon/random.h>
#include <lemon/dim2.h>
#include <lemon/nearest_neighbor_tsp.h>
#include <lemon/greedy_tsp.h>
#include <lemon/insertion_tsp.h>
#include <lemon/christofides_tsp.h>
#include <lemon/opt2_tsp.h>
#include "test_tools.h"
using namespace lemon;
// // Tests checkMetricCost() function
// void metricCostTest() {
// GRAPH_TYPEDEFS(FullGraph);
// FullGraph g(10);
// check(checkMetricCost(g, constMap<Edge>(0)), "Wrong checkMetricCost()");
// check(checkMetricCost(g, constMap<Edge>(1)), "Wrong checkMetricCost()");
// check(!checkMetricCost(g, constMap<Edge>(-1)), "Wrong checkMetricCost()");
//
// FullGraph::EdgeMap<float> cost(g);
// for (NodeIt u(g); u != INVALID; ++u) {
// for (NodeIt v(g); v != INVALID; ++v) {
// if (u == v) continue;
// float x1 = g.id(u), x2 = g.id(v);
// float y1 = x1 * x1, y2 = x2 * x2;
// cost[g.edge(u, v)] = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
// }
// }
// check(checkMetricCost(g, cost), "Wrong checkMetricCost()");
// float eps = Tolerance<float>::defaultEpsilon();
// cost[g.edge(g(0), g(9))] =
// cost[g.edge(g(0), g(8))] + cost[g.edge(g(8), g(9))] + eps * 2;
// check(!checkMetricCost(g, cost), "Wrong checkMetricCost()");
// check(checkMetricCost(g, cost, Tolerance<float>(eps * 4)),
// "Wrong checkMetricCost()");
// }
// Checks tour validity
template <typename Container>
bool checkTour(const FullGraph &gr, const Container &p) {
FullGraph::NodeMap<bool> used(gr, false);
int node_cnt = 0;
for (typename Container::const_iterator it = p.begin(); it != p.end(); ++it)
{
FullGraph::Node node = *it;
if (used[node]) return false;
used[node] = true;
++node_cnt;
}
return (node_cnt == gr.nodeNum());
}
// Checks tour validity
bool checkTourPath(const FullGraph &gr, const Path<FullGraph> &p) {
FullGraph::NodeMap<bool> used(gr, false);
if (!checkPath(gr, p)) return false;
if (gr.nodeNum() <= 1 && p.length() != 0) return false;
if (gr.nodeNum() > 1 && p.length() != gr.nodeNum()) return false;
for (int i = 0; i < p.length(); ++i) {
if (used[gr.target(p.nth(i))]) return false;
used[gr.target(p.nth(i))] = true;
}
return true;
}
// Checks tour cost
template <typename CostMap>
bool checkCost(const FullGraph &gr, const std::vector<FullGraph::Node> &p,
const CostMap &cost, typename CostMap::Value total)
{
typedef typename CostMap::Value Cost;
Cost s = 0;
for (int i = 0; i < int(p.size()) - 1; ++i)
s += cost[gr.edge(p[i], p[i+1])];
if (int(p.size()) >= 2)
s += cost[gr.edge(p.back(), p.front())];
return !Tolerance<Cost>().different(s, total);
}
// Checks tour cost
template <typename CostMap>
bool checkCost(const FullGraph &, const Path<FullGraph> &p,
const CostMap &cost, typename CostMap::Value total)
{
typedef typename CostMap::Value Cost;
Cost s = 0;
for (int i = 0; i < p.length(); ++i)
s += cost[p.nth(i)];
return !Tolerance<Cost>().different(s, total);
}
// Tests a TSP algorithm on small graphs
template <typename TSP>
void tspTestSmall(const std::string &alg_name) {
GRAPH_TYPEDEFS(FullGraph);
for (int n = 0; n <= 5; ++n) {
FullGraph g(n);
unsigned nsize = n;
int esize = n <= 1 ? 0 : n;
ConstMap<Edge, int> cost_map(1);
TSP alg(g, cost_map);
check(alg.run() == esize, alg_name + ": Wrong total cost");
check(alg.tourCost() == esize, alg_name + ": Wrong total cost");
std::list<Node> list1(nsize), list2;
std::vector<Node> vec1(nsize), vec2;
alg.tourNodes(list1.begin());
alg.tourNodes(vec1.begin());
alg.tourNodes(std::front_inserter(list2));
alg.tourNodes(std::back_inserter(vec2));
check(checkTour(g, alg.tourNodes()), alg_name + ": Wrong node sequence");
check(checkTour(g, list1), alg_name + ": Wrong node sequence");
check(checkTour(g, vec1), alg_name + ": Wrong node sequence");
check(checkTour(g, list2), alg_name + ": Wrong node sequence");
check(checkTour(g, vec2), alg_name + ": Wrong node sequence");
check(checkCost(g, vec1, constMap<Edge, int>(1), esize),
alg_name + ": Wrong tour cost");
SimplePath<FullGraph> path;
alg.tour(path);
check(path.length() == esize, alg_name + ": Wrong tour");
check(checkTourPath(g, path), alg_name + ": Wrong tour");
check(checkCost(g, path, constMap<Edge, int>(1), esize),
alg_name + ": Wrong tour cost");
}
}
// Tests a TSP algorithm on random graphs
template <typename TSP>
void tspTestRandom(const std::string &alg_name) {
GRAPH_TYPEDEFS(FullGraph);
FullGraph g(20);
FullGraph::NodeMap<dim2::Point<double> > pos(g);
DoubleEdgeMap cost(g);
TSP alg(g, cost);
Opt2Tsp<DoubleEdgeMap > opt2(g, cost);
for (int i = 1; i <= 3; i++) {
for (NodeIt u(g); u != INVALID; ++u) {
pos[u] = dim2::Point<double>(rnd(), rnd());
}
for (NodeIt u(g); u != INVALID; ++u) {
for (NodeIt v(g); v != INVALID; ++v) {
if (u == v) continue;
cost[g.edge(u, v)] = (pos[u] - pos[v]).normSquare();
}
}
check(alg.run() > 0, alg_name + ": Wrong total cost");
std::vector<Node> vec;
alg.tourNodes(std::back_inserter(vec));
check(checkTour(g, vec), alg_name + ": Wrong node sequence");
check(checkCost(g, vec, cost, alg.tourCost()),
alg_name + ": Wrong tour cost");
SimplePath<FullGraph> path;
alg.tour(path);
check(checkTourPath(g, path), alg_name + ": Wrong tour");
check(checkCost(g, path, cost, alg.tourCost()),
alg_name + ": Wrong tour cost");
check(!Tolerance<double>().less(alg.tourCost(), opt2.run(alg.tourNodes())),
"2-opt improvement: Wrong total cost");
check(checkTour(g, opt2.tourNodes()),
"2-opt improvement: Wrong node sequence");
check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()),
"2-opt improvement: Wrong tour cost");
check(!Tolerance<double>().less(alg.tourCost(), opt2.run(path)),
"2-opt improvement: Wrong total cost");
check(checkTour(g, opt2.tourNodes()),
"2-opt improvement: Wrong node sequence");
check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()),
"2-opt improvement: Wrong tour cost");
}
}
// Algorithm class for Nearest Insertion
template <typename CM>
class NearestInsertionTsp : public InsertionTsp<CM> {
public:
NearestInsertionTsp(const FullGraph &gr, const CM &cost)
: InsertionTsp<CM>(gr, cost) {}
typename CM::Value run() {
return InsertionTsp<CM>::run(InsertionTsp<CM>::NEAREST);
}
};
// Algorithm class for Farthest Insertion
template <typename CM>
class FarthestInsertionTsp : public InsertionTsp<CM> {
public:
FarthestInsertionTsp(const FullGraph &gr, const CM &cost)
: InsertionTsp<CM>(gr, cost) {}
typename CM::Value run() {
return InsertionTsp<CM>::run(InsertionTsp<CM>::FARTHEST);
}
};
// Algorithm class for Cheapest Insertion
template <typename CM>
class CheapestInsertionTsp : public InsertionTsp<CM> {
public:
CheapestInsertionTsp(const FullGraph &gr, const CM &cost)
: InsertionTsp<CM>(gr, cost) {}
typename CM::Value run() {
return InsertionTsp<CM>::run(InsertionTsp<CM>::CHEAPEST);
}
};
// Algorithm class for Random Insertion
template <typename CM>
class RandomInsertionTsp : public InsertionTsp<CM> {
public:
RandomInsertionTsp(const FullGraph &gr, const CM &cost)
: InsertionTsp<CM>(gr, cost) {}
typename CM::Value run() {
return InsertionTsp<CM>::run(InsertionTsp<CM>::RANDOM);
}
};
int main() {
GRAPH_TYPEDEFS(FullGraph);
// metricCostTest();
tspTestSmall<NearestNeighborTsp<ConstMap<Edge, int> > >("Nearest Neighbor");
tspTestSmall<GreedyTsp<ConstMap<Edge, int> > >("Greedy");
tspTestSmall<NearestInsertionTsp<ConstMap<Edge, int> > >("Nearest Insertion");
tspTestSmall<FarthestInsertionTsp<ConstMap<Edge, int> > >
("Farthest Insertion");
tspTestSmall<CheapestInsertionTsp<ConstMap<Edge, int> > >
("Cheapest Insertion");
tspTestSmall<RandomInsertionTsp<ConstMap<Edge, int> > >("Random Insertion");
tspTestSmall<ChristofidesTsp<ConstMap<Edge, int> > >("Christofides");
tspTestSmall<Opt2Tsp<ConstMap<Edge, int> > >("2-opt");
tspTestRandom<NearestNeighborTsp<DoubleEdgeMap > >("Nearest Neighbor");
tspTestRandom<GreedyTsp<DoubleEdgeMap > >("Greedy");
tspTestRandom<NearestInsertionTsp<DoubleEdgeMap > >("Nearest Insertion");
tspTestRandom<FarthestInsertionTsp<DoubleEdgeMap > >("Farthest Insertion");
tspTestRandom<CheapestInsertionTsp<DoubleEdgeMap > >("Cheapest Insertion");
tspTestRandom<RandomInsertionTsp<DoubleEdgeMap > >("Random Insertion");
tspTestRandom<ChristofidesTsp<DoubleEdgeMap > >("Christofides");
tspTestRandom<Opt2Tsp<DoubleEdgeMap > >("2-opt");
return 0;
}

View File

@@ -0,0 +1,102 @@
/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2009
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
#include <lemon/list_graph.h>
#include <lemon/maps.h>
#include <lemon/unionfind.h>
#include "test_tools.h"
using namespace lemon;
using namespace std;
typedef UnionFindEnum<ListGraph::NodeMap<int> > UFE;
int main() {
ListGraph g;
ListGraph::NodeMap<int> base(g);
UFE U(base);
vector<ListGraph::Node> n;
for(int i=0;i<20;i++) n.push_back(g.addNode());
U.insert(n[1]);
U.insert(n[2]);
check(U.join(n[1],n[2]) != -1, "Something is wrong with UnionFindEnum");
U.insert(n[3]);
U.insert(n[4]);
U.insert(n[5]);
U.insert(n[6]);
U.insert(n[7]);
check(U.join(n[1],n[4]) != -1, "Something is wrong with UnionFindEnum");
check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum");
check(U.join(n[3],n[5]) != -1, "Something is wrong with UnionFindEnum");
U.insert(n[8],U.find(n[5]));
check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[5])) == 3, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[6])) == 1, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum");
U.insert(n[9]);
U.insert(n[10],U.find(n[9]));
check(U.join(n[8],n[10]) != -1, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[9])) == 5, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[8])) == 5, "Something is wrong with UnionFindEnum");
U.erase(n[9]);
U.erase(n[1]);
check(U.size(U.find(n[10])) == 4, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum");
U.erase(n[6]);
U.split(U.find(n[8]));
check(U.size(U.find(n[4])) == 2, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[3])) == 1, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum");
check(U.join(n[3],n[4]) != -1, "Something is wrong with UnionFindEnum");
check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[3])) == 3, "Something is wrong with UnionFindEnum");
check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum");
U.eraseClass(U.find(n[4]));
U.eraseClass(U.find(n[7]));
return 0;
}