#!/usr/bin/env python3 # Dualitaet_Nachweis.py """ Kapitel LP: Primales und duales Problem unabhaengig loesen und den starken Dualitaetssatz sowie den komplementaeren Schlupf numerisch nachweisen. Modell aus der Simplex-Handrechnung (Bot-Allokation, LP-Relaxation): max 150*x1 + 250*x2 u.d.N. 2*x1+5*x2<=40, 4*x1+6*x2<=60, x1<=8, x>=0 """ import numpy as np from scipy.optimize import linprog # --- Primales Problem -------------------------------------------------------- C_PRIMAL = np.array([150.0, 250.0]) A_PRIMAL = np.array([[2.0, 5.0], [4.0, 6.0], [1.0, 0.0]]) B_PRIMAL = np.array([40.0, 60.0, 8.0]) # --- Duales Problem: min b^T y u.d.N. A^T y >= c, y >= 0 ------------------ # linprog kennt nur <=, also A^T y >= c <=> -A^T y <= -c C_DUAL = B_PRIMAL A_DUAL = -A_PRIMAL.T B_DUAL = -C_PRIMAL def loese(): primal = linprog(c=-C_PRIMAL, A_ub=A_PRIMAL, b_ub=B_PRIMAL, bounds=[(0, None)] * 2, method="highs") dual = linprog(c=C_DUAL, A_ub=A_DUAL, b_ub=B_DUAL, bounds=[(0, None)] * 3, method="highs") if not primal.success or not dual.success: raise SystemExit("Primal oder Dual nicht loesbar.") return primal, dual if __name__ == "__main__": primal, dual = loese() x = primal.x y = dual.x z_primal = -primal.fun z_dual = dual.fun print("=" * 78) print(" PRIMALES PROBLEM") print("=" * 78) print(f"x* = ({x[0]:.4f}, {x[1]:.4f})") print(f"Z* = {z_primal:.4f}") print("\n" + "=" * 78) print(" DUALES PROBLEM") print("=" * 78) print(f"y* = ({y[0]:.4f}, {y[1]:.4f}, {y[2]:.4f})") print(f"W* = {z_dual:.4f}") print("\n" + "=" * 78) print(" STARKER DUALITAETSSATZ: c^T x* == b^T y* ?") print("=" * 78) print(f" Primal Z* = {z_primal:.6f}") print(f" Dual W* = {z_dual:.6f}") differenz = abs(z_primal - z_dual) print(f" Differenz = {differenz:.2e} -> " f"{'BESTAETIGT' if differenz < 1e-6 else 'VERLETZT!'}") print("\n" + "=" * 78) print(" KOMPLEMENTAERER SCHLUPF: s_i * y_i == 0 fuer alle i ?") print("=" * 78) schlupf = B_PRIMAL - A_PRIMAL @ x ressourcen = ["vCPU (s1)", "RAM (s2)", "Marktlimit (s3)"] for name, s, yi in zip(ressourcen, schlupf, y): produkt = s * yi print(f" {name:<16} Schlupf s={s:6.4f} Schattenpreis y={yi:6.4f} " f"s*y={produkt:.2e} {'OK' if abs(produkt) < 1e-6 else 'VERLETZT!'}") print("\nFazit: Das dual geloeste y* stimmt exakt mit den Schattenpreisen") print("überein, die die Simplex-Rechnung von Hand in der Z-Zeile") print("ablas - unabhaengig voneinander berechnet, identisches Ergebnis.") print("=" * 78)