Skip to content

Commit 4669830

Browse files
Initial commit with a clean history
0 parents  commit 4669830

1,011 files changed

Lines changed: 3674668 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
3+
project(dynwmis C CXX)
4+
enable_language(CXX)
5+
6+
set(CMAKE_CXX_STANDARD 17)
7+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
8+
9+
# debugging
10+
#set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer")
11+
12+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
13+
14+
include_directories(${INTERFACE_INCLUDE_DIRECTORIES})
15+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/extern/argtable3-3.0.3)
16+
17+
18+
#set(GUROBI_LIBRARY /home/cschulz/local/opt/gurobi912/lib)
19+
#find_package(Gurobi REQUIRED)
20+
21+
#MESSAGE("Gurobi: include header files: ${GUROBI_INCLUDE_DIRS}")
22+
#include_directories(${GUROBI_INCLUDE_DIRS})
23+
24+
#add_definitions(-g -pg)
25+
SET(DYNWMIS_INCLUDE_DIRS
26+
lib
27+
lib/algorithms
28+
lib/data_structure
29+
lib/io
30+
lib/tools
31+
extern/sparsehash/src
32+
extern/argtable3-3.0.3/
33+
)
34+
include_directories(${DYNWMIS_INCLUDE_DIRS})
35+
add_definitions(-w)
36+
37+
set(KAMIS_DIR extern/wmis)
38+
include_directories(
39+
${KAMIS_DIR}/app
40+
${KAMIS_DIR}/lib
41+
${KAMIS_DIR}/lib/io
42+
${KAMIS_DIR}/lib/mis
43+
${KAMIS_DIR}/lib/mis/hils
44+
${KAMIS_DIR}/lib/mis/ils
45+
${KAMIS_DIR}/lib/mis/initial_mis
46+
${KAMIS_DIR}/lib/mis/kernel
47+
${KAMIS_DIR}/lib/partition
48+
${KAMIS_DIR}/lib/partition/uncoarsening/refinement/quotient_graph_refinement/flow_refinement
49+
${KAMIS_DIR}/lib/tools
50+
${KAMIS_DIR}/extern
51+
${KAMIS_DIR}/extern/KaHIP
52+
${KAMIS_DIR}/extern/KaHIP/lib
53+
${KAMIS_DIR}/extern/KaHIP/lib/io
54+
${KAMIS_DIR}/extern/KaHIP/lib/partition
55+
${KAMIS_DIR}/extern/KaHIP/lib/partition/uncoarsening/refinement/quotient_graph_refinement/flow_refinement
56+
${KAMIS_DIR}/extern/KaHIP/lib/tools
57+
${KAMIS_DIR}/extern/KaHIP/lib
58+
${KAMIS_DIR}/extern/KaHIP/lib/data_structure
59+
${KAMIS_DIR}/extern/KaHIP/lib/data_structure/matrix
60+
${KAMIS_DIR}/extern/KaHIP/lib/data_structure/priority_queues)
61+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/extern/onlinemis)
62+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/extern/onlinemis/ils)
63+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/extern/onlinemis/initial_mis)
64+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/extern/onlinemis/data_structure)
65+
66+
67+
# add source files of wmis
68+
add_subdirectory(${KAMIS_DIR})
69+
70+
71+
72+
# VARS
73+
SET(DYNWMIS dynwmis)
74+
#SET(CMAKE_BUILD_TYPE Debug)
75+
MESSAGE("${CMAKE_BUILD_TYPE}")
76+
77+
add_definitions(-O3 -DNDEBUG -fpermissive -march=native)
78+
79+
80+
SET(DYNWMIS_CXX_FILES
81+
lib/data_structure/dyn_graph_access.cpp
82+
lib/io/mwis_graph_io.cpp
83+
lib/tools/timer.cpp
84+
lib/algorithms/dyn_wmis_simple.cpp
85+
lib/algorithms/dyn_wmis_greedy.cpp
86+
lib/algorithms/dyn_wmis_greedy_deg.cpp
87+
lib/algorithms/dyn_wmis_bfs.cpp
88+
lib/algorithms/dyn_wmis_static.cpp
89+
lib/algorithms/solve_static_wmis.cpp
90+
lib/algorithms/mis_branch_and_reduce_algorithm.cpp
91+
lib/algorithms/modified.cpp
92+
extern/onlinemis/ils/local_search_online.cpp
93+
extern/onlinemis/ils/online_ils.cpp
94+
extern/onlinemis/tools/mis_log.cpp
95+
extern/onlinemis/initial_mis/greedy_mis_online.cpp
96+
extern/onlinemis/data_structure/candidate_list.cpp
97+
extern/onlinemis/data_structure/mis_permutation_online.cpp
98+
extern/onlinemis/data_structure/priority_queues/bucket_array.cpp
99+
)
100+
101+
set(LIBCONVERT_SOURCE_FILES
102+
./lib/io/mwis_graph_io.cpp
103+
./lib/data_structure/dyn_graph_access.cpp
104+
./lib/tools/random_functions.cpp
105+
extern/argtable3-3.0.3/argtable3.c)
106+
add_library(libconvert OBJECT ${LIBCONVERT_SOURCE_FILES})
107+
108+
# Obejct Library
109+
set(DYNWMIS_LIB dynwmis_lib)
110+
add_library(${DYNWMIS_LIB} OBJECT ${DYNWMIS_CXX_FILES})
111+
112+
113+
# build settings
114+
# debugging is activated if NDEBUG is not set
115+
# logging
116+
117+
# Executables
118+
add_executable(${DYNWMIS} app/${DYNWMIS}.cpp $<TARGET_OBJECTS:libkaffpa> $<TARGET_OBJECTS:libsources> $<TARGET_OBJECTS:${DYNWMIS_LIB}>)
119+
120+
add_executable(convert_metis_seq app/metis_to_sequence.cpp $<TARGET_OBJECTS:libconvert> )
121+
install(TARGETS convert_metis_seq DESTINATION ./)
122+
123+
# install
124+
set(CMAKE_INSTALL_PREFIX ../deploy)
125+
install(TARGETS ${DYNWMIS} DESTINATION ./)

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Dynamic Graph Algorithms Lab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Dynamic (Weighted) Independent Set [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
2+
3+
A dynamic graph algorithm is a data structure that supports edge insertions, deletions, and problem specific queries. While extensive research exists on dynamic algorithms for graph problems solvable in polynomial time, most of these algorithms have not been implemented or empirically evaluated. The open source framework addresses the NP-complete maximum weight as well as the maximum cardinality independent set problem in a dynamic setting, applicable to areas like dynamic map-labeling and vehicle routing. Specifically we introduce a novel local search technique called optimal neighborhood exploration. This technique creates independent subproblems that are solved to optimality, leading to improved overall solutions. Through numerous experiments, we assess the effectiveness of our approach and compare it with other state-of-the-art dynamic solvers. Our algorithm features a parameter, the subproblem size, that balances running time and solution quality.
4+
5+
Installation Notes
6+
=====
7+
## Downloading:
8+
You can download the project with the following command line:
9+
10+
```console
11+
git clone https://github.com/DynGraphLab/DynWMIS
12+
```
13+
14+
## Compiling:
15+
Just type in the main directory of the project:
16+
```console
17+
./compile_withcmake.sh
18+
```
19+
In this case, all binaries, libraries and headers are in the folder ./deploy/
20+
21+
Note that this script detects the amount of available cores on your machine and uses all of them for the compilation process. If you don't want that, set the variable NCORES to the number of cores that you would like to use for compilation.
22+
23+
Alternatively use the standard cmake build process:
24+
```console
25+
mkdir build
26+
cd build
27+
cmake ../ -DCMAKE_BUILD_TYPE=Release
28+
make
29+
cd ..
30+
```
31+
In this case, the binaries, libraries and headers are in the folder ./build
32+
33+
34+
35+
Graph Format
36+
=====
37+
The graph format used is a simple edge list. The first line is a # followed by two numbers `n` and `m` which specify the number of nodes of your input `n` and the number of edges/updates your perform. If there is a third number that equals `1` in this line, then the graph is weighted. If the graph is weighted, then the next `n` lines will specify vertex weights (one line per vertex). In both cases the `m` lines that follow, each line specifies an update. An update is either an edge insertion or deletion. An edge insertion is specified by a `1` followed by two numbers `u` and `v` which specify the edge `{u,v}` to be inserted. An edge deletion is specified by a `0` followed by two numbers `u` and `v` which specify the edge `{u,v}` to be deleted. In general, vertex IDs start at 1. Updates of vertex weights are in principle also possible, but not supported by the current implementation.
38+
39+
To convert a METIS graph file (like the ones available here https://dimacs10.github.io/) into the graph sequence format used by our program, you can use the following command:
40+
```console
41+
./deploy/convert_metis_seq nameofgraphfile.graph
42+
```
43+
The output will be store `nameofgraphfile.graph.seq`; For example,
44+
```console
45+
./deploy/convert_metis_seq examples/3elt.graph
46+
```
47+
Creates the file `examples/3elt.graph.seq`; Note, however, that this results in insertion only sequences.
48+
49+
50+
Running Programs
51+
=====
52+
Running the algorithm is done as follows:
53+
54+
Running the algorithm on a graph file `3elt.graph.seq` with the algorithm `DynamicOneFast`:
55+
```console
56+
./deploy/dynwmis examples/3elt.graph.seq --algorithm=DynamicOneFast
57+
```
58+
59+
Running the algorithm on a graph file `3elt.graph.seq` with the algorithm `DynamicOneFast`:
60+
```console
61+
./deploy/dynwmis examples/4elt.graph.seq --algorithm=DynamicOneFast
62+
```
63+
64+
The following commands should reproduce the values of the `4elt` instance in Table 1 of our paper:
65+
66+
```console
67+
for g in `seq 1 10`; do ./deploy/dynwmis examples/4elt.graph.seq --algorithm=DynamicOneFast --seed=$g | grep weight | grep -v spec; done | awk '{if($NF>max){max=$NF}}END{print max}'
68+
```
69+
70+
```console
71+
for g in `seq 1 10`; do ./deploy/dynwmis examples/4elt.graph.seq --algorithm=DynamicOneStrong --seed=$g | grep weight | grep -v spec; done | awk '{if($NF>max){max=$NF}}END{print max}'
72+
```
73+
74+
75+
76+
Licence
77+
=====
78+
The program is licenced under MIT licence.
79+
If you publish results using our algorithms, please acknowledge our work by quoting the following paper:
80+
81+
82+
```
83+
@misc{borowitz2024optimalneighborhoodexplorationdynamic,
84+
title={Optimal Neighborhood Exploration for Dynamic Independent Sets},
85+
author={Jannick Borowitz and Ernestine Großmann and Christian Schulz},
86+
year={2024},
87+
eprint={2407.06912},
88+
archivePrefix={arXiv},
89+
primaryClass={cs.DS},
90+
url={https://arxiv.org/abs/2407.06912},
91+
}
92+
```
93+
94+
95+

app/dynwmis.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//
2+
// Created by Jannick Borowitz on 18.04.22.
3+
//
4+
5+
#include <random_functions.h>
6+
7+
#include <algorithm>
8+
#include <cmath>
9+
#include <iostream>
10+
#include <iomanip>
11+
12+
#include "parse_parameters.h"
13+
#include "DynamicAlgorithmMeta.h"
14+
#include "DynWMISConfig.h"
15+
#include "algorithm_factory.h"
16+
#include "mwis_graph_io.h"
17+
#include "timer.h"
18+
19+
int main(int argc, char** argv) {
20+
21+
22+
DynWMISConfig config;
23+
24+
std::string graph_filename;
25+
int ret_code = parse_parameters(argc, argv, config, graph_filename);
26+
27+
if(ret_code) {
28+
return 0;
29+
}
30+
31+
32+
srand(config.seed);
33+
random_functions::setSeed(config.seed);
34+
35+
// read sequence
36+
auto graphIO = mwis_graph_io();
37+
timer t; t.restart();
38+
39+
std::vector<std::pair<int, std::pair<NodeID, NodeID> > > edge_sequence;
40+
bool has_node_weights = false;
41+
std::vector< NodeWeight > node_weights;
42+
std::pair<int,int> p = graphIO.readEdgeSequence( graph_filename, edge_sequence, node_weights, has_node_weights);
43+
int n = p.first;
44+
std::cout << "io took " << t.elapsed() << std::endl;
45+
46+
//configure algorithm based on input parameters
47+
std::shared_ptr<dyn_graph_access> G = std::make_shared<dyn_graph_access>(n);
48+
49+
std::shared_ptr<dyn_wmis_algorithm> algorithm = getdyn_wmis_instance(config.algorithmType, G, config);
50+
config.local_algorithmType = MIS_BRANCH_AND_REDUCE;
51+
if(has_node_weights) {
52+
forall_nodes((*G), node) {
53+
G->setNodeWeight(node, node_weights[node]);
54+
} endfor
55+
config.local_algorithmType = BRANCH_AND_REDUCE;
56+
} else {
57+
forall_nodes((*G), node) {
58+
G->setNodeWeight(node, 1);
59+
} endfor
60+
}
61+
62+
t.restart();
63+
// run algorithm
64+
if(algorithm != NULL)
65+
run_dynamic_algorithm(G, edge_sequence, algorithm);
66+
67+
std::cout << "time \t\t " << t.elapsed() << std::endl;
68+
std::cout << "weight \t\t " << algorithm->weight() << std::endl;
69+
70+
//call some postprocessing
71+
algorithm->end();
72+
73+
std::vector< bool > mis;
74+
mis = algorithm->getMIS();
75+
std::shared_ptr<dyn_graph_access> G_bar = std::make_shared<dyn_graph_access>(n);
76+
int mis_size = 0;
77+
for (size_t i = 0; i < edge_sequence.size(); ++i) {
78+
std::pair<NodeID, NodeID> & edge = edge_sequence[i].second;
79+
80+
if (edge_sequence.at(i).first) {
81+
G->new_edge(edge.first, edge.second);
82+
G->new_edge(edge.second, edge.first);
83+
} else {
84+
G->remove_edge(edge.first, edge.second);
85+
G->remove_edge(edge.second, edge.first);
86+
}
87+
88+
89+
90+
}
91+
92+
forall_nodes((*G), node) {
93+
if( mis[node] ) {
94+
//std::cout << "degree of is node " << G->getNodeDegree(node) << std::endl;
95+
mis_size += G->getNodeWeight(node);
96+
forall_out_edges((*G), e, node) {
97+
NodeID target = G->getEdgeTarget(node, e);
98+
if( mis[target] ) {
99+
std::cout << "NOT AN INDEPENDENT SET (" << node << "," << target << ")" << std::endl;
100+
exit(0);
101+
}
102+
} endfor
103+
} else {
104+
//std::cout << "degree of non-is node " << G->getNodeDegree(node) << std::endl;
105+
}
106+
} endfor
107+
108+
std::cout << "mis size checked is " << mis_size << std::endl;
109+
110+
return 0;
111+
}

0 commit comments

Comments
 (0)