Expressions — Building Blocks¶
The Expression class is the fundamental unit of Neurogebra. Everything in the library is built on expressions.
What is an Expression?¶
An Expression is a symbolic mathematical formula that can:
- ✅ Evaluate — compute a numerical result
- ✅ Differentiate — compute gradients symbolically
- ✅ Explain — describe itself in plain English
- ✅ Compose — combine with other expressions
- ✅ Train — learn parameters from data
- ✅ Visualize — plot itself
Creating an Expression¶
from neurogebra import Expression
# Simple: name + formula
square = Expression("square", "x**2")
# With parameters
line = Expression("line", "m*x + b", params={"m": 2.0, "b": 1.0})
# With trainable parameters
trainable_line = Expression(
"trainable_line",
"m*x + b",
params={"m": 0.0, "b": 0.0},
trainable_params=["m", "b"]
)
# With metadata
custom = Expression(
"my_function",
"x * tanh(x)",
metadata={
"category": "activation",
"description": "Custom activation function",
"usage": "Experimental hidden layers"
}
)
Evaluating Expressions¶
With Keyword Arguments¶
expr = Expression("poly", "a*x**2 + b*x + c",
params={"a": 1.0, "b": -2.0, "c": 1.0})
# Parameters are substituted automatically
result = expr.eval(x=3)
print(result) # 1*9 + (-2)*3 + 1 = 4.0
With NumPy Arrays¶
import numpy as np
square = Expression("square", "x**2")
x = np.array([1, 2, 3, 4, 5])
result = square.eval(x=x)
print(result) # [ 1 4 9 16 25]
Expression with Multiple Variables¶
loss = Expression("mse", "(y_pred - y_true)**2")
result = loss.eval(y_pred=3.0, y_true=5.0)
print(result) # 4.0
Expression Properties¶
from neurogebra import MathForge
forge = MathForge()
sigmoid = forge.get("sigmoid")
# Name
print(sigmoid.name) # "sigmoid"
# Symbolic formula (SymPy expression)
print(sigmoid.symbolic_expr) # 1/(1 + exp(-x))
# Variables (free symbols)
print(sigmoid.variables) # [x]
# Parameters
print(sigmoid.params) # {}
# Metadata
print(sigmoid.metadata)
# {'category': 'activation', 'description': '...', ...}
Explaining Expressions¶
Every expression can explain itself:
relu = forge.get("relu")
print(relu.explain())
sigmoid = forge.get("sigmoid")
print(sigmoid.explain())
# Metadata gives you detailed info
print(sigmoid.metadata["description"])
print(sigmoid.metadata["usage"])
print(sigmoid.metadata["pros"])
print(sigmoid.metadata["cons"])
Expression Arithmetic¶
Expressions support standard math operations:
from neurogebra import Expression
a = Expression("a", "x**2")
b = Expression("b", "x + 1")
# Addition
c = a + b # x² + x + 1
# Subtraction
d = a - b # x² - x - 1
# Multiplication
e = a * b # x² * (x + 1) = x³ + x²
# Scalar multiplication
f = 2 * a # 2x²
g = a * 0.5 # 0.5x²
Cloning Expressions¶
Create independent copies:
original = forge.get("relu")
clone = original.clone()
# Modifying clone doesn't affect original
clone.params["new_param"] = 42
print("new_param" in original.params) # False
Calling Expressions¶
Expressions are callable (you can use them like functions):
relu = forge.get("relu")
# These are equivalent:
result1 = relu.eval(x=5)
result2 = relu(5)
print(result1, result2) # 5, 5
Complete Example¶
from neurogebra import Expression, MathForge
import numpy as np
# === Create Custom Expression ===
gaussian = Expression(
"gaussian",
"exp(-x**2 / (2 * sigma**2))",
params={"sigma": 1.0},
metadata={
"category": "statistics",
"description": "Gaussian (bell curve) function"
}
)
# === Evaluate ===
x = np.linspace(-3, 3, 7)
y = gaussian.eval(x=x)
print("Gaussian values:")
for xi, yi in zip(x, y):
print(f" x={xi:+.1f} → f(x)={yi:.4f}")
# === Gradient ===
grad = gaussian.gradient("x")
print(f"\nGradient formula: {grad.symbolic_expr}")
# === Change parameter ===
gaussian.params["sigma"] = 0.5 # Narrower bell curve
y_narrow = gaussian.eval(x=x)
print("\nNarrower Gaussian:")
for xi, yi in zip(x, y_narrow):
print(f" x={xi:+.1f} → f(x)={yi:.4f}")
Quick Reference¶
| Property/Method | Description | Example |
|---|---|---|
.name |
Expression name | "relu" |
.symbolic_expr |
SymPy formula | Max(0, x) |
.variables |
Free variables | [x] |
.params |
Parameter dict | {"alpha": 0.01} |
.metadata |
Extra info | {"category": "activation"} |
.eval(**kwargs) |
Evaluate numerically | .eval(x=5) |
.gradient(var) |
Symbolic derivative | .gradient("x") |
.compose(other) |
Compose: self(other) | .compose(linear) |
.clone() |
Deep copy | .clone() |
.explain() |
Plain English explanation | .explain() |
.visualize() |
Plot the expression | .visualize() |
Next: Activation Functions →