import json, re, sys inst = json.load(open("instance.json")) H = inst["hours"] gens = inst["generators"] G = len(gens) reserve_pct = inst["reserve_pct"] demand = inst["demand_mw"] wind = inst["wind_mw"] solar = inst["solar_mw"] solfile = sys.argv[1] if len(sys.argv) > 1 else "sol2.txt" vals = {} with open(solfile) as f: lines = f.readlines() # find "# Columns" section, stop at next section starting with '#' after values, or "Rows" started = False for line in lines: line = line.strip() if line.startswith("# Columns"): started = True continue if started: if line.startswith("#") or line.startswith("Rows") or line=="": if line.startswith("#"): break if line=="": continue parts = line.split() if len(parts) == 2: name, val = parts vals[name] = float(val) else: break on = [[0]*H for _ in range(G)] p = [[0.0]*H for _ in range(G)] for g in range(G): for h in range(H): onval = vals.get(f"on_{g}_{h}", 0.0) pval = vals.get(f"p_{g}_{h}", 0.0) on[g][h] = 1 if onval > 0.5 else 0 p[g][h] = pval if on[g][h] == 1 else 0.0 artifact = {"on": on, "p": p} json.dump(artifact, open("solution.json", "w")) print("wrote solution.json") # ---- independent verifier mirroring mission spec exactly ---- EPS = 1e-6 net_demand = [demand[h] - wind[h] - solar[h] for h in range(H)] reserve_req = [reserve_pct * demand[h] for h in range(H)] first_violation = None def fail(msg): global first_violation if first_violation is None: first_violation = msg print("VIOLATION:", msg) # 1. shape assert len(on) == G and len(p) == G for g in range(G): assert len(on[g]) == H and len(p[g]) == H for h in range(H): assert isinstance(on[g][h], int) assert not (p[g][h] != p[g][h]) # not nan # 2. on/off consistency for g in range(G): gen = gens[g] for h in range(H): if on[g][h] == 0: if abs(p[g][h]) > EPS: fail(f"gen{g} h{h} off but p={p[g][h]}") elif on[g][h] == 1: if p[g][h] < gen["pmin"] - EPS or p[g][h] > gen["pmax"] + EPS: fail(f"gen{g} h{h} p={p[g][h]} out of [{gen['pmin']},{gen['pmax']}]") else: fail(f"gen{g} h{h} on value {on[g][h]} not 0/1") # 3. demand for h in range(H): tot = sum(p[g][h] for g in range(G)) if abs(tot - net_demand[h]) > EPS: fail(f"h{h} demand mismatch: sum_p={tot} net_demand={net_demand[h]} diff={tot-net_demand[h]}") # 4. reserve min_margin = None for h in range(H): margin = sum((gens[g]["pmax"] - p[g][h]) for g in range(G) if on[g][h] == 1) if min_margin is None or margin < min_margin: min_margin = margin if margin < reserve_req[h] - EPS: fail(f"h{h} reserve violation: margin={margin} req={reserve_req[h]}") # 5. min-up/min-down for g in range(G): gen = gens[g] min_up = gen["min_up"] min_down = gen["min_down"] init_on = gen["init_on"] init_hours = gen["init_hours"] # build full state sequence with virtual history # state at h=-1 is init_on, having been in that state for init_hours already prev_state = init_on run_len = init_hours # length of current run ending at h=-1 (inclusive of h=-1) for h in range(H): cur = on[g][h] if cur != prev_state: # switching if prev_state == 1: # switching off: need run_len (hours on so far, ending previous hour) >= min_up if run_len < min_up: fail(f"gen{g} switched off at h{h} after only {run_len}h on (min_up={min_up})") else: if run_len < min_down: fail(f"gen{g} switched on at h{h} after only {run_len}h off (min_down={min_down})") run_len = 1 prev_state = cur else: run_len += 1 # cost fuel_cost = sum(p[g][h]*gens[g]["fuel_cost"] for g in range(G) for h in range(H) if on[g][h]==1) noload_cost = sum(gens[g]["no_load_cost"] for g in range(G) for h in range(H) if on[g][h]==1) startup_cost = 0.0 for g in range(G): gen = gens[g] prev = gen["init_on"] for h in range(H): cur = on[g][h] if prev == 0 and cur == 1: startup_cost += gen["startup_cost"] prev = cur total_cost = fuel_cost + noload_cost + startup_cost co2 = sum(p[g][h]*gens[g]["co2_rate"] for g in range(G) for h in range(H) if on[g][h]==1) print("first_violation:", first_violation) print("feasible:", first_violation is None) print("fuel_cost:", fuel_cost) print("noload_cost:", noload_cost) print("startup_cost:", startup_cost) print("total_cost:", total_cost) print("co2_tonnes:", co2) print("min_reserve_margin_mw:", min_margin)