Lösen Sie das folgende Minimierungsproblem mit OpenMDAO.
\begin{align}
{\rm min} \: \: \:& f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3 \\
\\
{\rm subject \: to} \: \: \:& -50.0\leq x \leq 50.0 \\
& -50.0\leq y \leq 50.0 \\
\\
{\rm answer} \: \: \: & f(x,y)=-27.333 \: \: {\rm at}\: x=6.667, \: y=-7.333 \\
\\
\end{align}
Definieren Sie eine Paraboloidklasse, die die Komponentenklasse wie unten gezeigt erbt.
paraboloid.py
from openmdao.api import Component
class Paraboloid(Component):
""" Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3 """
def __init__(self):
super(Paraboloid, self).__init__()
self.add_param('x', val=0.0)
self.add_param('y', val=0.0)
self.add_output('f_xy', shape=1)
def solve_nonlinear(self, params, unknowns, resids):
"""f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3
"""
x = params['x']; y = params['y']
unknowns['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0
def linearize(self, params, unknowns, resids):
""" Jacobian for our paraboloid."""
x = params['x']; y = params['y']
J = {}
J['f_xy', 'x'] = 2.0*x - 6.0 + y
J['f_xy', 'y'] = 2.0*y + 8.0 + x
return J
Fügen Sie in der Methode __init__
die Eingabevariablen von x und y
mit dem Anfangswert 0.0 hinzu.
Definieren Sie eine unbekannte Ausgabevariable f_xy
mit shape = 1 (numerischer Typ).
Die Methode "Solve_nonlinear" wird verwendet, um $ f (x, y) $ zu berechnen. Das in der Berechnung verwendete "x, y" verwendet jedoch den im Wörterbuch übergebenen Wert, der als Parameter des Arguments bezeichnet wird, und das Argument "unknowns" `Aktualisieren des Inhalts des Wörterbuchs
Es kann ohne die Methode "linearisieren" berechnet werden. Es gibt ein Wörterbuch zurück, das der Jacobi-Matrix entspricht.
J ['f_xy', 'x']
ist die tatsächliche Berechnung von $ \ frac {\ partiell f (x, y)} {\ partiell x} $.
Paraboloid ist eine Komponente (Klasse), die die Funktion $ f (x, y) $ darstellt. Um eine Optimierung durchzuführen, muss die Optimierungsmethode für Entwurfsvariablen und Zielfunktionen festgelegt werden. Führen Sie den folgenden Code mit einem Skript oder Interpreter in dem Verzeichnis aus, in dem paraboloid.py gespeichert ist
opt_paraboloid.py
from __future__ import print_function
from openmdao.api import IndepVarComp, Component, Problem, Group, SqliteRecorder
from openmdao.api import ScipyOptimizer
from paraboloid import Paraboloid
top = Problem()
root = top.root = Group()
root.add('p1', IndepVarComp('x', 13.0))
root.add('p2', IndepVarComp('y', -14.0))
root.add('p', Paraboloid())
root.connect('p1.x', 'p.x')
root.connect('p2.y', 'p.y')
top.driver = ScipyOptimizer()
top.driver.options['optimizer'] = 'SLSQP'
top.driver.add_desvar('p1.x', lower=-50, upper=50)
top.driver.add_desvar('p2.y', lower=-50, upper=50)
top.driver.add_objective('p.f_xy')
recorder = SqliteRecorder('paraboloid')
recorder.options['record_params'] = True
recorder.options['record_metadata'] = True
top.driver.add_recorder(recorder)
top.setup()
top.run()
top.cleanup()
print('Minimum of %f found at (%f, %f)' % (top['p.f_xy'], top['p.x'], top['p.y']))
Zunächst werden die erforderlichen Klassen in der 1. bis 4. Zeile importiert.
Zeile 6 definiert ein Problem namens top (eine Instanz von Problem), das buchstäblich die Spitze dieses Optimierungsproblems darstellt.
Zeile 7 erstellt eine neue Gruppe für die betreffende Wurzel oben.
Die Zeilen 9 und 10 fügen die Komponente (IndepVarComp) von p1 und p2 mit den Variablen "x" und "y" hinzu.
Dieses p1.x, p2.y
ist die Entwurfsvariable dieses Problems (oben), die einen beliebigen Wert annehmen kann.
Zeile 11 fügt der Wurzel eine Paraboloid-Instanz mit dem Namen p hinzu.
Die Zeilen 12 und 13 verbinden die Entwurfsvariablen "p1.x, p2.y" mit den Paraboloid-Eingangsvariablen "p.x, p.y".
Wenn sich die Entwurfsvariablen in "p1.x" und "p2.y" ändern, ändert sich folglich auch die Ausgabevariable "p.f_xy" von Paraboloid.
Die 15. Zeile top.driver = ScipyOptimizer ()
und später definieren die Optimierungsmethode.
In Zeile 15 wird ScipyOptimizer als Optimierungstreiber angegeben. Jede in scipy implementierte Optimierungsmethode kann verwendet werden.
Die Optimierungsmethode in der 16. Zeile ist SLSQP. Sequentielle sekundäre Planungsmethode.
Die Zeilen 17 und 18 legen den möglichen Bereich der Entwurfsvariablen "p1.x, p2.y" fest.
Und in der 19. Zeile wird die Ausgangsvariable "p.f_xy" des Araboloids für die Zielfunktion angegeben.
Die Zeilen 21-24 sind die Rekordereinstellungen, die den Betrieb des Treibers aufzeichnen. Zeile 21 Das Argument von SqliteRecorder ist die Sicherungsdatei der aufgezeichneten Daten.
Die 26. Zeile ist das Setup des Hauptproblems, die 27. Zeile ist die Optimierung und die 28. Zeile ist die Bereinigung.
Das folgende Ausführungsergebnis wird angezeigt.
stdout
Optimization terminated successfully. (Exit mode 0)
Current function value: [-27.33333329]
Iterations: 4
Function evaluations: 5
Gradient evaluations: 4
Optimization Complete
Minimum of -27.333333 found at (6.666856, -7.333543)
Lesen Sie als Nächstes den von SqliteRecorder aufgezeichneten Operationsdatensatz (Dateiname: Paraboloid). Führen Sie den folgenden Code auf dem Interpreter aus.
IPython
import numpy as np
from matplotlib import pyplot as plt
import sqlitedict
db =sqlitedict.SqliteDict("paraboloid","iterations")
a = np.zeros(5)
for i in range(0,5):
a[i] = db[db.keys()[i]]["Unknowns"]["p.f_xy"]
Ipython fuhr fort
plt.plot(np.arange(0,5,1),a,"-o")
plt.xlabel("iterations")
plt.ylabel("f_xy")
plt.show()
Recommended Posts