Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pip install #18

Closed
wants to merge 4 commits into from
Closed
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
37 changes: 20 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,26 @@ If you find VeRyPy useful in your research and use it to produce results for you

## Quick Start

Make sure that the VeRyPy is in your `PYTHONPATH`. On linux the relevant command is
```
$ export PYTHONPATH=$PYTHONPATH:/home/jussi/Projects/CVRP:/home/jussi/Projects/CVRP/VeRyPy
```
and on Windows
```
> set PYTHONPATH=%PYTHONPATH%;C:\users\jussi\Projects\CVRP;C:\users\jussi\Projects\CVRP\VeRyPy
Currently, VeRyPy supports up to Python 3.8.
To install this package:
```bash
git clone https://github.com/yorak/VeRyPy.git
cd VeRyPy
pip install -e .
```
Be sure to modify the paths as necessary.

The command line use of VeRyPy assumes TSPLIB formatted files (assuming VeRyPy is in your PYTHONPATH):
```bash
$ python -O VeRyPy.py -a all E-n51-k5.vrp
python -O VeRyPy.py -a all examples/E-n51-k5.vrp
```

> Note: running with `python -O` entirely disables `__debug__` and logging.

An an alternative way of using VeRyPy, this simple Python code illustrates the API usage:
```python
import cvrp_io
from classic_heuristics.parallel_savings import parallel_savings_init
from util import sol2routes
import verypy.cvrp_io as cvrp_io
from verypy.classic_heuristics.parallel_savings import parallel_savings_init
from verypy.util import sol2routes

E_n51_k5_path = r"E-n51-k5.vrp"

Expand All @@ -108,17 +106,22 @@ for route_idx, route in enumerate(sol2routes(solution)):
print("Route #%d : %s"%(route_idx+1, route))
```

or

```bash
python examples/single_solve_example.py
```

<!-- TODO: Make sure it works -->

<!-- TODO: A more comprehensive reference documentation can be found [here](/doc/). -->

For API use, be sure to set the `PYTHONPATH` correctly.

### Dependencies and Installation

VeRyPy requires Python 2.7, NumPy, and SciPy. However, it should be Python3 compatible and *seems* to work also on Python 3.8. For CLI use you also need `natsort` from PyPI and some algorithms have additional dependencies: [CMT79-2P](#CMT79-2P), [FR76-1PLT](#FR76-1PLT), [GM74-SwRI](#GM74-SwRI) and [WH72-SwLS](#WH72-SwLS) require `orderedset` from PyPI; [MJ76-INS](#MJ76-INS) needs `llist` from PyPI; and [FR76-1PLT](#FR76-1PLT) , [FG81-GAP](#FG81-GAP), and [DV89-MM](#DV89-MM) require Gurobi with `gurobipy`. By default [Be83-RFCS](#Be83-RFCS), [SG82-LR3OPT](#SG82-LR3OPT), and [Ty68-NN](#Ty68-NN) use [LKH](http://akira.ruc.dk/~keld/research/LKH/) to solve TSPs, but they can be configured to use any other TSP solver (such as the internal one) if these external executables are not available. Refer to [auxiliary documentation](LKH_install_notes.md) on how to compile LKH.
<!-- ### Dependencies and Installation -->
<!--
VeRyPy requires Python 2.7, NumPy, and SciPy. However, it should be Python3 compatible and *seems* to work also on Python 3.8. For CLI use you also need `natsort` from PyPI and some algorithms have additional dependencies: [CMT79-2P](#CMT79-2P), [FR76-1PLT](#FR76-1PLT), [GM74-SwRI](#GM74-SwRI) and [WH72-SwLS](#WH72-SwLS) require `orderedset` from PyPI; [MJ76-INS](#MJ76-INS) needs `llist` from PyPI; and [FR76-1PLT](#FR76-1PLT) , [FG81-GAP](#FG81-GAP), and [DV89-MM](#DV89-MM) require Gurobi with `gurobipy`. By default [Be83-RFCS](#Be83-RFCS), [SG82-LR3OPT](#SG82-LR3OPT), and [Ty68-NN](#Ty68-NN) use [LKH](http://akira.ruc.dk/~keld/research/LKH/) to solve TSPs, but they can be configured to use any other TSP solver (such as the internal one) if these external executables are not available. Refer to [auxiliary documentation](LKH_install_notes.md) on how to compile LKH. -->

Be sure to add the VeRyPy root folder to your `PYTHONPATH` environment variable.
<!-- Be sure to add the VeRyPy root folder to your `PYTHONPATH` environment variable. -->



Expand Down
53 changes: 27 additions & 26 deletions VeRyPy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
from collections import defaultdict
import numpy as np

import cvrp_io
import cvrp_ops
import shared_cli
import verypy.cvrp_io as cvrp_io
import verypy.cvrp_ops as cvrp_ops
import verypy.shared_cli as shared_cli
import verypy.classic_heuristics as classic_heuristics

from local_search import do_local_search
from local_search.intra_route_operators import do_2opt_move, do_3opt_move
from verypy.local_search import do_local_search
from verypy.local_search.intra_route_operators import do_2opt_move, do_3opt_move
#TODO: offer other LS ops?

__author__ = "Jussi Rasku"
Expand Down Expand Up @@ -126,97 +127,97 @@ def get_algorithms(names):
# import only those that are needed, when needed
if algo_name in ["ps", "all", "classical"]:
#"ps":"Clarke & Wright (1964) parallel savings heuristic",
from classic_heuristics.parallel_savings import get_ps_algorithm
from verypy.classic_heuristics.parallel_savings import get_ps_algorithm
algos.append( ("ps",)+get_ps_algorithm() )
if algo_name in ["ps2o", "all"]:
#"ps2o":"Robbins and Turner (1979) CAWLIP savings algorithm",
from classic_heuristics.cawlip_savings import get_ps2o_algorithm
from verypy.classic_heuristics.cawlip_savings import get_ps2o_algorithm
algos.append( ("ps2o",)+get_ps2o_algorithm() )
if algo_name in ["gpl", "all", "classical"]:
#"gpl":"Gaskell (1967) best of pi/lambda savings heuristic",
from classic_heuristics.gaskell_savings import get_gs_algorithm
from verypy.classic_heuristics.gaskell_savings import get_gs_algorithm
algos.append( ("gpl",)+get_gs_algorithm() )
if algo_name in[ "ss", "all", "classical"]:
#"ss":"Webb (1964) sequential savings algorithm"
from classic_heuristics.sequential_savings import get_ss_algorithm
from verypy.classic_heuristics.sequential_savings import get_ss_algorithm
algos.append( ("ss",)+get_ss_algorithm(lambda_multiplier=1.0) )
if algo_name in ["gps", "all", "classical"]:
#"gps":"Paessens (1988) parallel savings heuristic with generalized savings function and M4 strategy",
from classic_heuristics.paessens_savings import get_gps_algorithm
from verypy.classic_heuristics.paessens_savings import get_gps_algorithm
algos.append( ("gps",)+get_gps_algorithm() )
pass
if algo_name in ["ims", "all", "classical"]:
#"ims":"Holmes & Parker (1976) iterative parallel savings merge suppression heuristic",
from classic_heuristics.suppression_savings import get_ims_algorithm
from verypy.classic_heuristics.suppression_savings import get_ims_algorithm
algos.append( ("ims",)+get_ims_algorithm() )
if algo_name in ["si", "all"]:
#"si":"Mole & Jameson (1976) sequential insertion heuristic without local search"),
from classic_heuristics.cheapest_insertion import get_si_algorithm
from verypy.classic_heuristics.cheapest_insertion import get_si_algorithm
algos.append( ("si",)+get_si_algorithm() )
if algo_name in ["mj", "all", "classical"]:
#"mj":"Mole & Jameson (1976) sequential insertion heuristic with local search"),
from classic_heuristics.mole_jameson_insertion import get_mj_algorithm
from verypy.classic_heuristics.mole_jameson_insertion import get_mj_algorithm
algos.append( ("mj",)+get_mj_algorithm() )
if algo_name in ["pi", "all"]:
#"pi":"van Breedam (1995) parallel insertion heuristic"),
from classic_heuristics.cheapest_insertion import get_pi_algorithm
from verypy.classic_heuristics.cheapest_insertion import get_pi_algorithm
algos.append( ("pi",)+get_pi_algorithm() )
if algo_name in ["mbsa", "all", "classical"]:
if not has_gurobi:
print("WARNING: [mbsa/DV89-MM] heuristic is not available (gurobipy is not installed).", file=sys.stderr)
else:
#"mbsa":"Desrochers and Verhoog (1989) matching based savings algorithm"
from classic_heuristics.matchingvrp import get_mm_algorithm
from verypy.classic_heuristics.matchingvrp import get_mm_algorithm
algos.append( ("mbsa",)+get_mm_algorithm())
if algo_name in ["cmt", "all", "classical"]:
#"cmt":"Christofides, Mingozzi & Toth (1979) two phase heuristic"
from classic_heuristics.cmt_2phase import get_cmt2p_algorithm
from verypy.classic_heuristics.cmt_2phase import get_cmt2p_algorithm
algos.append( ("cmt",)+get_cmt2p_algorithm() )
if algo_name in ["sn", "all"]:
#"sn":"Sequential Nearest Neighbor construction heuristic"
from classic_heuristics.nearest_neighbor import get_snn_algorithm
from verypy.classic_heuristics.nearest_neighbor import get_snn_algorithm
algos.append( ("sn",)+get_snn_algorithm() )
if algo_name in ["pn", "all"]:
#"pn":"Parallel Nearest Neighbor construction heuristic"
from classic_heuristics.nearest_neighbor import get_pnn_algorithm
from verypy.classic_heuristics.nearest_neighbor import get_pnn_algorithm
algos.append( ("pn",)+get_pnn_algorithm() )
if algo_name in ["ty", "all", "classical"]:
#"ty":"Tyagi (1968) Nearest Neighbor construction heuristic"
from classic_heuristics.tyagi_nearest_neighbor import get_ty_algorithm
from verypy.classic_heuristics.tyagi_nearest_neighbor import get_ty_algorithm
algos.append( ("ty",)+get_ty_algorithm() )
if algo_name in ["swp", "all"]:
#"swp":"Plain Sweep algorithm without route improvement heuristics"
from classic_heuristics.sweep import get_swp_algorithm
from verypy.classic_heuristics.sweep import get_swp_algorithm
algos.append( ("swp",)+get_swp_algorithm() )
if algo_name in ["wh", "all", "classical"]:
#"wh":"Wren and Holliday (1972) Sweep + Local Search algorithm"
from classic_heuristics.wren_holliday_sweep import get_wh_algorithm
from verypy.classic_heuristics.wren_holliday_sweep import get_wh_algorithm
algos.append( ("wh",)+get_wh_algorithm() )
if algo_name in ["gm", "all", "classical"]:
#"gm":"Gillett and Miller (1974) Sweep algorithm"
from classic_heuristics.gillet_miller_sweep import get_gm_algorithm
from verypy.classic_heuristics.gillet_miller_sweep import get_gm_algorithm
algos.append( ("gm",)+get_gm_algorithm() )
if algo_name in ["rfcs", "all", "classical"]:
#"rfcs":"Route-first-cluster-second heuristic of Beasley (1983)"
from classic_heuristics.rfcs import get_rfcs_algorithm
from verypy.classic_heuristics.rfcs import get_rfcs_algorithm
algos.append( ("rfcs",)+get_rfcs_algorithm())
if algo_name in ["gap", "all", "classical"]:
if not has_gurobi:
print("WARNING: [gap/FJ81-GAP] heuristic is not available (gurobipy is not installed).", file=sys.stderr)
else:
#"gap":"Fisher & Jaikumar (1981) generalized assignment problem heuristic"
from classic_heuristics.gapvrp import get_gap_algorithm
from verypy.classic_heuristics.gapvrp import get_gap_algorithm
algos.append( ("gap",)+get_gap_algorithm() )
if algo_name in ["ptl", "all", "classical"]:
if not has_gurobi:
print("WARNING: [ptl/FR76-1PTL] heuristic is not available (gurobipy is not installed).", file=sys.stderr)
else:
#"ptl":"Foster and Ryan (1976) Petal algorithm"
from classic_heuristics.petalvrp import get_ptl_algorithm
from verypy.classic_heuristics.petalvrp import get_ptl_algorithm
algos.append( ("ptl",)+get_ptl_algorithm() )
if algo_name in ["lr3o", "all", "classical"]:
#"lr3o":"Stewart and Golden (1982) LR3OPT heuristic"
from classic_heuristics.lr3opt import get_lr3opt_algorithm
from verypy.classic_heuristics.lr3opt import get_lr3opt_algorithm
algos.append( ("lr3o",)+get_lr3opt_algorithm() )
else:
print(algo_name, "is not a valid algorithm name", file=sys.stderr)
Expand Down
4 changes: 2 additions & 2 deletions examples/bing_maps_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ def getDistanceMatrix(addressDataList, travelMode, BingMapsAPIKey):

## Solve the related CVRP using VeRyPy ##
if args.C:
from classic_heuristics.parallel_savings import parallel_savings_init
from util import sol2routes
from verypy.classic_heuristics.parallel_savings import parallel_savings_init
from verypy.util import sol2routes

if locations:
d = [loc["demand"] for loc in locations]
Expand Down
2 changes: 1 addition & 1 deletion examples/calculate_geodetic_distances.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-

import numpy as np
from cvrp_io import _haversine
from verypy.cvrp_io import _haversine

points = [[24.42, 54.44], [24.44, 54.60], [24.42, 54.53]]

Expand Down
10 changes: 6 additions & 4 deletions examples/single_solve_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
printing the resulting solution route by route."""
###############################################################################

import cvrp_io
from classic_heuristics.parallel_savings import parallel_savings_init
from util import sol2routes
import verypy.cvrp_io as cvrp_io
from verypy.classic_heuristics.parallel_savings import parallel_savings_init
from verypy.util import sol2routes

E_n51_k5_path = r"E-n51-k5.vrp"
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
E_n51_k5_path = os.path.join(dir_path, "E-n51-k5.vrp")

problem = cvrp_io.read_TSPLIB_CVRP(E_n51_k5_path)

Expand Down
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# python<=3.8
natsort
orderedset # compatible up to python 3.8
numpy
scipy
llist
elkai
34 changes: 34 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from setuptools import setup

classifiers = [
"Development Status :: Development",
"License :: MIT License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
]


with open("README.md") as f:
long_description = f.read()

with open("requirements.txt") as f:
requirements = f.readlines()

install_requires = [r.strip() for r in requirements]

setup(
name="verypy",
version="0.0.1",
description="A python library with implementations of classical heuristics for the capacitated vehicle routing problem",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/yorak/VeRyPy",
license="MIT License",
platforms="any",
packages=["verypy"],
include_package_data=True,
install_requires=install_requires,
)
6 changes: 3 additions & 3 deletions tests/replication_tests/replicationbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

import numpy as np

from util import objf, without_empty_routes
from verypy.util import objf, without_empty_routes
from shared_cli import print_solution_statistics
from cvrp_ops import check_solution_feasibility
from verypy.cvrp_ops import check_solution_feasibility
import cvrp_io


from config import BENCHMARKS_BASEPATH
from verypy.config import BENCHMARKS_BASEPATH

class REPRO_QUALITY_LEVELS:
# Allow more leeway as there are many inaccuracies in the implementation details
Expand Down
12 changes: 6 additions & 6 deletions tests/replication_tests/test_beasley_rfcs.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-

from classic_heuristics.rfcs import route_first_cluster_second_init
from verypy.classic_heuristics.rfcs import route_first_cluster_second_init
from replicationbase import ReplicationBase
from config import BENCHMARKS_BASEPATH
from tsp_solvers.tsp_solver_ropt import solve_tsp_ropt
from tsp_solvers.tsp_solver_gurobi import solve_tsp_gurobi as solve_tsp_giant_tour
#from tsp_solvers.tsp_solver_lkh import solve_tsp_lkh as solve_tsp_giant_tour
from verypy.config import BENCHMARKS_BASEPATH
from verypy.tsp_solvers.tsp_solver_ropt import solve_tsp_ropt
from verypy.tsp_solvers.tsp_solver_gurobi import solve_tsp_gurobi as solve_tsp_giant_tour
#from verypy.tsp_solvers.tsp_solver_lkh import solve_tsp_lkh as solve_tsp_giant_tour

from util import objf
from verypy.util import objf
import unittest
from os import path

Expand Down
4 changes: 2 additions & 2 deletions tests/replication_tests/test_cmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
from __future__ import division

from replicationbase import ReplicationBase
from classic_heuristics.cmt_2phase import cmt_2phase_init
from verypy.classic_heuristics.cmt_2phase import cmt_2phase_init
from os import path
import unittest
from util import objf
from verypy.util import objf

from random import random

Expand Down
2 changes: 1 addition & 1 deletion tests/replication_tests/test_gapvrp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import unittest
import cvrp_io
from classic_heuristics.gapvrp import gap_init, _sweep_seed_points
from verypy.classic_heuristics.gapvrp import gap_init, _sweep_seed_points
import numpy as np
from collections import namedtuple
from os import path
Expand Down
4 changes: 2 additions & 2 deletions tests/replication_tests/test_gillet_miller_sweep.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import unittest
from scipy.spatial.distance import pdist, squareform
from classic_heuristics.gillet_miller_sweep import gillet_miller_init, _shortest_path_through_nodes
from cvrp_ops import D2D_c, check_solution_feasibility
from verypy.classic_heuristics.gillet_miller_sweep import gillet_miller_init, _shortest_path_through_nodes
from verypy.cvrp_ops import D2D_c, check_solution_feasibility

from replicationbase import ReplicationBase, REPRO_QUALITY_LEVELS

Expand Down
4 changes: 2 additions & 2 deletions tests/replication_tests/test_lr3opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import numpy as np

from replicationbase import ReplicationBase, REPRO_QUALITY_LEVELS
from classic_heuristics.lr3opt import lr3opt_init, _check_lr3opt_move, _init_with_random
from cvrp_ops import calculate_objective
from verypy.classic_heuristics.lr3opt import lr3opt_init, _check_lr3opt_move, _init_with_random
from verypy.cvrp_ops import calculate_objective

def _random_init_lr3opt(pts,D,d,C,L,st,times):
best_sol = None
Expand Down
6 changes: 3 additions & 3 deletions tests/replication_tests/test_matchingvrp.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-

import unittest
from classic_heuristics.matchingvrp import mbsa_init
from verypy.classic_heuristics.matchingvrp import mbsa_init
import numpy as np
from os import path

from replicationbase import ReplicationBase, REPRO_QUALITY_LEVELS
#from tsp_solvers.tsp_solver_ropt import solve_tsp_3opt as solve_tsp
from tsp_solvers.tsp_solver_gurobi import solve_tsp_gurobi as solve_tsp
#from verypy.tsp_solvers.tsp_solver_ropt import solve_tsp_3opt as solve_tsp
from verypy.tsp_solvers.tsp_solver_gurobi import solve_tsp_gurobi as solve_tsp


#
Expand Down
2 changes: 1 addition & 1 deletion tests/replication_tests/test_molejameson_insertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import unittest
from os import path

from classic_heuristics.mole_jameson_insertion import mole_jameson_insertion_init
from verypy.classic_heuristics.mole_jameson_insertion import mole_jameson_insertion_init
from replicationbase import ReplicationBase, REPRO_QUALITY_LEVELS

# Mole & Jameson (1976) insertion has five different approaches, each tested
Expand Down
Loading