55 lines
1.8 KiB
Python
55 lines
1.8 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
|
||
|
|
# QP_Grundlagen.py
|
||
|
|
"""
|
||
|
|
Kapitel QP/NLP: Die drei Faelle aus der Konvexitaets-Tabelle (Abschnitt
|
||
|
|
'Das quadratische Programm') an
|
||
|
|
einem Mini-QP demonstriert: P positiv definit, P (singulaer) semidefinit,
|
||
|
|
P mit negativem Eigenwert.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import numpy as np
|
||
|
|
import cvxpy as cp
|
||
|
|
|
||
|
|
|
||
|
|
def loese_qp(P, q, name):
|
||
|
|
n = len(q)
|
||
|
|
w = cp.Variable(n)
|
||
|
|
ziel = cp.Minimize(0.5 * cp.quad_form(w, P) + q @ w)
|
||
|
|
bedingungen = [cp.sum(w) == 1, w >= 0]
|
||
|
|
problem = cp.Problem(ziel, bedingungen)
|
||
|
|
|
||
|
|
print(f"\n--- {name} ---")
|
||
|
|
eigenwerte = np.linalg.eigvalsh(P)
|
||
|
|
print(f"Eigenwerte von P: {np.round(eigenwerte, 4)}")
|
||
|
|
print(f"DCP-konvex (CVXPY-Pruefung)? {problem.is_dcp()}")
|
||
|
|
|
||
|
|
if not problem.is_dcp():
|
||
|
|
print("-> CVXPY lehnt das Problem ab, BEVOR ueberhaupt ein Solver laeuft.")
|
||
|
|
return
|
||
|
|
|
||
|
|
problem.solve()
|
||
|
|
print(f"Status: {problem.status}")
|
||
|
|
print(f"w* = {np.round(w.value, 4)}")
|
||
|
|
print(f"Zielwert = {problem.value:.6f}")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
q = np.zeros(2)
|
||
|
|
|
||
|
|
# Fall 1: P positiv definit -> eindeutiges Minimum
|
||
|
|
P_definit = np.array([[2.0, 0.5], [0.5, 1.0]])
|
||
|
|
loese_qp(P_definit, q, "P positiv definit")
|
||
|
|
|
||
|
|
# Fall 2: P singulaer/semidefinit (zwei "identische" Assets) -> unendlich viele Minima
|
||
|
|
P_semidefinit = np.array([[1.0, 1.0], [1.0, 1.0]])
|
||
|
|
loese_qp(P_semidefinit, q, "P positiv semidefinit (singulaer)")
|
||
|
|
|
||
|
|
# Fall 3: P mit negativem Eigenwert -> nicht konvex
|
||
|
|
P_indefinit = np.array([[1.0, 2.0], [2.0, 1.0]])
|
||
|
|
loese_qp(P_indefinit, q, "P indefinit (negativer Eigenwert)")
|
||
|
|
|
||
|
|
print("\n--- Nachweis: 'unendlich viele Minima' im semidefiniten Fall ---")
|
||
|
|
for punkt in [np.array([1.0, 0.0]), np.array([0.0, 1.0]), np.array([0.3, 0.7])]:
|
||
|
|
wert = 0.5 * punkt @ P_semidefinit @ punkt
|
||
|
|
print(f" w = {punkt} -> Zielwert = {wert:.4f} (identisch, obwohl w verschieden)")
|