Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
jobs:
test:
name: test
runs-on: ubuntu-latest
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v4
Expand All @@ -31,6 +31,8 @@ jobs:
python -m pip install -r build-requirements.txt

- name: "Install pyvroom"
env:
CXX: g++-14
run: |
# Because `pip install -e .` does not play nice with gcov, we go old school:
CFLAGS="-coverage" python setup.py build_ext --inplace
Expand Down
24 changes: 15 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Check metadata
run: pipx run twine check dist/*

- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v4
with:
path: dist/*.tar.gz

Expand Down Expand Up @@ -78,25 +78,31 @@ jobs:
with:
platforms: all

- name: Set version
if: matrix.platform != 'macos-arm' && matrix.platform != 'macos-intel'
run: |
sed -i 's/^version = 0\.1\.0$/version = ${{ github.ref_name }}/' setup.cfg

- name: Set version
if: matrix.platform == 'macos-arm' || matrix.platform == 'macos-intel'
run: |
sed -i "" 's/^version = 0\.1\.0$/version = ${{ github.ref_name }}/' setup.cfg

- name: Build wheels
if: matrix.platform != 'macos-arm'
uses: pypa/cibuildwheel@v2.19.2
env:
MACOSX_DEPLOYMENT_TARGET: 13.0
CC: gcc-13
CXX: g++-13
CC: gcc-14
CXX: g++-14

- name: Build wheels
if: matrix.platform == 'macos-arm'
uses: pypa/cibuildwheel@v2.19.2
env:
MACOSX_DEPLOYMENT_TARGET: 14.0
CC: gcc-13
CXX: g++-13

- name: Verify clean directory
run: git diff --exit-code
shell: bash
CC: gcc-14
CXX: g++-14

- name: Upload wheels
uses: actions/upload-artifact@v3
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Usage with a routing engine

>>> sol = problem_instance.solve(exploration_level=5, nb_threads=4)
>>> print(sol.summary.duration)
2714
4041

Installation
------------
Expand Down
2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
requires = [
"setuptools>=45",
"wheel",
"setuptools_scm>=6.2",
"setuptools_scm_git_archive",
"pybind11>=2.8.0",
]

Expand Down
6 changes: 3 additions & 3 deletions src/_vroom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#include "structures/typedefs.h"

#include "structures/generic/edge.cpp"
#include "structures/generic/matrix.cpp"
#include "structures/generic/matrix.h"
#include "structures/generic/undirected_graph.cpp"

#include "structures/vroom/cost_wrapper.cpp"
Expand Down Expand Up @@ -137,8 +137,8 @@
.def(py::init<vroom::HEURISTIC, vroom::INIT, float>());

py::class_<vroom::Server>(m, "Server")
.def(py::init<std::string &, std::string &>(),
py::arg("host") = "0.0.0.0", py::arg("port") = "5000");
.def(py::init<std::string &, std::string &, std::string &>(),
py::arg("host") = "0.0.0.0", py::arg("port") = "5000", py::arg("path") = "");

Check warning on line 141 in src/_vroom.cpp

View check run for this annotation

Codecov / codecov/patch

src/_vroom.cpp#L141

Added line #L141 was not covered by tests

py::class_<vroom::Violations>(m, "Violations")
.def(py::init<>())
Expand Down
1 change: 0 additions & 1 deletion src/bind/enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ void init_enums(py::module_ &m) {
py::enum_<vroom::HEURISTIC>(m, "HEURISTIC")
.value("BASIC", vroom::HEURISTIC::BASIC)
.value("DYNAMIC", vroom::HEURISTIC::DYNAMIC)
.value("INIT_ROUTES", vroom::HEURISTIC::INIT_ROUTES)
.export_values();

py::enum_<vroom::INIT>(m, "INIT")
Expand Down
23 changes: 13 additions & 10 deletions src/bind/input/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <map>

#include <pybind11/operators.h>
#include <pybind11/chrono.h>

#include "structures/cl_args.cpp"
#include "structures/vroom/input/input.cpp"
Expand All @@ -13,17 +14,17 @@

py::class_<vroom::Input>(m, "Input")
.def(
py::init([](const vroom::io::Servers &servers, vroom::ROUTER router) {
return new vroom::Input(servers, router);
py::init([](const vroom::io::Servers &servers, vroom::ROUTER router, bool apply_TSPFix) {
return new vroom::Input(servers, router, apply_TSPFix);

Check warning on line 18 in src/bind/input/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/input/input.cpp#L17-L18

Added lines #L17 - L18 were not covered by tests
}),
"Class initializer.",
py::arg("servers") = std::map<std::string, vroom::io::Servers>(),
py::arg("router") = vroom::ROUTER::OSRM)
py::arg("router") = vroom::ROUTER::OSRM,
py::arg("apply_TSPFix") = false)

Check warning on line 23 in src/bind/input/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/input/input.cpp#L22-L23

Added lines #L22 - L23 were not covered by tests
.def_readonly("jobs", &vroom::Input::jobs)
.def_readonly("vehicles", &vroom::Input::vehicles)
.def("_from_json", &vroom::io::parse, py::arg("json_string"),
py::arg("geometry"))
.def("_set_amount_size", &vroom::Input::set_amount_size)
.def("_set_geometry", &vroom::Input::set_geometry)
.def("_add_job", &vroom::Input::add_job)
.def("_add_shipment", &vroom::Input::add_shipment)
Expand All @@ -43,18 +44,20 @@
vroom::Matrix<vroom::UserCost> &m) {
self.set_costs_matrix(profile, std::move(m));
})
.def("zero_amount", &vroom::Input::zero_amount)
.def("has_skills", &vroom::Input::has_skills)
.def("has_jobs", &vroom::Input::has_jobs)
.def("has_shipments", &vroom::Input::has_shipments)
.def("get_cost_upper_bound", &vroom::Input::get_cost_upper_bound)
.def("has_homogeneous_locations",
&vroom::Input::has_homogeneous_locations)
.def("has_homogeneous_profiles", &vroom::Input::has_homogeneous_profiles)
// .def("vehicle_ok_with_job", &vroom::Input::vehicle_ok_with_job)
.def("_solve", &vroom::Input::solve, "Solve problem.",
py::arg("exploration_level"), py::arg("nb_threads") = 1,
py::arg("timeout") = vroom::Timeout(),
py::arg("h_param") = std::vector<vroom::HeuristicParameters>())
.def("has_homogeneous_costs", &vroom::Input::has_homogeneous_costs)
.def("_solve",
[](vroom::Input &self, unsigned exploration_level, unsigned nb_threads, const vroom::Timeout& timeout, const std::vector<vroom::HeuristicParameters> h_param) {
return self.solve(exploration_level, nb_threads, timeout, h_param);

Check warning on line 57 in src/bind/input/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/input/input.cpp#L54-L57

Added lines #L54 - L57 were not covered by tests
},
"Solve routing problem",
py::arg("exploration_level"), py::arg("nb_threads"), py::arg("timeout"), py::arg("h_param")
)

Check warning on line 61 in src/bind/input/input.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/input/input.cpp#L61

Added line #L61 was not covered by tests
.def("check", &vroom::Input::check);
}
7 changes: 4 additions & 3 deletions src/bind/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
void init_vehicle(py::module_ &m) {

py::class_<vroom::VehicleCosts>(m, "VehicleCosts")
.def(py::init<vroom::UserCost, vroom::UserCost>(),
.def(py::init<vroom::UserCost, vroom::UserCost, vroom::UserCost>(),
"VehicleCost constructor.", py::arg("fixed") = 0,
py::arg("per_hour") = 3600)
py::arg("per_hour") = 3600, py::arg("per_km") = 0)

Check warning on line 12 in src/bind/vehicle.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/vehicle.cpp#L12

Added line #L12 was not covered by tests
.def_readonly("_fixed", &vroom::VehicleCosts::fixed)
.def_readonly("_per_hour", &vroom::VehicleCosts::per_hour);
.def_readonly("_per_hour", &vroom::VehicleCosts::per_hour)
.def_readonly("_per_km", &vroom::VehicleCosts::per_km);

Check warning on line 15 in src/bind/vehicle.cpp

View check run for this annotation

Codecov / codecov/patch

src/bind/vehicle.cpp#L14-L15

Added lines #L14 - L15 were not covered by tests

py::class_<vroom::CostWrapper>(m, "CostWrapper")
.def(py::init<double, vroom::Cost, vroom::Cost>(),
Expand Down
67 changes: 35 additions & 32 deletions src/vroom/input/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations
from typing import Dict, Optional, Sequence, Set, Union
from pathlib import Path
from datetime import timedelta

from numpy.typing import ArrayLike
import numpy
Expand Down Expand Up @@ -35,16 +36,14 @@

def __init__(
self,
amount_size: Optional[int] = None,
servers: Optional[Dict[str, Union[str, _vroom.Server]]] = None,
router: _vroom.ROUTER = _vroom.ROUTER.OSRM,
apply_TSPFix: bool = False,
geometry: bool = False,
) -> None:
"""Class initializer.

Args:
amount_size:
The size of the job to be transported. Used to verify all jobs
have the same size limit.
servers:
Assuming no custom duration matrix is provided (from
`set_durations_matrix`), use this dict to configure the
Expand All @@ -53,24 +52,30 @@
router:
If servers is used, define what kind of server is provided.
See `vroom.ROUTER` enum for options.
apply_TSPFix:
Experimental local search operator.
geometry:
Add detailed route geometry and distance.
"""
if servers is None:
servers = {}
for key, server in servers.items():
if isinstance(server, str):
servers[key] = _vroom.Server(*server.split(":"))
self._amount_size = amount_size
self._servers = servers
self._router = router
_vroom.Input.__init__(self, servers=servers, router=router)
if amount_size is not None:
self._set_amount_size(amount_size)
_vroom.Input.__init__(
self,
servers=servers,
router=router,
apply_TSPFix=apply_TSPFix,
)
if geometry:
self.set_geometry()

Check warning on line 74 in src/vroom/input/input.py

View check run for this annotation

Codecov / codecov/patch

src/vroom/input/input.py#L74

Added line #L74 was not covered by tests

def __repr__(self) -> str:
"""String representation."""
args = []
if self._amount_size is not None:
args.append(f"amount_size={self._amount_size}")
if self._servers:
args.append(f"servers={self._servers}")
if self._router != _vroom.ROUTER.OSRM:
Expand Down Expand Up @@ -117,21 +122,10 @@
return instance

def set_geometry(self):
"""Add detailed route geometry and distance."""
self._geometry = True
return self._set_geometry(True)

def set_amount_size(self, *amount_sizes: int) -> None:
"""Add amount sizes."""
sizes = set(amount_sizes)
if self._amount_size is not None:
sizes.add(self._amount_size)
if len(sizes) > 1:
raise _vroom.VroomInputException(f"Inconsistent capacity lengths: {sizes}")
if self._amount_size is None:
size = sizes.pop()
self._amount_size = size
self._set_amount_size(size)

def add_job(
self,
job: Union[Job, Shipment, Sequence[Job], Sequence[Shipment]],
Expand All @@ -157,14 +151,9 @@
jobs = [job] if isinstance(job, (Job, Shipment)) else job
for job_ in jobs:
if isinstance(job_, Job):
if job_._pickup:
self.set_amount_size(len(job_._pickup))
if job_._delivery:
self.set_amount_size(len(job_._delivery))
self._add_job(job_)

elif isinstance(job_, Shipment):
self.set_amount_size(len(job_.amount))
self._add_shipment(
_vroom.Job(
id=job_.pickup.id,
Expand Down Expand Up @@ -221,7 +210,6 @@
The job priority level, where 0 is the most
important and 100 is the least important.
"""
self.set_amount_size(len(amount))
if skills is None:
skills = set()
self._add_shipment(
Expand Down Expand Up @@ -266,7 +254,6 @@
vehicles = [vehicle] if isinstance(vehicle, _vroom.Vehicle) else vehicle
if not vehicles:
return
self.set_amount_size(*[len(vehicle_.capacity) for vehicle_ in vehicles])
for vehicle_ in vehicles:
self._add_vehicle(vehicle_)

Expand Down Expand Up @@ -334,12 +321,28 @@
def solve(
self,
exploration_level: int,
nb_threads: int,
nb_threads: int = 4,
timeout: Optional[timedelta] = None,
h_param = (),
) -> Solution:
"""Solve routing problem.

Args:
exploration_level:
The exploration level to use. Number between 1 and 5.
nb_threads:
The number of available threads.
timeout:
Stop the solving process after a given amount of time.
"""
assert timeout is None or isinstance(timeout, (None, timedelta)), (
f"unknown timeout type: {timeout}")
solution = Solution(
self._solve(
exploration_level=exploration_level,
nb_threads=nb_threads,
exploration_level=int(exploration_level),
nb_threads=int(nb_threads),
timeout=timeout,
h_param=list(h_param),
)
)
solution._geometry = self._geometry
Expand Down
18 changes: 13 additions & 5 deletions src/vroom/vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,22 @@ class VehicleCosts(_vroom.VehicleCosts):
A fixed price for the vehicle to be utilized.
per_hour:
The price per hour to utilize the vehicle.
per_km:
The price per kilometer to utilize the vehicle.

Examples:
>>> vroom.VehicleCosts()
VehicleCosts()
>>> vroom.VehicleCosts(fixed=100, per_hour=50)
VehicleCosts(fixed=100, per_hour=50)
>>> vroom.VehicleCosts(fixed=100, per_hour=50, per_km=25)
VehicleCosts(fixed=100, per_hour=50, per_km=25)
"""

def __init__(self, fixed: int = 0, per_hour: int = 3600):
def __init__(self, fixed: int = 0, per_hour: int = 3600, per_km: int = 0):
_vroom.VehicleCosts.__init__(
self,
fixed=int(fixed),
per_hour=int(per_hour),
per_km=int(per_km),
)

@property
Expand All @@ -47,11 +50,15 @@ def fixed(self) -> int:
def per_hour(self) -> int:
return self._per_hour

@property
def per_km(self) -> int:
return self._per_km

def __bool__(self) -> bool:
return self.fixed != 0 or self.per_hour != 3600
return self.fixed != 0 or self.per_hour != 3600 or self.per_km != 0

def __repr__(self):
args = f"fixed={self.fixed}, per_hour={self.per_hour}" if self else ""
args = f"fixed={self.fixed}, per_hour={self.per_hour}, per_km={self.per_km}" if self else ""
return f"{self.__class__.__name__}({args})"


Expand Down Expand Up @@ -231,6 +238,7 @@ def costs(self) -> VehicleCosts:
return VehicleCosts(
fixed=self._costs._fixed,
per_hour=self._costs._per_hour,
per_km=self._costs._per_km,
)

@property
Expand Down
2 changes: 1 addition & 1 deletion vroom
Submodule vroom updated 187 files
Loading