最終的に描写するもの
- 暫定解値と, 下限値の時間推移
- 最適値
下記記事のGUROBI版です。正規表現などの解説は、次の記事にあります。
描写コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import argparse | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
integer = "[0-9]+" | |
double = "[0-9]+\.*[0-9]*" | |
_double = "[0-9]+\.[0-9]+([eE][+-]?[0-9]+)" | |
line_log_pattern = re.compile( | |
f"\s*(?P<expl>{integer})\s+(?P<unexpl>{integer})\s+(?P<obj>{double})\s+(?P<depth>{integer})\s+(?P<intinf>{integer})\s+(?P<incumbent>{double})\s+(?P<bestbd>{double})\s+(?P<gap>{double})%\s+(?P<itnode>{double})\s+(?P<time>{integer})s" | |
) | |
result_log_pattern1 = re.compile( | |
f"Explored (?P<expl>{integer}) nodes \((?P<simplex_iter>{integer}) simplex iterations\) in (?P<time>{double}) seconds \((?P<work_units>{double}) work units\)" | |
) | |
result_log_pattern2 = re.compile( | |
f"Best objective (?P<obj>{_double}), best bound (?P<bestbd>{_double}), gap (?P<gap>{double})%" | |
) | |
def main(log_file): | |
logs = list() | |
for line in open(log_file, "r"): | |
line = line.strip() | |
if m := line_log_pattern.match(line): | |
logs.append(m.groupdict()) | |
elif m := result_log_pattern1.match(line): | |
result1 = m.groupdict() | |
elif m := result_log_pattern2.match(line): | |
result2 = m.groupdict() | |
objective_value = float(result2["obj"]) | |
df = pd.DataFrame(logs).astype(float) # cast from str to float | |
objective_value = float(objective_value) # cast from str to float | |
fig, ax = plt.subplots() | |
# plot incumbent and lower bound | |
df.plot(x="time", y="incumbent", ax=ax) | |
df.plot(x="time", y="bestbd", ax=ax) | |
# plot objective value | |
x_min, x_max = 0, float(df.tail(1).time) | |
ax.hlines( | |
objective_value, x_min, x_max, color="red", linestyles="--", label="optimal" | |
) | |
# some settings | |
ax.set_xlabel("Time [s]") | |
ax.set_ylabel("Objective value") | |
ax.grid("--") | |
ax.legend() | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument( | |
"gurobi_log_file", | |
type=str, | |
) | |
args = parser.parse_args() | |
main(args.gurobi_log_file) |