operations_research/OR_HTML_04/programme/QP_Grundlagen.py
dschlueter b7af2f1d9a Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.

Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.

Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.

Zusaetzlich in diesem Commit:

* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
  figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
  unveraendert daneben bestehen. ortools steht in der Grundausstattung,
  highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
  schlanken Installation gar nicht erst auftreten.

* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
  importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
  steht in requirements.txt, wird aber von keinem Programm importiert,
  sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
  [empfehlungen]).

* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
  ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
  Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.

* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
  tatsaechlichen aus erzeuge_titelseite.py korrigiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00

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)")