Skip to content

Commit 732b978

Browse files
committed
graph-based hungarian assignment algorithm
0 parents  commit 732b978

14 files changed

+787
-0
lines changed

.clang-format

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
Language: Cpp
3+
# BasedOnStyle: LLVM
4+
AccessModifierOffset: -3
5+
AlignAfterOpenBracket: true
6+
AlignEscapedNewlinesLeft: false
7+
AlignOperands: true
8+
AlignTrailingComments: true
9+
AllowAllParametersOfDeclarationOnNextLine: true
10+
AllowShortBlocksOnASingleLine: false
11+
AllowShortCaseLabelsOnASingleLine: false
12+
AllowShortIfStatementsOnASingleLine: false
13+
AllowShortLoopsOnASingleLine: false
14+
AllowShortFunctionsOnASingleLine: None
15+
AlwaysBreakAfterDefinitionReturnType: false
16+
AlwaysBreakTemplateDeclarations: false
17+
AlwaysBreakBeforeMultilineStrings: false
18+
BreakBeforeBinaryOperators: None
19+
BreakBeforeTernaryOperators: true
20+
BreakConstructorInitializersBeforeComma: true
21+
BinPackParameters: true
22+
BinPackArguments: true
23+
ColumnLimit: 120
24+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
25+
ConstructorInitializerIndentWidth: 4
26+
DerivePointerAlignment: false
27+
ExperimentalAutoDetectBinPacking: false
28+
IndentCaseLabels: true
29+
IndentWrappedFunctionNames: false
30+
IndentFunctionDeclarationAfterType: false
31+
MaxEmptyLinesToKeep: 1
32+
KeepEmptyLinesAtTheStartOfBlocks: false
33+
NamespaceIndentation: None
34+
ObjCBlockIndentWidth: 2
35+
ObjCSpaceAfterProperty: false
36+
ObjCSpaceBeforeProtocolList: true
37+
PenaltyBreakBeforeFirstCallParameter: 19
38+
PenaltyBreakComment: 300
39+
PenaltyBreakString: 1000
40+
PenaltyBreakFirstLessLess: 120
41+
PenaltyExcessCharacter: 1000000
42+
PenaltyReturnTypeOnItsOwnLine: 60
43+
PointerAlignment: Left
44+
SpacesBeforeTrailingComments: 2
45+
Cpp11BracedListStyle: true
46+
Standard: Cpp11
47+
IndentWidth: 4
48+
TabWidth: 8
49+
UseTab: Never
50+
BreakBeforeBraces: Linux # the position of the braces
51+
SpacesInParentheses: false
52+
SpacesInSquareBrackets: false
53+
SpacesInAngles: false
54+
SpaceInEmptyParentheses: false
55+
SpacesInCStyleCastParentheses: false
56+
SpaceAfterCStyleCast: false
57+
SpacesInContainerLiterals: true
58+
SpaceBeforeAssignmentOperators: true
59+
ContinuationIndentWidth: 4
60+
CommentPragmas: '.*'
61+
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
62+
SpaceBeforeParens: ControlStatements
63+
DisableFormat: false
64+
...

.gitignore

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Compiled source #
2+
###################
3+
*.com
4+
*.class
5+
*.dll
6+
*.exe
7+
*.o
8+
*.so
9+
*.pyc
10+
.ipynb_checkpoints
11+
*~
12+
*#
13+
build*
14+
15+
# Packages #
16+
###################
17+
# it's better to unpack these files and commit the raw source
18+
# git has its own built in compression methods
19+
*.7z
20+
*.dmg
21+
*.gz
22+
*.iso
23+
*.jar
24+
*.rar
25+
*.tar
26+
*.zip
27+
28+
# Logs and databases #
29+
######################
30+
*.log
31+
*.sql
32+
*.sqlite
33+
34+
# OS generated files #
35+
######################
36+
.DS_Store
37+
.DS_Store?
38+
._*
39+
.Spotlight-V100
40+
.Trashes
41+
ehthumbs.db
42+
Thumbs.db
43+
44+
# Images
45+
######################
46+
*.jpg
47+
*.gif
48+
*.png
49+
*.svg
50+
*.ico
51+
52+
# Video
53+
######################
54+
*.wmv
55+
*.mpg
56+
*.mpeg
57+
*.mp4
58+
*.mov
59+
*.flv
60+
*.avi
61+
*.ogv
62+
*.ogg
63+
*.webm
64+
65+
# Audio
66+
######################
67+
*.wav
68+
*.mp3
69+
*.wma
70+
71+
# Fonts
72+
######################
73+
Fonts
74+
*.eot
75+
*.ttf
76+
*.woff
77+
78+
# Format
79+
######################
80+
CPPLINT.cfg
81+
.clang-format
82+
83+
# Gtags
84+
######################
85+
GPATH
86+
GRTAGS
87+
GSYMS
88+
GTAGS

CMakeLists.txt

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
project(hungarian_algorithm LANGUAGES CXX)
4+
5+
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
6+
7+
set(LIBRARY_NAME ${PROJECT_NAME})
8+
9+
find_package(OpenMP QUIET)
10+
if(OpenMP_FOUND)
11+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
12+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
13+
endif()
14+
15+
add_subdirectory(src)
16+
17+
if(BUILD_EXAMPLES)
18+
add_subdirectory(examples)
19+
endif(BUILD_EXAMPLES)
20+
21+
if(BUILD_TEST)
22+
enable_testing()
23+
add_subdirectory(tests)
24+
endif()

Makefile

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
UTEST=OFF
2+
BUILD_EXAMPLES=OFF
3+
CMAKE_ARGS:=$(CMAKE_ARGS)
4+
5+
default:
6+
@mkdir -p build
7+
@cd build && cmake .. -DBUILD_TEST=$(UTEST) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=Release $(CMAKE_ARGS) && make
8+
9+
apps:
10+
@make default BUILD_EXAMPLES=ON
11+
12+
unittest:
13+
@make default UTEST=ON
14+
@cd build && make test
15+
16+
clean:
17+
@rm -rf build*

README.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# 📝 Hungarian Assignment Algorithm (Maximum Weighted Bipartite Matching) #
2+
***
3+
4+
## :tada: TODO
5+
***
6+
7+
- [x] implementation of graph-based hungarian assignment algorithm
8+
- [x] unittest
9+
10+
## 🔨 How to Build ##
11+
***
12+
13+
```bash
14+
make default # to build library
15+
make apps # to build examples
16+
make unittest # to build unittests
17+
```
18+
19+
## :running: How to Run ##
20+
***
21+
22+
- run simple sample
23+
24+
```bash
25+
./build/examples/hungarian_algorithm_app
26+
```
27+
28+
## :gem: References ##
29+
***
30+
31+
- [Bipartite Matching & the Hungarian Method by Subhash Suri](https://www.cse.ust.hk/~golin/COMP572/Notes/Matching.pdf)
32+
- [Assignment Problem @ TopCoder](https://www.topcoder.com/community/competitive-programming/tutorials/assignment-problem-and-hungarian-algorithm/)
33+
- [Python implementation](https://github.com/xtof-durr/makeSimple/blob/master/Munkres/kuhnMunkres.py)

cmake/googletest-download.cmake

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
project(googletest-download NONE)
4+
5+
include(ExternalProject)
6+
7+
ExternalProject_Add(
8+
googletest
9+
SOURCE_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-src"
10+
BINARY_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build"
11+
GIT_REPOSITORY
12+
https://github.com/google/googletest.git
13+
GIT_TAG
14+
release-1.10.0
15+
CONFIGURE_COMMAND ""
16+
BUILD_COMMAND ""
17+
INSTALL_COMMAND ""
18+
TEST_COMMAND ""
19+
)

cmake/googletest.cmake

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
function(__fetch_googletest download_module_path download_root)
4+
set(GOOGLETEST_DOWNLOAD_ROOT ${download_root})
5+
configure_file(
6+
${download_module_path}/googletest-download.cmake
7+
${download_root}/CMakeLists.txt
8+
@ONLY
9+
)
10+
unset(GOOGLETEST_DOWNLOAD_ROOT)
11+
12+
execute_process(
13+
COMMAND
14+
"${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
15+
WORKING_DIRECTORY
16+
${download_root}
17+
)
18+
execute_process(
19+
COMMAND
20+
"${CMAKE_COMMAND}" --build .
21+
WORKING_DIRECTORY
22+
${download_root}
23+
)
24+
25+
add_subdirectory(
26+
${download_root}/googletest-src
27+
${download_root}/googletest-build
28+
)
29+
endfunction()

examples/App.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @file App.cpp
3+
*
4+
* @author btran
5+
*
6+
*/
7+
8+
#include <iostream>
9+
#include <vector>
10+
11+
#include <hungarian_algorithm/HungarianAlgorithm.hpp>
12+
13+
int main(int argc, char* argv[])
14+
{
15+
std::vector<double> cost = {
16+
7, 53, 183, 439, 863, //
17+
497, 383, 563, 79, 973, //
18+
287, 63, 343, 169, 583, //
19+
627, 343, 773, 959, 943, //
20+
767, 473, 103, 699, 303 //
21+
};
22+
23+
int numRows = 5;
24+
int numCols = 5;
25+
auto assignments = hungarian::solve(cost.data(), numRows, numCols);
26+
27+
for (int i = 0; i < numRows; ++i) {
28+
std::cout << "match: " << i << " " << assignments[i] << "\n";
29+
}
30+
31+
return EXIT_SUCCESS;
32+
}

examples/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
add_executable(hungarian_algorithm_app
4+
${CMAKE_CURRENT_LIST_DIR}/App.cpp
5+
)
6+
7+
target_link_libraries(hungarian_algorithm_app
8+
PUBLIC
9+
${LIBRARY_NAME}
10+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @file HungarianAlgorithm.hpp
3+
*
4+
* @author btran
5+
*
6+
*/
7+
8+
#pragma once
9+
10+
#include <vector>
11+
12+
namespace hungarian
13+
{
14+
/**
15+
* @brief solve matching problems of numRows agents to numCols jobs to maximize total outputs
16+
*
17+
* @return indices of matched jobs to each row agent. index -1 means no match
18+
*
19+
*/
20+
std::vector<int> solve(const double* costMatrix, int numRows, int numCols);
21+
} // namespace hungarian

src/CMakeLists.txt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
set(SOURCE_FILES
4+
${PROJECT_SOURCE_DIR}/src/HungarianAlgorithm.cpp
5+
)
6+
7+
add_library(${LIBRARY_NAME}
8+
SHARED
9+
${SOURCE_FILES}
10+
)
11+
12+
target_include_directories(${LIBRARY_NAME}
13+
SYSTEM PUBLIC
14+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
15+
$<INSTALL_INTERFACE:include>
16+
)
17+
18+
target_compile_features(${LIBRARY_NAME}
19+
PUBLIC
20+
cxx_std_17
21+
)
22+
23+
target_compile_options(${LIBRARY_NAME}
24+
PRIVATE
25+
$<$<CONFIG:Debug>:-O0 -g -Wall -Werror>
26+
$<$<CONFIG:Release>:-O3 -Wall -Werror>
27+
)

0 commit comments

Comments
 (0)