ascent-science-aco 0.1.0__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.
- ascent_science_aco-0.1.0/PKG-INFO +13 -0
- ascent_science_aco-0.1.0/README.md +4 -0
- ascent_science_aco-0.1.0/pyproject.toml +19 -0
- ascent_science_aco-0.1.0/setup.cfg +4 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco/__init__.py +163 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/PKG-INFO +13 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/SOURCES.txt +9 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/dependency_links.txt +1 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/entry_points.txt +2 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/requires.txt +1 -0
- ascent_science_aco-0.1.0/src/ascent_science_aco.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ascent-science-aco
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ant colony optimizer plugin for Ascent Science SDK
|
|
5
|
+
License-Expression: LicenseRef-Proprietary
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: ascent-science<0.10,>=0.9
|
|
9
|
+
|
|
10
|
+
# Ascent Science ACO plugin
|
|
11
|
+
|
|
12
|
+
Install with `python -m pip install ascent-science-aco`, then use
|
|
13
|
+
`ascent.combinatorial.ACOOptimizer(...)`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ascent-science-aco"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Ant colony optimizer plugin for Ascent Science SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "LicenseRef-Proprietary"
|
|
12
|
+
dependencies = ["ascent-science>=0.9,<0.10"]
|
|
13
|
+
|
|
14
|
+
[project.entry-points."ascent.algorithms"]
|
|
15
|
+
aco = "ascent_science_aco:register"
|
|
16
|
+
|
|
17
|
+
[tool.setuptools.packages.find]
|
|
18
|
+
where = ["src"]
|
|
19
|
+
include = ["ascent_science_aco*"]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Ant colony optimization plugin for Ascent Science."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
import random
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import asdict, dataclass
|
|
9
|
+
|
|
10
|
+
from ascent.core import AlgorithmSpec
|
|
11
|
+
from ascent.plugin_api import register_algorithm, square_matrix, tracked, validated_license
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class ACOResult:
|
|
18
|
+
best_route: list[int]
|
|
19
|
+
best_distance: float
|
|
20
|
+
history: list[float]
|
|
21
|
+
iterations: int
|
|
22
|
+
runtime_seconds: float
|
|
23
|
+
solver_name: str = "ACOOptimizer"
|
|
24
|
+
solver_version: str = "ascent-science-aco 0.1.0"
|
|
25
|
+
execution_location: str = "local"
|
|
26
|
+
status: str = "FEASIBLE"
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def best_solution(self):
|
|
30
|
+
return self.best_route
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def best_value(self):
|
|
34
|
+
return self.best_distance
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def result(self):
|
|
38
|
+
return self.best_route
|
|
39
|
+
|
|
40
|
+
def to_dict(self):
|
|
41
|
+
return asdict(self)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ACOOptimizer:
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
*,
|
|
48
|
+
user_id=None,
|
|
49
|
+
sdk_code=None,
|
|
50
|
+
endpoint=None,
|
|
51
|
+
license_path=None,
|
|
52
|
+
timeout=30.0,
|
|
53
|
+
report_usage=True,
|
|
54
|
+
validation_mode="cached",
|
|
55
|
+
ants=30,
|
|
56
|
+
evaporation=0.5,
|
|
57
|
+
alpha=1.0,
|
|
58
|
+
beta=2.0,
|
|
59
|
+
deposit=100.0,
|
|
60
|
+
iterations=100,
|
|
61
|
+
seed=None,
|
|
62
|
+
):
|
|
63
|
+
self.endpoint, self.license_user_id, self._usage_reporter = validated_license(
|
|
64
|
+
endpoint, user_id, sdk_code, license_path, timeout, report_usage, validation_mode
|
|
65
|
+
)
|
|
66
|
+
self.ants = int(ants)
|
|
67
|
+
self.evaporation = float(evaporation)
|
|
68
|
+
self.alpha = float(alpha)
|
|
69
|
+
self.beta = float(beta)
|
|
70
|
+
self.deposit = float(deposit)
|
|
71
|
+
self.iterations = int(iterations)
|
|
72
|
+
self.seed = seed
|
|
73
|
+
if self.ants < 1 or self.iterations < 1:
|
|
74
|
+
raise ValueError("ants and iterations must be positive integers")
|
|
75
|
+
if not 0.0 < self.evaporation < 1.0:
|
|
76
|
+
raise ValueError("evaporation must be between 0 and 1")
|
|
77
|
+
if self.alpha < 0 or self.beta < 0 or self.deposit <= 0:
|
|
78
|
+
raise ValueError("alpha and beta cannot be negative; deposit must be positive")
|
|
79
|
+
|
|
80
|
+
def solve(self, distance_matrix, *, start_city=0, iterations=None, seed=None):
|
|
81
|
+
return self.solve_tsp(
|
|
82
|
+
distance_matrix, start_city=start_city, iterations=iterations, seed=seed
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@tracked("aco")
|
|
86
|
+
def solve_tsp(self, distance_matrix, *, start_city=0, iterations=None, seed=None):
|
|
87
|
+
matrix = square_matrix(distance_matrix, "distance_matrix")
|
|
88
|
+
size = len(matrix)
|
|
89
|
+
count = self.iterations if iterations is None else int(iterations)
|
|
90
|
+
if size < 2:
|
|
91
|
+
raise ValueError("distance_matrix must contain at least two cities")
|
|
92
|
+
if any(value < 0 for row in matrix for value in row):
|
|
93
|
+
raise ValueError("distance_matrix entries cannot be negative")
|
|
94
|
+
if not isinstance(start_city, int) or not 0 <= start_city < size:
|
|
95
|
+
raise ValueError("start_city must be a valid city index")
|
|
96
|
+
if count < 1:
|
|
97
|
+
raise ValueError("iterations must be a positive integer")
|
|
98
|
+
|
|
99
|
+
started = time.perf_counter()
|
|
100
|
+
rng = random.Random(self.seed if seed is None else seed)
|
|
101
|
+
pheromone = [[1.0] * size for _ in range(size)]
|
|
102
|
+
best_route, best_distance = None, math.inf
|
|
103
|
+
history = []
|
|
104
|
+
|
|
105
|
+
def construct_tour():
|
|
106
|
+
route = [start_city]
|
|
107
|
+
unvisited = set(range(size))
|
|
108
|
+
unvisited.remove(start_city)
|
|
109
|
+
while unvisited:
|
|
110
|
+
current = route[-1]
|
|
111
|
+
candidates = sorted(unvisited)
|
|
112
|
+
weights = [
|
|
113
|
+
pheromone[current][city] ** self.alpha
|
|
114
|
+
* (1.0 / max(matrix[current][city], 1e-12)) ** self.beta
|
|
115
|
+
for city in candidates
|
|
116
|
+
]
|
|
117
|
+
destination = rng.choices(candidates, weights=weights)[0]
|
|
118
|
+
route.append(destination)
|
|
119
|
+
unvisited.remove(destination)
|
|
120
|
+
route.append(start_city)
|
|
121
|
+
distance = sum(matrix[route[index]][route[index + 1]] for index in range(size))
|
|
122
|
+
return route, distance
|
|
123
|
+
|
|
124
|
+
for _ in range(count):
|
|
125
|
+
tours = [construct_tour() for _ in range(self.ants)]
|
|
126
|
+
for route, distance in tours:
|
|
127
|
+
if distance < best_distance:
|
|
128
|
+
best_route, best_distance = list(route), distance
|
|
129
|
+
for source in range(size):
|
|
130
|
+
for destination in range(size):
|
|
131
|
+
pheromone[source][destination] *= 1.0 - self.evaporation
|
|
132
|
+
for route, distance in tours:
|
|
133
|
+
reward = self.deposit / max(distance, 1e-12)
|
|
134
|
+
for index in range(size):
|
|
135
|
+
pheromone[route[index]][route[index + 1]] += reward
|
|
136
|
+
history.append(float(best_distance))
|
|
137
|
+
|
|
138
|
+
return ACOResult(
|
|
139
|
+
best_route=best_route or [start_city, start_city],
|
|
140
|
+
best_distance=float(best_distance),
|
|
141
|
+
history=history,
|
|
142
|
+
iterations=count,
|
|
143
|
+
runtime_seconds=time.perf_counter() - started,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def register():
|
|
148
|
+
return register_algorithm(
|
|
149
|
+
category="combinatorial",
|
|
150
|
+
exports={"ACOOptimizer": ACOOptimizer, "ACOResult": ACOResult},
|
|
151
|
+
specification=AlgorithmSpec(
|
|
152
|
+
name="aco",
|
|
153
|
+
family="metaheuristic",
|
|
154
|
+
problem_types=("tsp",),
|
|
155
|
+
input_kind="distance_matrix",
|
|
156
|
+
output_kind="route",
|
|
157
|
+
factory=ACOOptimizer,
|
|
158
|
+
description="Ant colony optimization for travelling-salesperson problems.",
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
__all__ = ["ACOOptimizer", "ACOResult", "register"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ascent-science-aco
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ant colony optimizer plugin for Ascent Science SDK
|
|
5
|
+
License-Expression: LicenseRef-Proprietary
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: ascent-science<0.10,>=0.9
|
|
9
|
+
|
|
10
|
+
# Ascent Science ACO plugin
|
|
11
|
+
|
|
12
|
+
Install with `python -m pip install ascent-science-aco`, then use
|
|
13
|
+
`ascent.combinatorial.ACOOptimizer(...)`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/ascent_science_aco/__init__.py
|
|
4
|
+
src/ascent_science_aco.egg-info/PKG-INFO
|
|
5
|
+
src/ascent_science_aco.egg-info/SOURCES.txt
|
|
6
|
+
src/ascent_science_aco.egg-info/dependency_links.txt
|
|
7
|
+
src/ascent_science_aco.egg-info/entry_points.txt
|
|
8
|
+
src/ascent_science_aco.egg-info/requires.txt
|
|
9
|
+
src/ascent_science_aco.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ascent-science<0.10,>=0.9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ascent_science_aco
|