Skip to content

Commit b449db8

Browse files
committed
Merge branch 'dev'
2 parents cf90a13 + c160c25 commit b449db8

File tree

5 files changed

+120
-37
lines changed

5 files changed

+120
-37
lines changed

README.md

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
<a href="https://pypi.org/project/pynetgen"><img src="https://img.shields.io/pypi/v/pynetgen?logo=pypi&logoColor=white"/></a> <a href="https://github.com/adam-rumpf/pynetgen"><img src="https://img.shields.io/github/v/tag/adam-rumpf/pynetgen?logo=github"></a> <a href="https://pypi.org/project/pynetgen/#history"><img src="https://img.shields.io/pypi/status/pynetgen"/></a> <a href="https://www.python.org/"><img src="https://img.shields.io/pypi/pyversions/pynetgen?logo=python&logoColor=white"></a> <a href="https://github.com/adam-rumpf/pynetgen/blob/main/LICENSE"><img src="https://img.shields.io/github/license/adam-rumpf/pynetgen"/></a> <a href="https://github.com/adam-rumpf/pynetgen/commits/main"><img src="https://img.shields.io/maintenance/yes/2022"/></a>
44

5-
A Python module for generating random network flows problem instances in [DIMACS graph format](http://dimacs.rutgers.edu/archive/Challenges/), including an implementation of the NETGEN algorithm ([Klingman et al. 1974](https://doi.org/10.1287/mnsc.20.5.814)).
5+
A Python module for generating random network flows problem instances in [DIMACS graph format](#dimacs-file-format), including an implementation of the NETGEN algorithm ([Klingman et al. 1974](https://doi.org/10.1287/mnsc.20.5.814)).
66

77
## Introduction
88

9-
This package defines a variety of scripts for generating random instances of network flows problems subject to tuneable parameters. This can be accomplished within Python by importing `pynetgen` as a module, or from the command line by calling `pynetgen` as a shell script.
9+
This package defines a variety of scripts for generating random instances of network flows problems subject to tuneable parameters. This can be accomplished within Python by importing `pynetgen` as a [module](#module-usage), or from the command line by calling `pynetgen` as a [shell script](#command-line-usage).
1010

1111
PyNETGEN began as a Python implementation of NETGEN, a random network flows problem instance generator defined in:
1212

@@ -18,6 +18,69 @@ An alternate network generation algorithm is also included for generating grid-b
1818

1919
> S. Sadeghi, A. Seifi, and E. Azizi. Trilevel shortest path network interdiction with partial fortification. _Computers & Industrial Engineering_, 106:400-411, 2017. [doi:10.1016/j.cie.2017.02.006](https://doi.org/10.1016/j.cie.2017.02.006).
2020
21+
## Network Generation Algorithms
22+
23+
Two different random network generation algorithms are defined. Both are capable of generating minimum-cost network flows problems according to a set of tuneable parameters that control things like the size of the network and the acceptable ranges of arc costs and capacities, and both have measures in place to guarantee that the resulting problem is feasible. To briefly describe each algorithm:
24+
25+
* The NETGEN algorithm (`netgen_generate`) begins by defining source and sink nodes and randomly distributing supply among them. It then generates a set of "skeleton arcs" to create paths from the sources to the sinks. Skeleton arcs are guaranteed to have enough capacity to carry all required flow, ensuring that the problem instance is feasible, but they can also be specified to have maximum cost in order to discourage uninteresting solutions that utilize only skeleton arcs. After the skeleton is defined, arcs are randomly generated between pairs of randomly-selected nodes until the desired density is reached.
26+
* The grid-based algorithm (`grid_generate`) defines a rectangular array of nodes with a specified number of columns and rows. A single master source is placed on one side, and a master sink is placed on the other. Arcs are generated in a square (or square with diagonal) grid pattern, and can be specified to be directed either strictly from the source side to the sink side or in both directions. The "skeleton arcs" consist of the first row of the grid, which is guaranteed to have enough capacity to carry all required flow, but at high cost.
27+
28+
By default both algorithms produce a minimum-cost flow problem instance. If the minimum and maximum arc costs are both set to exactly 1, and if the number of sources does not equal the total supply (easily achieved by setting the supply to 0), then a maximum flow problem is generated instead.
29+
30+
## Usage
31+
32+
PyNETGEN can be installed from [PyPI](https://pypi.org/project/pynetgen) via the console command
33+
```
34+
$ pip install pynetgen
35+
```
36+
37+
After installation, PyNETGEN can be used either by importing it as a module or through its shell script.
38+
39+
### Module Usage
40+
41+
PyNETGEN can be imported from within Python using
42+
```python
43+
import pynetgen
44+
```
45+
which grants access to the two main public functions `netgen_generate()` and `grid_generate()`. For detailed descriptions of the algorithms see their docstrings via `help(netgen_generate)` and `help(grid_generate)`. This includes brief descriptions of the network structures and a detailed lists of network parameters.
46+
47+
### Command Line Usage
48+
49+
PyNETGEN can be run through the command line using the `pynetgen` shell script
50+
```
51+
$ pynetgen [-h] [-v] [-q] [-f [FILE]] arg_list [arg_list ...]
52+
```
53+
For basic usage instructions, access the documentation via
54+
```
55+
$ pynetgen --help
56+
```
57+
For detailed instructions for the NETGEN and grid-based algorithms, including a brief description of the network's structure and a detailed list of network parameters, use
58+
```
59+
$ pynetgen netgen help
60+
```
61+
or
62+
```
63+
$ pynetgen grid help
64+
```
65+
66+
## DIMACS File Format
67+
68+
The resulting network is output as a file in [DIMACS graph format](http://dimacs.rutgers.edu/archive/Challenges/) (or printed to the screen, in case no file path is given). To give a brief description of the format, a DIMACS graph file is a pure text file in which every line begins with either the letter `c`, `p`, `n`, or `a` to specify what type of information it defines. In the case of a minimum-cost flows problem:
69+
70+
* `c` indicates a comment line. The output file begins with a header made up of comment lines describing the parameters used to generate the problem.
71+
* `p` indicates the problem definition. This follows the header and has the format `p min NODES DENSITY`, where:
72+
* `NODES` is the total number of nodes.
73+
* `DENSITY` is the total number of arcs.
74+
* `n` indicates a node definition. The node definitions follow the problem definition, and have the format `n ID SUPPLY`, where:
75+
* `ID` is a unique numerical index given to all nodes (starting at 1).
76+
* `SUPPLY` is the supply value of the node (positive for sources, negative for sinks). In order to save space, only nodes with nonzero supply values are included.
77+
* `a` indicates an arc definition. The arc definitions follow the node definitions, and have the format `a FROM TO MINCAP MAXCAP COST`, where:
78+
* `FROM` and `TO` are the node indices of the arc's origin and destination, respectively.
79+
* `MINCAP` and `MAXCAP` are the arc's lower and upper capacity bounds, respectively.
80+
* `COST` is the arc's unit flow cost.
81+
82+
The output file for a maximum-flow problem is mostly the same, except that the objective is `max` instead of `min`, and source and sink nodes are given the `SUPPLY` values `s` and `t`, respectively, rather than a specific number.
83+
2184
## Project Status
2285

23-
This is a work in progress. It currently includes only a few necessary submodules and some of the overall framework, and it is not yet release-ready.
86+
This is a work in progress. The NETGEN algorithm is complete but mostly untested, while the grid-based algorithm has not yet been implemented.

src/pynetgen/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,17 @@
1+
"""A Python module for generating random network flows problem instances.
2+
3+
Importing the pynetgen module grants access to the two main public methods:
4+
netgen_generate()
5+
grid_generate()
6+
for generating random networks using the NETGEN algorithm or a grid-based
7+
network generation algorithm. Access their docstrings via help() for
8+
detailed usage instructions.
9+
10+
PyNETGEN can also be accessed via the command line using the pynetgen shell
11+
script. Access its documentation via
12+
$ pynetgen --help
13+
for detailed usage instructions.
14+
"""
15+
116
from ._version import __author__, __version__, _author_email, _copyright_year
217
from .pynetgen import *

src/pynetgen/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
__author__ = "Adam Rumpf"
2-
__version__ = "0.2.0"
2+
__version__ = "0.3.0"
33
_author_email = "arumpf@floridapoly.edu"
44
_copyright_year = "2022"

src/pynetgen/gen/netgen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def __init__(self, seed=1, nodes=10, sources=3, sinks=3, density=30,
121121
self.sinks - self.tsinks and self.sources == self.supply):
122122
self._type = 2
123123
self._create_assignment()
124-
elif self.mincap == 1 and self.maxcap == 1:
124+
elif self.mincost == 1 and self.maxcost == 1:
125125
self._type = 1
126126
self._create_problem()
127127

src/pynetgen/pynetgen.py

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
"""The main PyNETGEN module.
1+
"""A Python module for generating random network flows problem instances.
22
3-
This file contains the main driver functions for the PyNETGEN procedures,
4-
which are handled using the classes defined in the submodules.
3+
Importing the pynetgen module grants access to the two main public methods:
4+
netgen_generate()
5+
grid_generate()
6+
for generating random networks using the NETGEN algorithm or a grid-based
7+
network generation algorithm. Access their docstrings via help() for
8+
detailed usage instructions.
59
6-
Importing the pynetgen module allows the netgen_generate and grid_generate
7-
methods to be called from within Python. Random networks can also be generated
8-
from the command line using the "pynetgen" shell script. For help, use:
10+
PyNETGEN can also be accessed via the command line using the pynetgen shell
11+
script. Access its documentation via
912
$ pynetgen --help
13+
for detailed usage instructions.
1014
"""
1115

1216
from ._version import __author__, __version__, _author_email, _copyright_year
@@ -16,10 +20,10 @@
1620
import argparse
1721

1822
# Define help strings
19-
desc = "Scripts for generating random flow networks in DIMACS format."
20-
vers = ("PyNETGEN v" + __version__ + "\nCopyright (c) " + _copyright_year
23+
_desc = "Scripts for generating random flow networks in DIMACS format."
24+
_vers = ("PyNETGEN v" + __version__ + "\nCopyright (c) " + _copyright_year
2125
+ " " + __author__ + "\n" + _author_email)
22-
epil = """
26+
_epil = """
2327
This shell script generates random network flows problem instances exported in
2428
DIMACS graph format <http://dimacs.rutgers.edu/archive/Challenges/>. The
2529
"arg_list" argument specifies the network generation method and its options.
@@ -40,7 +44,7 @@
4044
algorithm described in Sadeghi, Seifi, and Azizi 2017
4145
(doi:10.1016/j.cie.2017.02.006).
4246
"""
43-
netgen_instructions = """
47+
_netgen_instructions = """
4448
usage: pynetgen.py [-q] [-f [FILE]] netgen [ARGS ...]
4549
4650
An implementation of the NETGEN network flows problem instance generator.
@@ -85,9 +89,10 @@
8589
implicitly chosen according to the network parameters.
8690
8791
The resulting problem instance is a transportation problem if the total number
88-
of sources and sinks equals the total number of nodes, and if there are no
89-
transshipment sources or sinks. It is a maximum flow problem if it is not an
90-
assignment problem and the min/max costs are both set to 1.
92+
of sources and sinks equals the total number of nodes, there are no
93+
transshipment sources or sinks, and the total supply, sources, and sinks are
94+
all equal. It is a maximum flow problem if it is not an assignment problem and
95+
the min/max costs are both set to 1.
9196
9297
Skeleton arcs are part of NETGEN's process for generated minimum-cost flow
9398
problems, and are included to ensure feasibility. They are a subset of arcs
@@ -96,7 +101,7 @@
96101
are chosen to receive the maximum possible cost in order to discourage
97102
uninteresting solutions that use only the skeleton arcs.
98103
"""
99-
grid_instructions = """
104+
_grid_instructions = """
100105
usage: pynetgen.py [-f [FILE]] grid [ARGS ...]
101106
102107
A grid-based network flows problem instance generator.
@@ -134,8 +139,9 @@
134139
135140
By default the resulting problem instance is a minimum-cost flow problem. A
136141
maximum flow problem is generated if the minimum and maximum arc costs are both
137-
set equal to 1. Transshipment sources and sinks are not included, and
138-
transportation problems cannot be generated.
142+
set equal to 1 and the number of sources does not equal the total supply.
143+
Transshipment sources and sinks are not included. Transportation problems
144+
cannot be generated.
139145
140146
The master source is located on the West side while the master sink is located
141147
on the East side. All transshipment arcs feed into their immediate neighbors to
@@ -150,6 +156,14 @@
150156
uncapacitated to ensure that the network can carry enough flow, but a fraction
151157
of them are chosen to receive the maximum possible cost in order to discourage
152158
uninteresting solutions that use only the skeleton arcs.
159+
160+
In the output file, the different types of arcs in the arc list are divided
161+
using comments. In order, they consist of: the master supply arcs, the master
162+
sink arcs, the Eastern row arcs (with the first row constituting the skeleton
163+
arcs), the Western row arcs (if present), the Southern column arcs, the
164+
Northern column arcs, the Southeast diagonal arcs (if present), the Northeast
165+
diagonal arcs (if present), the Northwest diagonal arcs (if present), and
166+
finally the Southwest diagonal arcs (if present).
153167
"""
154168

155169
#=============================================================================
@@ -166,9 +180,10 @@ def main():
166180
"""
167181

168182
# Define argument parser
169-
parser = argparse.ArgumentParser(description=desc, epilog=epil,
183+
parser = argparse.ArgumentParser(prog="pynetgen", description=_desc,
184+
epilog=_epil,
170185
formatter_class=argparse.RawDescriptionHelpFormatter)
171-
parser.add_argument("-v", "--version", action="version", version=vers)
186+
parser.add_argument("-v", "--version", action="version", version=_vers)
172187
parser.add_argument("-q", "--quiet", action="store_true",
173188
help="silence result message")
174189
parser.add_argument("-f", "--file", nargs="?", dest="file",
@@ -182,10 +197,10 @@ def main():
182197
# Display method-specific help messages if requested
183198
if len(arg_list) > 1:
184199
if arg_list[0] == "netgen" and arg_list[1] == "help":
185-
print(netgen_instructions)
200+
print(_netgen_instructions)
186201
return None
187202
if arg_list[0] == "grid" and arg_list[1] == "help":
188-
print(grid_instructions)
203+
print(_grid_instructions)
189204
return None
190205

191206
# If a method is selected, call its function with the other arguments
@@ -213,13 +228,7 @@ def netgen_generate(seed=1, nodes=10, sources=3, sinks=3, density=30,
213228
mincost=10, maxcost=99, supply=1000, tsources=0, tsinks=0,
214229
hicost=0, capacitated=100, mincap=100, maxcap=1000,
215230
rng=0, fname=None):
216-
"""
217-
netgen_generate([seed][, nodes][, sources][, sinks][, density][, ...
218-
mincost][, maxcost][, supply][, tsources][, tsinks][, ...
219-
hicost][, capacitated][, mincap][, maxcap][, rng][, ...
220-
fname])
221-
222-
The main NETGEN random network generation function.
231+
"""The main NETGEN random network generation function.
223232
224233
Keyword arguments:
225234
seed -- random number generator seed (default 1; -1 for random)
@@ -283,11 +292,7 @@ def netgen_generate(seed=1, nodes=10, sources=3, sinks=3, density=30,
283292
def grid_generate(seed=1, rows=3, columns=4, diagonal=1, reverse=1,
284293
wrap=0, mincost=10, maxcost=99, supply=1000, hicost=0,
285294
capacitated=100, mincap=100, maxcap=1000, rng=0, fname=None):
286-
"""grid_generate([seed][, rows][, columns][, diagonal][, reverse][, ...
287-
wrap][, mincost][, maxcost][, supply][, hicost][, ...
288-
capacitated][, mincap][, maxcap][, rng][, fname])
289-
290-
A grid-based random network generation function.
295+
"""A grid-based random network generation function.
291296
292297
Keyword arguments:
293298
seed -- random number generator seed (default 1; -1 for random)

0 commit comments

Comments
 (0)