サブロウ丸

Sabrou-mal サブロウ丸

主にプログラミングと数学

GUROBI ソルバ ログの可視化

最終的に描写するもの

  • 暫定解値と, 下限値の時間推移
  • 最適値

下記記事のGUROBI版です。正規表現などの解説は、次の記事にあります。

描写コード

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)
gist.github.com