pipstools 0.2.1__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.
- pipstools-0.2.1/PKG-INFO +115 -0
- pipstools-0.2.1/README.md +74 -0
- pipstools-0.2.1/pyproject.toml +74 -0
- pipstools-0.2.1/pyproject.toml.orig +65 -0
- pipstools-0.2.1/src/pipstools/__init__.py +5 -0
- pipstools-0.2.1/src/pipstools/annotation.py +204 -0
- pipstools-0.2.1/src/pipstools/cli.py +258 -0
- pipstools-0.2.1/src/pipstools/conversion.py +75 -0
- pipstools-0.2.1/src/pipstools/io/__init__.py +5 -0
- pipstools-0.2.1/src/pipstools/io/gdx.py +461 -0
- pipstools-0.2.1/src/pipstools/io/mps.py +232 -0
- pipstools-0.2.1/src/pipstools/io/parquet.py +51 -0
- pipstools-0.2.1/src/pipstools/partitioning.py +609 -0
- pipstools-0.2.1/src/pipstools/scoring.py +143 -0
- pipstools-0.2.1/src/pipstools/utils.py +174 -0
- pipstools-0.2.1/src/pipstools/validation.py +57 -0
- pipstools-0.2.1/src/pipstools/visualisation.py +226 -0
pipstools-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pipstools
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Manuel Wetzel
|
|
6
|
+
Author-email: Manuel Wetzel <manuel.wetzel@dlr.de>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Operating System :: Unix
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Requires-Dist: gamsapi
|
|
19
|
+
Requires-Dist: gamspy-base
|
|
20
|
+
Requires-Dist: highspy
|
|
21
|
+
Requires-Dist: matplotlib
|
|
22
|
+
Requires-Dist: mtkahypar ; sys_platform != 'win32'
|
|
23
|
+
Requires-Dist: networkx
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: polars
|
|
26
|
+
Requires-Dist: pyarrow
|
|
27
|
+
Requires-Dist: scipy
|
|
28
|
+
Requires-Dist: tqdm
|
|
29
|
+
Requires-Dist: typer
|
|
30
|
+
Requires-Dist: typing-extensions
|
|
31
|
+
Requires-Dist: gurobipy ; extra == 'gurobi'
|
|
32
|
+
Requires-Dist: mosek ; extra == 'mosek'
|
|
33
|
+
Requires-Dist: coverage ; extra == 'test'
|
|
34
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
35
|
+
Requires-Dist: pytest-cov ; extra == 'test'
|
|
36
|
+
Requires-Python: >=3.11
|
|
37
|
+
Provides-Extra: gurobi
|
|
38
|
+
Provides-Extra: mosek
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# PIPS-IPM++ tools
|
|
43
|
+
|
|
44
|
+
`pipstools` is a collection of software tools that aims to give modellers easy access to the [massively parallel solver PIPS-IPM++](https://gitlab.com/pips-ipmpp).
|
|
45
|
+
The tools can be used to identify suitable block structures for linear optimisation problems, either based on domain information or
|
|
46
|
+
in a fully automated manner using hypergraph partitioning. Furthermore, the identified block structures can be scored to estimate
|
|
47
|
+
their expected performance with PIPS-IPM++, and can be visually inspected to help modellers improve the problem formulation.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Getting started
|
|
51
|
+
|
|
52
|
+
If you are using [uv](https://docs.astral.sh/uv) as your python package manager, annotation a problem file can be done with a single call:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
uvx git+https://git@gitlab.com/pips-ipmpp/pipstools annotate problem.mps
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For solving the problem with PIPS-IPM++ using e.g. a Docker imange please refer to the [solver documentation](https://gitlab.com/pips-ipmpp/pips-ipmpp#docker-image).
|
|
59
|
+
|
|
60
|
+
## Annotation
|
|
61
|
+
|
|
62
|
+
Problem annotation describes the process of identifying underlying block strucutres which the massivly parallel solver PIPS-IPM++ can
|
|
63
|
+
exploit. Problem files can be provided either as .lp, .mps, or .gdx. If gurobipy is used as a file reader, also compressed
|
|
64
|
+
files (.mps.gz, .lp.gz) can be provided. `pipstools` currently support two differnt modes of identifying block strucutres, user-defined
|
|
65
|
+
annotations using domain knowledge and fully automated annotation using hypergraph partitioning.
|
|
66
|
+
|
|
67
|
+
### Using variables names and regular expressions
|
|
68
|
+
|
|
69
|
+
Typcially, users are aware of the strucutre and interdependencies between variables and equation of their optimization problem. This can
|
|
70
|
+
provide a good starting point by specifying variables naming patterns to be used for the decomposition. In the [sample file](/../main/samples/remix.mps.gz)
|
|
71
|
+
of an energy system optimization model generated with the [REMix framework](https://gitlab.com/dlr-ve/esy/remix/framework) the temporal
|
|
72
|
+
dimension uses the naming pattern of `tm` followed by the integer of the specific timestep, e.g. `tm1` to `tm8760` for each timestep of a year.
|
|
73
|
+
This specific pattern can be encoded as the regular expression "tm([0-9]+)" which captures the integer representing the timestep to maintain
|
|
74
|
+
chronological ordering. Note, that using regular expressions for the annotation requires the problem file to include the actual variables
|
|
75
|
+
as generated with the specific mathematical programming tool used.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
pipstools annotate samples/remix.mps --regex-pattern=tm([0-9]+)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Using hypergraph partitioning
|
|
82
|
+
For problems without variable names or prior knowledge about the underlying problem strucutre, a fully automated annotation can be used.
|
|
83
|
+
The algorithm first splits any dense variables (automatically detected by heuristics, can be changed using the `--densecol` argument), which
|
|
84
|
+
in the case of energy system optimization problems typically corrosponds to investment decisions. The remaining problem strucute is then
|
|
85
|
+
converted to a hypergraph using variables as nodes and constraints as hyperedges. Using the [Karlsruhe Hypergraph Partitioner](https://github.com/kahypar/mt-kahypar),
|
|
86
|
+
a balanced partitioning into `n` partitions for the variables is generated (corresponding to the `--blocks n` argument). Afterwards, the
|
|
87
|
+
constraints of the optimization problem are similarly paritioned taking into account the variable partions included in each constraint.
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
pipstools annotate samples/remix.mps --method hypergraph --blocks 30
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Visualization
|
|
94
|
+
|
|
95
|
+
After the identification of block structures using the annotation functionality, the identified block structure can be explored visually
|
|
96
|
+
using the included visulisation tool. By default it will try to plot the matrix using a matplot display and include both the annotation
|
|
97
|
+
as well as variable and equation names. The matrix can be zoomed into, which further help refining the block structure and model formulation.
|
|
98
|
+
If no display is available, the matrix plot can also be redirected to an image using the `--output` argument.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
pipstools visualize samples/remix.gdx
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Scoring of block strucutres
|
|
105
|
+
|
|
106
|
+
Scoring of the annotation is currently a work-in-progress feature.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## Authors
|
|
110
|
+
- Manuel Wetzel (German Aerospace Center, DLR)
|
|
111
|
+
- Stephen Maher (GAMS Software GmbH)
|
|
112
|
+
|
|
113
|
+
## Acknoledgements
|
|
114
|
+
`pipstools` was developed as a deliverable of the PEREGRINE project, which was funded by
|
|
115
|
+
the German Federal Ministry for Economic Affairs and Energy under grant number 03EI1082A-B.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# PIPS-IPM++ tools
|
|
2
|
+
|
|
3
|
+
`pipstools` is a collection of software tools that aims to give modellers easy access to the [massively parallel solver PIPS-IPM++](https://gitlab.com/pips-ipmpp).
|
|
4
|
+
The tools can be used to identify suitable block structures for linear optimisation problems, either based on domain information or
|
|
5
|
+
in a fully automated manner using hypergraph partitioning. Furthermore, the identified block structures can be scored to estimate
|
|
6
|
+
their expected performance with PIPS-IPM++, and can be visually inspected to help modellers improve the problem formulation.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Getting started
|
|
10
|
+
|
|
11
|
+
If you are using [uv](https://docs.astral.sh/uv) as your python package manager, annotation a problem file can be done with a single call:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
uvx git+https://git@gitlab.com/pips-ipmpp/pipstools annotate problem.mps
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For solving the problem with PIPS-IPM++ using e.g. a Docker imange please refer to the [solver documentation](https://gitlab.com/pips-ipmpp/pips-ipmpp#docker-image).
|
|
18
|
+
|
|
19
|
+
## Annotation
|
|
20
|
+
|
|
21
|
+
Problem annotation describes the process of identifying underlying block strucutres which the massivly parallel solver PIPS-IPM++ can
|
|
22
|
+
exploit. Problem files can be provided either as .lp, .mps, or .gdx. If gurobipy is used as a file reader, also compressed
|
|
23
|
+
files (.mps.gz, .lp.gz) can be provided. `pipstools` currently support two differnt modes of identifying block strucutres, user-defined
|
|
24
|
+
annotations using domain knowledge and fully automated annotation using hypergraph partitioning.
|
|
25
|
+
|
|
26
|
+
### Using variables names and regular expressions
|
|
27
|
+
|
|
28
|
+
Typcially, users are aware of the strucutre and interdependencies between variables and equation of their optimization problem. This can
|
|
29
|
+
provide a good starting point by specifying variables naming patterns to be used for the decomposition. In the [sample file](/../main/samples/remix.mps.gz)
|
|
30
|
+
of an energy system optimization model generated with the [REMix framework](https://gitlab.com/dlr-ve/esy/remix/framework) the temporal
|
|
31
|
+
dimension uses the naming pattern of `tm` followed by the integer of the specific timestep, e.g. `tm1` to `tm8760` for each timestep of a year.
|
|
32
|
+
This specific pattern can be encoded as the regular expression "tm([0-9]+)" which captures the integer representing the timestep to maintain
|
|
33
|
+
chronological ordering. Note, that using regular expressions for the annotation requires the problem file to include the actual variables
|
|
34
|
+
as generated with the specific mathematical programming tool used.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
pipstools annotate samples/remix.mps --regex-pattern=tm([0-9]+)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Using hypergraph partitioning
|
|
41
|
+
For problems without variable names or prior knowledge about the underlying problem strucutre, a fully automated annotation can be used.
|
|
42
|
+
The algorithm first splits any dense variables (automatically detected by heuristics, can be changed using the `--densecol` argument), which
|
|
43
|
+
in the case of energy system optimization problems typically corrosponds to investment decisions. The remaining problem strucute is then
|
|
44
|
+
converted to a hypergraph using variables as nodes and constraints as hyperedges. Using the [Karlsruhe Hypergraph Partitioner](https://github.com/kahypar/mt-kahypar),
|
|
45
|
+
a balanced partitioning into `n` partitions for the variables is generated (corresponding to the `--blocks n` argument). Afterwards, the
|
|
46
|
+
constraints of the optimization problem are similarly paritioned taking into account the variable partions included in each constraint.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
pipstools annotate samples/remix.mps --method hypergraph --blocks 30
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Visualization
|
|
53
|
+
|
|
54
|
+
After the identification of block structures using the annotation functionality, the identified block structure can be explored visually
|
|
55
|
+
using the included visulisation tool. By default it will try to plot the matrix using a matplot display and include both the annotation
|
|
56
|
+
as well as variable and equation names. The matrix can be zoomed into, which further help refining the block structure and model formulation.
|
|
57
|
+
If no display is available, the matrix plot can also be redirected to an image using the `--output` argument.
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
pipstools visualize samples/remix.gdx
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Scoring of block strucutres
|
|
64
|
+
|
|
65
|
+
Scoring of the annotation is currently a work-in-progress feature.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Authors
|
|
69
|
+
- Manuel Wetzel (German Aerospace Center, DLR)
|
|
70
|
+
- Stephen Maher (GAMS Software GmbH)
|
|
71
|
+
|
|
72
|
+
## Acknoledgements
|
|
73
|
+
`pipstools` was developed as a deliverable of the PEREGRINE project, which was funded by
|
|
74
|
+
the German Federal Ministry for Economic Affairs and Energy under grant number 03EI1082A-B.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pipstools"
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Development Status :: 4 - Beta",
|
|
9
|
+
"Operating System :: Unix",
|
|
10
|
+
"Intended Audience :: Science/Research",
|
|
11
|
+
"Programming Language :: Python",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"Topic :: Scientific/Engineering",
|
|
18
|
+
]
|
|
19
|
+
requires-python = ">=3.11"
|
|
20
|
+
dependencies = [
|
|
21
|
+
"gamsapi",
|
|
22
|
+
"gamspy_base",
|
|
23
|
+
"highspy",
|
|
24
|
+
"matplotlib",
|
|
25
|
+
"mtkahypar ; platform_system != 'Windows'",
|
|
26
|
+
"networkx",
|
|
27
|
+
"numpy",
|
|
28
|
+
"polars",
|
|
29
|
+
"pyarrow",
|
|
30
|
+
"scipy",
|
|
31
|
+
"tqdm",
|
|
32
|
+
"typer",
|
|
33
|
+
"typing-extensions",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[[project.authors]]
|
|
37
|
+
name = "Manuel Wetzel"
|
|
38
|
+
email = "manuel.wetzel@dlr.de"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
test = [
|
|
42
|
+
"coverage",
|
|
43
|
+
"pytest",
|
|
44
|
+
"pytest-cov",
|
|
45
|
+
]
|
|
46
|
+
gurobi = ["gurobipy"]
|
|
47
|
+
mosek = ["mosek"]
|
|
48
|
+
|
|
49
|
+
[project.scripts]
|
|
50
|
+
pipstools = "pipstools.cli:app"
|
|
51
|
+
|
|
52
|
+
[build-system]
|
|
53
|
+
requires = ["uv_build>=0.12.7,<0.13.0"]
|
|
54
|
+
build-backend = "uv_build"
|
|
55
|
+
|
|
56
|
+
[tool.uv]
|
|
57
|
+
package = true
|
|
58
|
+
|
|
59
|
+
[tool.ruff]
|
|
60
|
+
line-length = 100
|
|
61
|
+
fix = true
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = [
|
|
65
|
+
"E",
|
|
66
|
+
"F",
|
|
67
|
+
"I",
|
|
68
|
+
]
|
|
69
|
+
ignore = ["E501"]
|
|
70
|
+
|
|
71
|
+
[tool.ruff.format]
|
|
72
|
+
quote-style = "double"
|
|
73
|
+
indent-style = "space"
|
|
74
|
+
docstring-code-format = true
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pipstools"
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "Add your description here"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [{ name = "Manuel Wetzel", email = "manuel.wetzel@dlr.de" }]
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Development Status :: 4 - Beta",
|
|
10
|
+
"Operating System :: Unix",
|
|
11
|
+
"Intended Audience :: Science/Research",
|
|
12
|
+
"Programming Language :: Python",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Scientific/Engineering",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
requires-python = ">=3.11"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"gamsapi",
|
|
24
|
+
"gamspy_base",
|
|
25
|
+
"highspy",
|
|
26
|
+
"matplotlib",
|
|
27
|
+
"mtkahypar ; platform_system != 'Windows'",
|
|
28
|
+
"networkx",
|
|
29
|
+
"numpy",
|
|
30
|
+
"polars",
|
|
31
|
+
"pyarrow",
|
|
32
|
+
"scipy",
|
|
33
|
+
"tqdm",
|
|
34
|
+
"typer",
|
|
35
|
+
"typing-extensions",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
test = ["coverage", "pytest", "pytest-cov"]
|
|
40
|
+
|
|
41
|
+
gurobi = ["gurobipy"]
|
|
42
|
+
mosek = ["mosek"]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
pipstools = "pipstools.cli:app"
|
|
46
|
+
|
|
47
|
+
[build-system]
|
|
48
|
+
requires = ["uv_build>=0.12.7,<0.13.0"]
|
|
49
|
+
build-backend = "uv_build"
|
|
50
|
+
|
|
51
|
+
[tool.uv]
|
|
52
|
+
package = true
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 100
|
|
56
|
+
fix = true
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = ["E", "F", "I"]
|
|
60
|
+
ignore = ["E501"]
|
|
61
|
+
|
|
62
|
+
[tool.ruff.format]
|
|
63
|
+
quote-style = "double"
|
|
64
|
+
indent-style = "space"
|
|
65
|
+
docstring-code-format = true
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
from .annotation import annotate_problem as annotate_problem
|
|
2
|
+
from .conversion import convert_problem as convert_problem
|
|
3
|
+
from .scoring import score_problem as score_problem
|
|
4
|
+
from .validation import validate_problem as validate_problem
|
|
5
|
+
from .visualisation import visualize_problem as visualize_problem
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import gzip
|
|
2
|
+
import importlib.util
|
|
3
|
+
import shutil
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from time import perf_counter
|
|
6
|
+
|
|
7
|
+
from pipstools.io import read_gdx, read_mps, read_parquet, write_gdx, write_parquet
|
|
8
|
+
from pipstools.partitioning import get_partitions
|
|
9
|
+
from pipstools.scoring import get_score
|
|
10
|
+
from pipstools.utils import get_stem
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def annotate_problem(
|
|
14
|
+
f_input,
|
|
15
|
+
k,
|
|
16
|
+
f_output=None,
|
|
17
|
+
fileformat="gdx",
|
|
18
|
+
var_dense=None,
|
|
19
|
+
equ_dense=None,
|
|
20
|
+
presolve=False,
|
|
21
|
+
mpsreader=None,
|
|
22
|
+
method="hypergraph",
|
|
23
|
+
hypergraph="col",
|
|
24
|
+
hg_objective="soed",
|
|
25
|
+
regex_pattern=None,
|
|
26
|
+
regex_order=None,
|
|
27
|
+
regex_mapfile=None,
|
|
28
|
+
dec=None,
|
|
29
|
+
write_names=True,
|
|
30
|
+
write_uels=True,
|
|
31
|
+
distributed=False,
|
|
32
|
+
vcycles=0,
|
|
33
|
+
):
|
|
34
|
+
start = perf_counter()
|
|
35
|
+
if isinstance(f_input, str):
|
|
36
|
+
f_input = Path(f_input)
|
|
37
|
+
|
|
38
|
+
if var_dense is not None and var_dense < 0:
|
|
39
|
+
var_dense = None
|
|
40
|
+
|
|
41
|
+
if equ_dense is not None and equ_dense < 0:
|
|
42
|
+
var_dense = None
|
|
43
|
+
|
|
44
|
+
if mpsreader is None:
|
|
45
|
+
lib_gurobi = importlib.util.find_spec("gurobipy")
|
|
46
|
+
if lib_gurobi is not None:
|
|
47
|
+
mpsreader = "gurobi"
|
|
48
|
+
else:
|
|
49
|
+
mpsreader = "highs"
|
|
50
|
+
print(f"Selected {mpsreader} as default mps reader.")
|
|
51
|
+
|
|
52
|
+
if k == 1 and method.lower() != "oneblock":
|
|
53
|
+
print('Specificed partitioning into a single block, switching method to "oneblock"')
|
|
54
|
+
method = "oneblock"
|
|
55
|
+
|
|
56
|
+
if regex_pattern is not None:
|
|
57
|
+
print('Specificed regex pattern, switching method to "regex"')
|
|
58
|
+
method = "regex"
|
|
59
|
+
|
|
60
|
+
if dec is not None:
|
|
61
|
+
print('Specificed .dec file, switching method to "dec"')
|
|
62
|
+
method = "dec"
|
|
63
|
+
|
|
64
|
+
# Check if valid hypergraph arguments are provided
|
|
65
|
+
if method == "hypergraph":
|
|
66
|
+
if hypergraph.lower() not in ["col", "row", "colrow", "rowcol"]:
|
|
67
|
+
raise IOError(
|
|
68
|
+
f"Hypergraph type {hypergraph} is not available. "
|
|
69
|
+
"Use either 'col', 'row', 'colrow', or 'rowcol'"
|
|
70
|
+
)
|
|
71
|
+
if hg_objective.lower() not in ["cut", "km1", "soed"]:
|
|
72
|
+
raise IOError(
|
|
73
|
+
f"Hypergraph objective {hg_objective} is not available. "
|
|
74
|
+
"Use either 'cut', 'km1', or 'soed'"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Read in file and extract A, vars, cols
|
|
78
|
+
match f_input.suffix.lower():
|
|
79
|
+
case ".gdx":
|
|
80
|
+
A, cols, rows, objcol, objrow, objcoef, objjacval = read_gdx(f_input=f_input)
|
|
81
|
+
case ".parquet":
|
|
82
|
+
A, cols, rows, objcol, objrow, objcoef, objjacval = read_parquet(f_input=f_input)
|
|
83
|
+
case ".lp" | ".mps" | ".gz" | ".bz2":
|
|
84
|
+
compressed_input = f_input.suffix.lower() in [".gz", ".bz2"]
|
|
85
|
+
|
|
86
|
+
# File needs to be compresses lp or mps
|
|
87
|
+
if compressed_input:
|
|
88
|
+
suffix_uncomp = f_input.stem.lower()
|
|
89
|
+
if not suffix_uncomp.endswith(".lp") and not suffix_uncomp.endswith(".mps"):
|
|
90
|
+
raise (
|
|
91
|
+
IOError(
|
|
92
|
+
"Can only read compressed files of type .lp and .mps, "
|
|
93
|
+
f"not {f_input.suffix}"
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# For highspy manually decompress file and delete later
|
|
98
|
+
remove_decompressed = False
|
|
99
|
+
if compressed_input and mpsreader == "highs":
|
|
100
|
+
print(f"Automatically decompressing problem file {f_input.as_posix()} for highs")
|
|
101
|
+
if f_input.with_suffix("").exists():
|
|
102
|
+
raise (
|
|
103
|
+
IOError(
|
|
104
|
+
f"Cannot automatically decompress file {f_input.as_posix()}, since "
|
|
105
|
+
"a file with the target name already exists!"
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
with gzip.open(f_input, "rb") as f_in:
|
|
109
|
+
with open(f_input.with_suffix(""), "wb") as f_out:
|
|
110
|
+
shutil.copyfileobj(f_in, f_out)
|
|
111
|
+
f_input = f_input.with_suffix("")
|
|
112
|
+
remove_decompressed = True
|
|
113
|
+
|
|
114
|
+
# Read in mps content
|
|
115
|
+
A, cols, rows, objcol, objrow, objcoef = read_mps(
|
|
116
|
+
f_input=f_input,
|
|
117
|
+
presolve=presolve,
|
|
118
|
+
read_names=write_names or method == "regex",
|
|
119
|
+
mpsreader=mpsreader,
|
|
120
|
+
)
|
|
121
|
+
objjacval = 1.0
|
|
122
|
+
|
|
123
|
+
# Remove temporary decompressed file again
|
|
124
|
+
if remove_decompressed:
|
|
125
|
+
print(f"Automatically removing decompressed file {f_input.as_posix()}")
|
|
126
|
+
f_input.unlink()
|
|
127
|
+
case _:
|
|
128
|
+
raise (IOError(f"No reader implemented for filetype {f_input.suffix}"))
|
|
129
|
+
|
|
130
|
+
# Check if kahypar is available
|
|
131
|
+
if method == "hypergraph":
|
|
132
|
+
lib_mkkahypar = importlib.util.find_spec("mtkahypar")
|
|
133
|
+
if lib_mkkahypar is None:
|
|
134
|
+
raise ImportError(
|
|
135
|
+
"Hypergraph partitioning specified, but library mtkahypar not available."
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Partition by regex, hypergraph or dense elements
|
|
139
|
+
cols, rows = get_partitions(
|
|
140
|
+
A=A,
|
|
141
|
+
cols=cols,
|
|
142
|
+
rows=rows,
|
|
143
|
+
method=method,
|
|
144
|
+
hypergraph=hypergraph,
|
|
145
|
+
hg_objective=hg_objective,
|
|
146
|
+
k=k,
|
|
147
|
+
var_dense=var_dense,
|
|
148
|
+
equ_dense=equ_dense,
|
|
149
|
+
regex_pattern=regex_pattern,
|
|
150
|
+
regex_order=regex_order,
|
|
151
|
+
regex_mapfile=regex_mapfile,
|
|
152
|
+
dec=dec,
|
|
153
|
+
vcycles=vcycles,
|
|
154
|
+
objcol=objcol,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Derive stem for output
|
|
158
|
+
if f_output is None:
|
|
159
|
+
stem, suffix = get_stem(f_input)
|
|
160
|
+
else:
|
|
161
|
+
stem, suffix = get_stem(f_output)
|
|
162
|
+
if suffix is not None:
|
|
163
|
+
fileformat = suffix.lstrip(".")
|
|
164
|
+
|
|
165
|
+
f_output = Path(f"{stem}_{len(set(cols['partition'].unique()) - {1})}b")
|
|
166
|
+
f_output.parent.mkdir(parents=True, exist_ok=True)
|
|
167
|
+
|
|
168
|
+
# Get scoring for annotation
|
|
169
|
+
get_score(A, cols, rows)
|
|
170
|
+
|
|
171
|
+
# Write out annotated gdx file
|
|
172
|
+
match fileformat.lower():
|
|
173
|
+
case "gdx":
|
|
174
|
+
write_gdx(
|
|
175
|
+
f_input=f_input,
|
|
176
|
+
f_output=f_output,
|
|
177
|
+
A=A,
|
|
178
|
+
cols=cols,
|
|
179
|
+
rows=rows,
|
|
180
|
+
objcol=objcol,
|
|
181
|
+
objrow=objrow,
|
|
182
|
+
objcoef=objcoef,
|
|
183
|
+
objjacval=objjacval,
|
|
184
|
+
write_names=write_names,
|
|
185
|
+
write_uels=write_uels,
|
|
186
|
+
distributed=distributed,
|
|
187
|
+
)
|
|
188
|
+
case "parquet":
|
|
189
|
+
write_parquet(
|
|
190
|
+
f_input=f_input,
|
|
191
|
+
f_output=f_output,
|
|
192
|
+
A=A,
|
|
193
|
+
cols=cols,
|
|
194
|
+
rows=rows,
|
|
195
|
+
objcol=objcol,
|
|
196
|
+
objrow=objrow,
|
|
197
|
+
objcoef=objcoef,
|
|
198
|
+
objjacval=objjacval,
|
|
199
|
+
)
|
|
200
|
+
case _:
|
|
201
|
+
raise (IOError(f"No method implemented for output format {fileformat}"))
|
|
202
|
+
|
|
203
|
+
stop = perf_counter()
|
|
204
|
+
print(f"Annotated problem in {(stop - start):.2f} seconds")
|