kap 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: kap
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Gabrovšek's Multiple Hungarian method for solving k-Assignment Problem.
5
5
  Home-page: https://github.com/inspiros/kap
6
6
  Author: Hoang-Nhat Tran (inspiros)
@@ -20,16 +20,20 @@ Classifier: Programming Language :: Python :: 3.8
20
20
  Classifier: Programming Language :: Python :: 3.9
21
21
  Classifier: Programming Language :: Python :: 3.10
22
22
  Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
23
26
  Classifier: Operating System :: OS Independent
24
27
  Classifier: Topic :: Scientific/Engineering :: Mathematics
25
28
  Requires-Python: >=3.7
26
29
  Description-Content-Type: text/markdown
27
30
  License-File: LICENSE.txt
28
31
  Requires-Dist: numpy
32
+ Dynamic: license-file
29
33
 
30
34
  ``kap``: $k$-Assignment Problem Solver
31
35
  ======
32
- [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt)
36
+ [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt) [![DOI](https://zenodo.org/badge/731651337.svg)](https://zenodo.org/doi/10.5281/zenodo.10449790)
33
37
 
34
38
  This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for solving the **$k$-Assignment Problem**
35
39
  (or **$k$-Partite Graph Matching Problem**), described in [this paper](https://www.mdpi.com/2227-7390/8/11/2050).
@@ -43,7 +47,7 @@ This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for
43
47
  It is also traditionally referred to as **Multidimensional Assignment Problem**.
44
48
 
45
49
  <p align="center">
46
- <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.png" width="300">
50
+ <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.svg" width="300">
47
51
  </p>
48
52
 
49
53
  Formally, we seek a $k$-assignment of a given $k$-partite weighted graph $G = (V, E, \omega)$ with the minimum weight:
@@ -177,6 +181,21 @@ print("Total cost:", sum(matching_result.matching_costs))
177
181
 
178
182
  These code blocks are extracted from [examples](examples).
179
183
 
184
+ ## Citation
185
+
186
+ ```bibtex
187
+ @software{inspiros_2024_10449791,
188
+ author = {Hoang-Nhat Tran},
189
+ title = {inspiros/kap: v0.2.1},
190
+ month = jan,
191
+ year = 2024,
192
+ publisher = {Zenodo},
193
+ version = {v0.2.1},
194
+ doi = {10.5281/zenodo.10449791},
195
+ url = {https://doi.org/10.5281/zenodo.10449791}
196
+ }
197
+ ```
198
+
180
199
  ## License
181
200
 
182
201
  MIT licensed. See [LICENSE.txt](LICENSE.txt).
@@ -1,6 +1,6 @@
1
1
  ``kap``: $k$-Assignment Problem Solver
2
2
  ======
3
- [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt)
3
+ [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt) [![DOI](https://zenodo.org/badge/731651337.svg)](https://zenodo.org/doi/10.5281/zenodo.10449790)
4
4
 
5
5
  This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for solving the **$k$-Assignment Problem**
6
6
  (or **$k$-Partite Graph Matching Problem**), described in [this paper](https://www.mdpi.com/2227-7390/8/11/2050).
@@ -14,7 +14,7 @@ This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for
14
14
  It is also traditionally referred to as **Multidimensional Assignment Problem**.
15
15
 
16
16
  <p align="center">
17
- <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.png" width="300">
17
+ <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.svg" width="300">
18
18
  </p>
19
19
 
20
20
  Formally, we seek a $k$-assignment of a given $k$-partite weighted graph $G = (V, E, \omega)$ with the minimum weight:
@@ -148,6 +148,21 @@ print("Total cost:", sum(matching_result.matching_costs))
148
148
 
149
149
  These code blocks are extracted from [examples](examples).
150
150
 
151
+ ## Citation
152
+
153
+ ```bibtex
154
+ @software{inspiros_2024_10449791,
155
+ author = {Hoang-Nhat Tran},
156
+ title = {inspiros/kap: v0.2.1},
157
+ month = jan,
158
+ year = 2024,
159
+ publisher = {Zenodo},
160
+ version = {v0.2.1},
161
+ doi = {10.5281/zenodo.10449791},
162
+ url = {https://doi.org/10.5281/zenodo.10449791}
163
+ }
164
+ ```
165
+
151
166
  ## License
152
167
 
153
168
  MIT licensed. See [LICENSE.txt](LICENSE.txt).
@@ -0,0 +1 @@
1
+ __version__ = '0.2.2'
@@ -182,7 +182,7 @@ class KPartiteGraph:
182
182
  cost_ij[:, n_matches_12 + n_free_1:] = cost_i2[:, free_2]
183
183
  quotient_cost_matrices.append(cost_ij)
184
184
  else:
185
- quotient_cost_matrices.append(self[i, j].clone())
185
+ quotient_cost_matrices.append(self[i, j].copy())
186
186
 
187
187
  quotient_node_indices = KPartiteNamedNodeList()
188
188
  for i in range(self.n_partites - 1):
@@ -486,7 +486,8 @@ def _Em_loop(G: KPartiteGraph,
486
486
  first_partite_pair: Tuple[int, int],
487
487
  maximize: bool = False,
488
488
  max_iter: int = 100,
489
- backend: str = "scipy") -> Tuple[KPartiteGraph, float]:
489
+ backend: str = "scipy",
490
+ random_state: np.random.RandomState = np.random.RandomState()) -> Tuple[KPartiteGraph, float]:
490
491
  best_Gq = G_init
491
492
  best_score = G_init.vertices_cost()
492
493
  best_vertices = G_init.vertices()
@@ -495,8 +496,8 @@ def _Em_loop(G: KPartiteGraph,
495
496
  # undeterministic steepest descent
496
497
  for iteration in range(max_iter):
497
498
  improvement_achieved = False
498
- for p1, p2 in np.random.permutation(list(filter(lambda _: _ != best_first_partites_pair,
499
- itertools.combinations(range(G.n_partites), r=2)))):
499
+ for p1, p2 in random_state.permutation(list(filter(lambda _: _ != best_first_partites_pair,
500
+ itertools.combinations(range(G.n_partites), r=2)))):
500
501
  fixed_vertices = list(filter(lambda _: (_[0][0], _[1][0]) == (p1, p2), best_vertices))
501
502
  M = [[_[0][1], _[1][1]] for _ in fixed_vertices]
502
503
  Gq = G.quotient(p1, p2, M)
@@ -521,11 +522,14 @@ def solve_Em(G: KPartiteGraph,
521
522
  maximize: bool = False,
522
523
  max_iter: int = 100,
523
524
  n_trials: int = 1,
524
- backend: str = "scipy") -> KPartiteGraph:
525
+ backend: str = "scipy",
526
+ random_state: Optional[Union[np.random.RandomState, int]] = None) -> KPartiteGraph:
525
527
  if max_iter <= 0:
526
528
  raise ValueError(f"max_iter must be a positive integer. Got {max_iter}.")
527
529
  if n_trials <= 0:
528
530
  raise ValueError(f"n_trials must be a positive integer. Got {n_trials}.")
531
+ if not isinstance(random_state, np.random.RandomState):
532
+ random_state = np.random.RandomState(random_state)
529
533
 
530
534
  # init with Bm
531
535
  Gq, choices = solve_Bm(G, maximize,
@@ -537,7 +541,7 @@ def solve_Em(G: KPartiteGraph,
537
541
 
538
542
  for ti in range(n_trials):
539
543
  Gq, score = _Em_loop(G, Gq, best_first_partites_pair, maximize, max_iter,
540
- backend=backend)
544
+ backend=backend, random_state=random_state)
541
545
  if (score < best_score and not maximize) or (score > best_score and maximize):
542
546
  best_Gq = Gq
543
547
  best_score = score
@@ -548,9 +552,12 @@ def solve_Em(G: KPartiteGraph,
548
552
  def solve_Fm(G: KPartiteGraph,
549
553
  maximize: bool = False,
550
554
  max_iter: int = 100,
551
- backend: str = "scipy") -> KPartiteGraph:
555
+ backend: str = "scipy",
556
+ random_state: Optional[Union[np.random.RandomState, int]] = None) -> KPartiteGraph:
552
557
  if max_iter <= 0:
553
558
  raise ValueError(f"max_iter must be a positive integer. Got {max_iter}.")
559
+ if not isinstance(random_state, np.random.RandomState):
560
+ random_state = np.random.RandomState(random_state)
554
561
 
555
562
  # init with Bm
556
563
  Gq, choices = solve_Bm(G, maximize,
@@ -566,7 +573,7 @@ def solve_Fm(G: KPartiteGraph,
566
573
  for iteration in range(max_iter):
567
574
  improvement_achieved = False
568
575
 
569
- rand_ind = np.random.randint(0, len(best_Gq_list))
576
+ rand_ind = random_state.randint(0, len(best_Gq_list))
570
577
  best_Gq = best_Gq_list[rand_ind]
571
578
  best_edges = best_edges_list[rand_ind]
572
579
  best_first_partites_pair = best_first_partites_pair_list[rand_ind]
@@ -597,7 +604,7 @@ def solve_Fm(G: KPartiteGraph,
597
604
  if not improvement_achieved:
598
605
  break
599
606
  if len(best_Gq_list):
600
- rand_ind = np.random.randint(0, len(best_Gq_list))
607
+ rand_ind = random_state.randint(0, len(best_Gq_list))
601
608
  best_Gq = best_Gq_list[rand_ind]
602
609
  return best_Gq
603
610
 
@@ -608,7 +615,8 @@ def k_assignment(cost_matrices: Sequence[Array2DLike],
608
615
  n_trials: int = 1,
609
616
  maximize: bool = False,
610
617
  return_free: bool = False,
611
- backend: str = "scipy") -> AssignmentResult:
618
+ backend: str = "scipy",
619
+ random_state: Optional[Union[np.random.RandomState, int]] = None) -> AssignmentResult:
612
620
  r"""
613
621
  Solve the k-Assignment Problem using Gabrovšek's multiple Hungarian methods,
614
622
  described in ref. [1]_. This function call the Linear Assignment Problem solver
@@ -630,6 +638,10 @@ def k_assignment(cost_matrices: Sequence[Array2DLike],
630
638
  backend (str): The backend used to solve the linear assignment problem.
631
639
  Supported backends are "scipy", "lap", "lapjv", "lapsolver", "munkres".
632
640
  Defaults to "scipy".
641
+ random_state (RandomState, int, optional): Controls the pseudo random
642
+ number generation for shuffling or choosing random partites pair in
643
+ Em and Fm algorithms. Pass an int for reproducible output across
644
+ multiple function calls. Defaults to None.
633
645
 
634
646
  Returns:
635
647
  matching_results: A namedtuple of ``matches``, ``matching_costs``,
@@ -688,11 +700,11 @@ def k_assignment(cost_matrices: Sequence[Array2DLike],
688
700
  return Gq.reconstruct(return_free=return_free)
689
701
  elif algo == "e":
690
702
  Gq = solve_Em(G, maximize, max_iter, n_trials,
691
- backend=backend)
703
+ backend=backend, random_state=random_state)
692
704
  return Gq.reconstruct(return_free=return_free)
693
705
  elif algo == "f":
694
706
  Gq = solve_Fm(G, maximize, max_iter,
695
- backend=backend)
707
+ backend=backend, random_state=random_state)
696
708
  return Gq.reconstruct(return_free=return_free)
697
709
  else:
698
710
  raise ValueError("algo must be either Am | Bm | Cm | Dm | Em | Fm "
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: kap
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Gabrovšek's Multiple Hungarian method for solving k-Assignment Problem.
5
5
  Home-page: https://github.com/inspiros/kap
6
6
  Author: Hoang-Nhat Tran (inspiros)
@@ -20,16 +20,20 @@ Classifier: Programming Language :: Python :: 3.8
20
20
  Classifier: Programming Language :: Python :: 3.9
21
21
  Classifier: Programming Language :: Python :: 3.10
22
22
  Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
23
26
  Classifier: Operating System :: OS Independent
24
27
  Classifier: Topic :: Scientific/Engineering :: Mathematics
25
28
  Requires-Python: >=3.7
26
29
  Description-Content-Type: text/markdown
27
30
  License-File: LICENSE.txt
28
31
  Requires-Dist: numpy
32
+ Dynamic: license-file
29
33
 
30
34
  ``kap``: $k$-Assignment Problem Solver
31
35
  ======
32
- [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt)
36
+ [![Build wheels](https://github.com/inspiros/kap/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/inspiros/kap/actions) [![PyPI](https://img.shields.io/pypi/v/kap)](https://pypi.org/project/kap) [![Downloads](https://static.pepy.tech/badge/kap)](https://pepy.tech/project/kap) [![License](https://img.shields.io/github/license/inspiros/kap)](https://github.com/inspiros/kap/blob/master/LICENSE.txt) [![DOI](https://zenodo.org/badge/731651337.svg)](https://zenodo.org/doi/10.5281/zenodo.10449790)
33
37
 
34
38
  This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for solving the **$k$-Assignment Problem**
35
39
  (or **$k$-Partite Graph Matching Problem**), described in [this paper](https://www.mdpi.com/2227-7390/8/11/2050).
@@ -43,7 +47,7 @@ This project implements **Boštjan Gabrovšek**'s Multiple Hungarian Methods for
43
47
  It is also traditionally referred to as **Multidimensional Assignment Problem**.
44
48
 
45
49
  <p align="center">
46
- <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.png" width="300">
50
+ <img src="https://raw.githubusercontent.com/inspiros/kap/master/resources/tripartite_matching_example.svg" width="300">
47
51
  </p>
48
52
 
49
53
  Formally, we seek a $k$-assignment of a given $k$-partite weighted graph $G = (V, E, \omega)$ with the minimum weight:
@@ -177,6 +181,21 @@ print("Total cost:", sum(matching_result.matching_costs))
177
181
 
178
182
  These code blocks are extracted from [examples](examples).
179
183
 
184
+ ## Citation
185
+
186
+ ```bibtex
187
+ @software{inspiros_2024_10449791,
188
+ author = {Hoang-Nhat Tran},
189
+ title = {inspiros/kap: v0.2.1},
190
+ month = jan,
191
+ year = 2024,
192
+ publisher = {Zenodo},
193
+ version = {v0.2.1},
194
+ doi = {10.5281/zenodo.10449791},
195
+ url = {https://doi.org/10.5281/zenodo.10449791}
196
+ }
197
+ ```
198
+
180
199
  ## License
181
200
 
182
201
  MIT licensed. See [LICENSE.txt](LICENSE.txt).
@@ -24,6 +24,9 @@ classifiers =
24
24
  Programming Language :: Python :: 3.9
25
25
  Programming Language :: Python :: 3.10
26
26
  Programming Language :: Python :: 3.11
27
+ Programming Language :: Python :: 3.12
28
+ Programming Language :: Python :: 3.13
29
+ Programming Language :: Python :: 3.14
27
30
  Operating System :: OS Independent
28
31
  Topic :: Scientific/Engineering :: Mathematics
29
32
  keywords = k-assignment, k-partite-matching, linear-assignment, bi-partite-matching, hungarian
kap-0.2.0/kap/_version.py DELETED
@@ -1 +0,0 @@
1
- __version__ = '0.2.0'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes