Convenience Interface
The convenience interface provides a simple, high-level API for optimizing arbitrary Python functions without needing to understand the details of tensor networks.
Quick Start
Basic optimization of a function with named parameters:
from qutree import optimize_function
# Define your function with named parameters
def rosenbrock(x, y):
return (1 - x)**2 + 100*(y - x**2)**2
# Define parameter bounds
bounds = {'x': (-2, 2), 'y': (-1, 3)}
# Optimize!
result = optimize_function(rosenbrock, bounds)
print(f"Optimal x={result['x']['x']:.3f}, y={result['x']['y']:.3f}")
print(f"Minimum value: {result['fun']:.6f}")
Function Signatures
The convenience interface supports multiple function signatures:
Named Parameters
def my_func(x, y, z):
return x**2 + y**2 + z**2
bounds = {'x': (-5, 5), 'y': (-5, 5), 'z': (-5, 5)}
result = optimize_function(my_func, bounds)
Dictionary Parameter
def my_func(params):
return params['x']**2 + params['y']**2
bounds = {'x': (-5, 5), 'y': (-5, 5)}
result = optimize_function(my_func, bounds)
Array Parameter
def my_func(x):
return np.sum(x**2)
# Can use list of bounds for array functions
bounds = [(-5, 5), (-5, 5), (-5, 5)]
result = minimize(my_func, bounds)
Per-Parameter Grid Points
Use different grid resolutions for different parameters to balance accuracy and computational cost:
def anisotropic(x, y, z):
# y has a narrow valley, needs finer resolution
return (x - 1)**2 + 100*(y - 0.5)**2 + (z + 1)**2
bounds = {'x': (-2, 3), 'y': (-1, 2), 'z': (-3, 1)}
# Use different grid resolutions
grid_points = {
'x': 11, # Coarse grid
'y': 31, # Fine grid for narrow valley
'z': 11 # Coarse grid
}
result = optimize_function(
anisotropic,
bounds,
grid_points=grid_points,
n_sweeps=3
)
When to use per-parameter grids:
Functions with narrow valleys in some dimensions
Parameters with different sensitivities
High-dimensional problems where you want to focus resolution
This can significantly reduce computational cost. In the example above, using per-parameter grids requires ~3,700 evaluations vs ~26,000 for a uniform 31×31×31 grid.
Warm-Start Optimization
Provide initial guess points to speed up convergence:
def quadratic(x, y):
return (x - 1.5)**2 + (y + 0.5)**2
bounds = {'x': (0, 3), 'y': (-2, 1)}
# Provide start points near the optimum
start_points = {
'x': [1.0, 1.2, 1.4, 1.6, 1.8],
'y': [-1.0, -0.8, -0.6, -0.4, -0.2]
}
result = optimize_function(
quadratic,
bounds,
start_points=start_points,
bond_dim=4 # Must have at least bond_dim points
)
Method Selection
The optimizer automatically chooses the best tensor network structure based on dimensionality:
# For low-dimensional problems (< 20 dimensions)
# Uses tensor train network (default)
bounds_3d = {f'x{i}': (-5, 5) for i in range(3)}
result = optimize_function(my_func, bounds_3d, method='auto')
# For high-dimensional problems (>= 20 dimensions)
# Automatically uses balanced tree network
bounds_25d = {f'x{i}': (-5, 5) for i in range(25)}
result = optimize_function(my_func, bounds_25d, method='auto')
You can also manually specify the method:
# Force tensor train
result = optimize_function(my_func, bounds, method='tensor_train')
# Force balanced tree
result = optimize_function(my_func, bounds, method='balanced_tree')
Hyperparameter Tuning Example
A practical example for machine learning hyperparameter optimization:
from qutree import optimize_function
# Define your objective (e.g., validation error)
def model_error(learning_rate, batch_size, dropout_rate, l2_reg):
# Replace with your actual model training/validation
# This is a placeholder that returns simulated error
error = (learning_rate - 0.001)**2 + (batch_size - 64)**2 / 1000
error += (dropout_rate - 0.3)**2 + (l2_reg - 0.01)**2
return error
# Define hyperparameter search space
bounds = {
'learning_rate': (1e-5, 1e-1),
'batch_size': (16, 128),
'dropout_rate': (0.0, 0.5),
'l2_reg': (1e-6, 1e-1)
}
# Use different grid resolutions for different parameters
grid_points = {
'learning_rate': 25, # Fine grid
'batch_size': 15, # Coarse grid
'dropout_rate': 11, # Coarse grid
'l2_reg': 21 # Medium grid
}
# Optimize hyperparameters
result = optimize_function(
model_error,
bounds,
grid_points=grid_points,
n_sweeps=5
)
print("Best hyperparameters:")
for param, value in result['x'].items():
print(f" {param}: {value:.6f}")
print(f"Best validation error: {result['fun']:.6f}")
print(f"Function evaluations: {result['n_calls']}")
scipy.optimize-like Interface
For users familiar with scipy, the minimize function provides a similar interface:
from qutree import minimize
def sphere(x):
return np.sum(x**2)
# List of bounds like scipy.optimize.minimize
bounds = [(-5, 5), (-5, 5), (-5, 5)]
result = minimize(sphere, bounds, n_sweeps=3, bond_dim=4)
# Access results
print(f"Optimal value: {result['fun']}")
print(f"Optimal point: {result['x']}") # Dict with x0, x1, x2
Parameters Reference
optimize_function(func, bounds, …)
- Parameters:
- funccallable
Function to minimize. Can accept named parameters, dict, or array.
- boundsdict
Dictionary mapping parameter names to (min, max) tuples. Example:
{'x': (0, 10), 'y': (-5, 5)}
- methodstr, default=’auto’
Optimization method: ‘auto’, ‘tensor_train’ (‘tt’), or ‘balanced_tree’ (‘bt’)
- n_sweepsint, default=3
Number of optimization sweeps. More sweeps = better convergence.
- bond_dimint, default=4
Bond dimension r. Larger values = more accurate but slower.
- grid_pointsint or dict, default=21
Number of grid points per dimension. Can be:
int: Same number for all dimensions
dict: Per-parameter grid points, e.g.
{'x': 21, 'y': 31}
- start_pointsdict, optional
Initial guess points for warm-start. Format:
{'x': [x1, x2, ...], 'y': [y1, y2, ...]}Each parameter needs >= bond_dim points.
- verbosebool, default=True
Print optimization progress and results.
- Returns:
- Dictionary containing:
x : dict of optimal parameter values
fun : optimal function value
n_calls : number of function evaluations
n_cache_hits : number of cache hits
objective : Objective instance with full history
network : optimized tensor network
Tips and Best Practices
Grid Resolution
Start with 11-21 grid points for initial exploration
Increase to 31-51 for final refinement
Use per-parameter grids for efficiency in high dimensions
Number of Sweeps
2-3 sweeps often sufficient for simple functions
5-10 sweeps for complex landscapes
Monitor convergence by checking if result improves
Bond Dimension
Start with bond_dim=4 (default)
Increase to 6-8 for more accurate results
Higher bond dimensions increase computational cost
High-Dimensional Problems
Use balanced tree for >= 20 dimensions
Use coarser grids (11 points) to keep cost manageable
Consider per-parameter grids if some dimensions are more important
Debugging
Set
verbose=Trueto see optimization progressCheck
result['n_calls']to understand computational costExamine
result['objective'].logger.dffor full optimization history
See Also
Tree Tensor Network Optimization (TTNOpt) - Low-level TTNOpt interface
Tree Tensor Network Structures - Understanding tensor network structures
../examples - More usage examples