Components
The Component class is the foundation of Amigo. All analysis and computation in Amigo occurs within classes that inherit from amigo.Component. A component encapsulates a computational model with well-defined inputs, outputs, constraints, and objectives.
Basic Structure
The minimal structure of an Amigo component consists of:
- A class inheriting from
amigo.Component - An
__init__method defining the interface - A
computemethod implementing the analysis
import amigo as am
class MyComponent(am.Component):
def __init__(self):
super().__init__()
# Define inputs, outputs, constraints, objectives
self.add_input("x", value=1.0, lower=0.0, upper=10.0)
self.add_output("y")
def compute(self):
# Extract inputs
x = self.inputs["x"]
# Perform computation
self.outputs["y"] = 2 * x
Always call super().__init__() at the beginning of your component's constructor.
The Constructor
The constructor defines the component's interface. This is where you declare all variables your component will use:
def __init__(self):
super().__init__()
# Constants (compile-time values)
self.add_constant("g", value=9.81)
# Design variables (optimizer can change these)
self.add_input("x", value=0.0, lower=-10.0, upper=10.0)
# Outputs (computed values that can be linked)
self.add_output("lift")
# Constraints (must be satisfied)
self.add_constraint("stress", upper=0.0)
# Objective (function to minimize)
self.add_objective("weight")
The Compute Method
The compute method contains your analysis logic. Values are accessed through dictionary-like member objects:
def compute(self):
# Read inputs and constants
x = self.inputs["x"]
g = self.constants["g"]
# Store intermediate variables (optional)
self.vars["temp"] = x * x
# Set outputs
self.outputs["lift"] = 10 * x
# Set constraints
self.constraints["stress"] = x * x - 100.0
# Set objective
self.objective["weight"] = x
Variables in compute() are symbolic, not numeric. They encode mathematical operations for automatic differentiation and C++ code generation.
Example: Rosenbrock Function
A complete example implementing the Rosenbrock optimization problem:
import amigo as am
class Rosenbrock(am.Component):
def __init__(self):
super().__init__()
# Design variables
self.add_input("x1", value=-1.0, lower=-2.0, upper=2.0)
self.add_input("x2", value=-1.0, lower=-2.0, upper=2.0)
# Objective to minimize
self.add_objective("obj")
# Constraint: x1² + x2² ≤ 1
self.add_constraint("con", upper=0.0)
def compute(self):
x1 = self.inputs["x1"]
x2 = self.inputs["x2"]
# Rosenbrock function
self.objective["obj"] = (1 - x1)**2 + 100*(x2 - x1**2)**2
# Circular constraint
self.constraints["con"] = x1**2 + x2**2 - 1.0