Adaptive Selection: Let BusinessMath Choose the Best Algorithm
BusinessMath Quarterly Series
16 min read
Part 31 of 12-Week BusinessMath Series
What You’ll Learn
- Understanding when to use each optimization algorithm
- Leveraging AdaptiveOptimizer for automatic algorithm selection
- Problem characteristics that guide algorithm choice
- Performance profiling and benchmarking
- Fallback strategies when optimization fails
- Building self-tuning optimization pipelines
The Problem
BusinessMath provides 10+ optimization algorithms:
- Gradient descent, BFGS, Newton-Raphson
- Simulated annealing, genetic algorithms, particle swarm
- Simplex, branch-and-bound, conjugate gradient
Which should you use? The answer depends on:
- Problem size (10 variables vs. 1,000)
- Smoothness (continuous vs. discontinuous objective)
- Constraints (none, linear, nonlinear)
- Budget (seconds vs. minutes)
Choosing wrong can mean: no solution, slow convergence, or local optima.
The Solution
BusinessMath’s AdaptiveOptimizer analyzes your problem and automatically selects the best algorithm. It considers problem characteristics, tries multiple methods in parallel, and returns the best result.
Automatic Algorithm Selection
Business Problem: Optimize portfolio allocation without worrying about algorithm details.
import BusinessMath
import Foundation
let assets: [String] = ["US Stocks", "Intl Stocks", "Bonds", "Real Estate"]
let expectedReturns = VectorN([0.10, 0.12, 0.04, 0.09])
let riskFreeRate = 0.03
// Covariance matrix (variances on diagonal, covariances off-diagonal)
let covarianceMatrix = [
[0.0400, 0.0150, 0.0020, 0.0180], // US Stocks
[0.0150, 0.0625, 0.0015, 0.0200], // Intl Stocks
[0.0020, 0.0015, 0.0036, 0.0010], // Bonds
[0.0180, 0.0200, 0.0010, 0.0400] // Real Estate
]
// Define your optimization problem
let portfolioObjective: @Sendable (VectorN
) -> Double = { weights in // Minimize negative Sharpe ratio let expectedReturn = weights.dot(expectedReturns) var variance = 0.0 for i in 0..
>.budgetConstraint let longOnlyConstraints = MultivariateConstraint
>.nonNegativity(dimension: assets.count) let constraints: [MultivariateConstraint
>] = [budgetConstraint] + longOnlyConstraints // Let AdaptiveOptimizer choose the algorithm let adaptive = AdaptiveOptimizer
>() do { let result = try adaptive.optimize( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: constraints ) print("Optimal Portfolio:") for (asset, weight) in zip(assets, result.solution.toArray()) { if weight > 0.01 { print(" \(asset): \(weight.percent())") } } print("\nOptimization Details:") print(" Algorithm Used: \(result.algorithmUsed)") print(" Selection Reason: \(result.selectionReason)") print(" Iterations: \(result.iterations)") print(" Sharpe Ratio: \((-result.objectiveValue).number())") } catch { print("Optimization failed: \(error)") }
Parallel Multi-Start Optimization
Pattern: Run the same algorithm from multiple starting points in parallel to find global optima.
import BusinessMath
import Foundation
// Use ParallelOptimizer for problems with multiple local minima
let parallelOptimizer = ParallelOptimizer
>( algorithm: .inequality, // Use inequality-constrained optimizer numberOfStarts: 20, // Try 20 different starting points maxIterations: 1000, tolerance: 1e-6 ) // Define search region for starting points let searchRegion = ( lower: VectorN(repeating: 0.0, count: 4), upper: VectorN(repeating: 1.0, count: 4) ) // Run optimization in parallel (async/await) let parallelResult = try await parallelOptimizer.optimize( objective: portfolioObjective, searchRegion: searchRegion, constraints: constraints ) print("Best solution found across \(parallelResult.allResults.count) attempts") print("Success rate: \(parallelResult.successRate.percent())") print("Objective value: \(parallelResult.objectiveValue.number())")
Algorithm Selection Based on Problem Characteristics
Pattern: Analyze problem structure to choose algorithm.
AdaptiveOptimizer uses a decision tree to select the best algorithm:
// AdaptiveOptimizer's actual selection logic:
// Rule 1: Inequality constraints? → InequalityOptimizer (penalty-barrier method)
if hasInequalityConstraints {
// Use interior-point penalty-barrier method
return .inequality
}
// Rule 2: Equality constraints only? → ConstrainedOptimizer (augmented Lagrangian)
else if hasEqualityConstraints {
// Use augmented Lagrangian method
return .constrained
}
// Rule 3: Large unconstrained problem (>100 variables)? → Gradient Descent
else if problemSize > 100 {
// Memory-efficient gradient descent with adaptive learning rate
return .gradientDescent
}
// Rule 4: Prefer accuracy + small problem (<10 vars)? → Newton-Raphson
else if preferAccuracy && problemSize < 10 {
// Full Newton method with Hessian for quadratic convergence
return .newtonRaphson
}
// Rule 5: Very small problem (≤5 vars)? → Newton-Raphson
else if problemSize <= 5 {
// Newton-Raphson for fast convergence
return .newtonRaphson
}
// Default: Gradient Descent (best balance)
else {
return .gradientDescent
}
// Use analyzeProblem() to see what will be selected:
let adaptive = AdaptiveOptimizer
>() let analysis = adaptive.analyzeProblem( initialGuess: VectorN(repeating: 0.25, count: 4), constraints: constraints, hasGradient: false ) print("Problem size: \(analysis.size)") print("Has constraints: \(analysis.hasConstraints)") print("Has inequalities: \(analysis.hasInequalities)") print("Recommended: \(analysis.recommendedAlgorithm)") print("Reason: \(analysis.reason)")
Understanding Optimizer Preferences
Pattern: Control adaptive selection with preferences.
// Prefer speed: Uses higher learning rates and simpler algorithms
let fastOptimizer = AdaptiveOptimizer
>( preferSpeed: true, maxIterations: 500, tolerance: 1e-4 // Looser tolerance for faster convergence ) // Prefer accuracy: Uses Newton-Raphson for small problems let accurateOptimizer = AdaptiveOptimizer
>( preferAccuracy: true, maxIterations: 2000, tolerance: 1e-8 // Tighter tolerance for precise results ) // Example: Portfolio optimization with accuracy preference let result = try accurateOptimizer.optimize( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: 4), constraints: constraints ) print("With preferAccuracy=true:") print(" Algorithm: \(result.algorithmUsed)") print(" Reason: \(result.selectionReason)") print(" Iterations: \(result.iterations)") print(" Converged: \(result.converged)") // Compare with default settings let defaultResult = try AdaptiveOptimizer
>().optimize( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: 4), constraints: constraints ) print("\nWith default settings:") print(" Algorithm: \(defaultResult.algorithmUsed)") print(" Reason: \(defaultResult.selectionReason)")
How It Works
AdaptiveOptimizer Decision Tree
Has Inequality Constraints?
├─ YES → InequalityOptimizer (penalty-barrier method)
│
└─ NO → Has Equality Constraints?
├─ YES → ConstrainedOptimizer (augmented Lagrangian)
│
└─ NO (Unconstrained) → Problem Size?
├─ > 100 variables → Gradient Descent (memory-efficient)
│
├─ ≤ 5 variables → Newton-Raphson (fast convergence)
│
├─ < 10 variables + preferAccuracy → Newton-Raphson
│
└─ Default → Gradient Descent (best balance)
Comparing Optimizer Performance
import Foundation
// Compare different optimizers on the same problem
struct OptimizerComparison {
let objective: (VectorN
) -> Double let initialGuess: VectorN
let constraints: [MultivariateConstraint
>] func compare() throws { print("Optimizer Performance Comparison") print("═══════════════════════════════════════════════") // Test 1: Gradient Descent let startGD = Date() let gdOptimizer = MultivariateGradientDescent
>( learningRate: 0.01, maxIterations: 1000, tolerance: 1e-6 ) let gdResult = try gdOptimizer.minimize( function: objective, gradient: { try numericalGradient(objective, at: $0) }, initialGuess: initialGuess ) let gdTime = Date().timeIntervalSince(startGD) print("Gradient Descent:") print(" Value: \(gdResult.value.number(4))") print(" Time: \(gdTime.number(2))s") print(" Iterations: \(gdResult.iterations)") // // Test 2: Newton-Raphson (if problem is small) // NOTE: This will likely crash if run in a playground. To understand when and how to use Newton-Raphson, check out our [Newton-Raphson Guide](../05-fri-newton-raphson-guide) // if initialGuess.dimension <= 10 { // let startNR = Date() // let nrOptimizer = MultivariateNewtonRaphson
>( // maxIterations: 1000, // tolerance: 1e-6 // ) // let nrResult = try nrOptimizer.minimize( // function: objective, // gradient: { try numericalGradient(objective, at: $0) }, // hessian: { try numericalHessian(objective, at: $0) }, // initialGuess: initialGuess // ) // let nrTime = Date().timeIntervalSince(startNR) // // print("\nNewton-Raphson:") // print(" Value: \(nrResult.value.number(4))") // print(" Time: \(nrTime.number(2))s") // print(" Iterations: \(nrResult.iterations)") // } // Test 3: Adaptive (let it choose) let startAdaptive = Date() let adaptiveOptimizer = AdaptiveOptimizer
>() let adaptiveResult = try adaptiveOptimizer.optimize( objective: objective, initialGuess: initialGuess, constraints: constraints ) let adaptiveTime = Date().timeIntervalSince(startAdaptive) print("\nAdaptive Optimizer:") print(" Algorithm chosen: \(adaptiveResult.algorithmUsed)") print(" Value: \(adaptiveResult.objectiveValue.number(4))") print(" Time: \(adaptiveTime.number(2))s") print(" Iterations: \(adaptiveResult.iterations)") } } // Run comparison let comparison = OptimizerComparison( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: 4), constraints: constraints ) try comparison.compare()
Real-World Application
Supply Chain Optimization: Multi-Facility Production
Company: National manufacturer with 12 facilities, 8 products, 40 distribution centers Challenge: Minimize total costs (production + shipping) subject to capacity and demand
Problem Characteristics:
- 96 variables (12 facilities × 8 products)
- Nonlinear costs (volume discounts)
- Multiple constraints (capacity, demand, quality)
Algorithm Selection Process:
import BusinessMath
import Foundation
// Problem dimensions
let numFacilities = 12
let numProducts = 8
let numVariables = numFacilities * numProducts // 96 variables
// Cost structure ($/unit for each facility-product combination)
// Lower costs for specialized facilities, higher for general purpose
let productionCosts = (0..
) -> Double = { production in var totalCost = 0.0 // Production costs with volume discounts for i in 0..
volumeDiscountThreshold { let discountedAmount = quantity - volumeDiscountThreshold totalCost += productionCosts[i] * volumeDiscountThreshold totalCost += productionCosts[i] * volumeDiscountRate * discountedAmount } else { totalCost += baseCost } } return totalCost } // Current production (starting point) // Distribute demand equally across facilities initially let currentProduction = VectorN((0..
>] = [] for facility in 0..
>] = [] for product in 0..
>.nonNegativity(dimension: numVariables) let allConstraints = capacityConstraints + demandConstraints + nonNegativityConstraints // Let AdaptiveOptimizer analyze and choose do { print(String(repeating: "=", count: 70)) print("SUPPLY CHAIN OPTIMIZATION: MULTI-FACILITY PRODUCTION") print(String(repeating: "=", count: 70)) print("Facilities: \(numFacilities)") print("Products: \(numProducts)") print("Variables: \(numVariables)") print("Total demand: \(productDemands.reduce(0, +).number(0)) units/month") print("Total capacity: \(facilityCapacities.reduce(0, +).number(0)) units/month") print() let supplyChainOptimizer = AdaptiveOptimizer
>( maxIterations: 2000, tolerance: 1e-5 ) // First, analyze what algorithm will be selected let analysis = supplyChainOptimizer.analyzeProblem( initialGuess: currentProduction, constraints: allConstraints, hasGradient: false ) print("Problem Analysis:") print(" Size: \(analysis.size) variables") print(" Constraints: \(analysis.hasConstraints)") print(" Inequalities: \(analysis.hasInequalities)") print(" Recommended: \(analysis.recommendedAlgorithm)") print(" Reason: \(analysis.reason)") print() // Run optimization let startTime = Date() let supplyChainResult = try supplyChainOptimizer.optimize( objective: totalCostObjective, initialGuess: currentProduction, constraints: allConstraints ) let elapsedTime = Date().timeIntervalSince(startTime) print("Supply Chain Optimization Results:") print(" Algorithm Selected: \(supplyChainResult.algorithmUsed)") print(" Total Cost: \(supplyChainResult.objectiveValue.currency())") print(" Time: \(elapsedTime.number())s") print(" Iterations: \(supplyChainResult.iterations)") print(" Converged: \(supplyChainResult.converged)") // Calculate cost savings vs initial let initialCost = totalCostObjective(currentProduction) let savings = initialCost - supplyChainResult.objectiveValue let savingsPercent = (savings / initialCost) print("\nCost Savings:") print(" Initial cost: \(initialCost.currency())") print(" Optimized cost: \(supplyChainResult.objectiveValue.currency())") print(" Savings: \(savings.currency()) (\(savingsPercent.percent(1)))") // Show production summary var facilitiesUsed = 0 for facility in 0..
1.0 { facilitiesUsed += 1 } } print("\nProduction Summary:") print(" Active facilities: \(facilitiesUsed)/\(numFacilities)") print(" Total units produced: \(supplyChainResult.solution.sum.number(0))") } catch { print("Optimization failed: \(error)") }
AdaptiveOptimizer Analysis:
- Problem size: 96 variables → “medium-large”
- Constraints: Mix of equality and inequality → InequalityOptimizer
- Decision: Use penalty-barrier method (InequalityOptimizer)
Results:
- Cost reduction: $2.4M/year (8% improvement)
- Optimization time: 3.2 minutes (acceptable for weekly planning)
- Solution quality: Consistently within 1% of best-known solutions
Try It Yourself
Click to expand full playground code
import BusinessMath
import Foundation
// MARK: - Basic Portfolio Optimization with AdaptiveOptimizer
let assets = ["US Stocks", "Intl Stocks", "Bonds", "Real Estate"]
let expectedReturns = VectorN([0.10, 0.12, 0.04, 0.09])
let riskFreeRate = 0.03
// Covariance matrix (variances on diagonal, covariances off-diagonal)
let covarianceMatrix = [
[0.0400, 0.0150, 0.0020, 0.0180], // US Stocks
[0.0150, 0.0625, 0.0015, 0.0200], // Intl Stocks
[0.0020, 0.0015, 0.0036, 0.0010], // Bonds
[0.0180, 0.0200, 0.0010, 0.0400] // Real Estate
]
// Define optimization problem - maximize Sharpe ratio
let portfolioObjective: @Sendable (VectorN
) -> Double = { weights in // Minimize negative Sharpe ratio let expectedReturn = weights.dot(expectedReturns) var variance = 0.0 for i in 0..
>.budgetConstraint let longOnlyConstraints = MultivariateConstraint
>.nonNegativity(dimension: assets.count) let constraints: [MultivariateConstraint
>] = [budgetConstraint] + longOnlyConstraints // Let AdaptiveOptimizer choose the algorithm let adaptive = AdaptiveOptimizer
>() do { // First, analyze what algorithm will be selected let analysis = adaptive.analyzeProblem( initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: constraints, hasGradient: false ) print("Problem Analysis:") print(" Size: \(analysis.size) variables") print(" Has constraints: \(analysis.hasConstraints)") print(" Has inequalities: \(analysis.hasInequalities)") print(" Recommended: \(analysis.recommendedAlgorithm)") print(" Reason: \(analysis.reason)") print() // Run optimization let result = try adaptive.optimize( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: constraints ) print("Optimal Portfolio:") for (asset, weight) in zip(assets, result.solution.toArray()) { if weight > 0.01 { print(" \(asset): \(weight.percent())") } } print("\nOptimization Details:") print(" Algorithm Used: \(result.algorithmUsed)") print(" Selection Reason: \(result.selectionReason)") print(" Iterations: \(result.iterations)") print(" Converged: \(result.converged)") print(" Sharpe Ratio: \((-result.objectiveValue).number())") // Calculate portfolio metrics let optimalReturn = result.solution.dot(expectedReturns) var optimalVariance = 0.0 for i in 0..
>(
preferSpeed: true,
maxIterations: 500,
tolerance: 1e-4
)
do {
let fastResult = try fastOptimizer.optimize(
objective: portfolioObjective,
initialGuess: VectorN.equalWeights(dimension: assets.count),
constraints: constraints
)
print(" \nwith preferspeed="true:")" print(" algorithm: \(fastresult.algorithmused)") print(" iterations: \(fastresult.iterations)") print(" sharpe ratio: \((-fastresult.objectivevalue).number())") } catch { print("fast optimization failed: \(error)") } prefer accuracy: tighter tolerance, uses newton when possible let accurateoptimizer="AdaptiveOptimizer
>( preferAccuracy: true, maxIterations: 2000, tolerance: 1e-8 ) do { let accurateResult = try accurateOptimizer.optimize( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: constraints ) print("\nWith preferAccuracy=true:") print(" Algorithm: \(accurateResult.algorithmUsed)") print(" Iterations: \(accurateResult.iterations)") print(" Sharpe Ratio: \((-accurateResult.objectiveValue).number())") } catch { print("Accurate optimization failed: \(error)") } // MARK: - Testing Decision Tree with Different Problem Sizes print("\n" + String(repeating: "=", count: 60)) print("TESTING DECISION TREE") print(String(repeating: "=", count: 60)) // Small unconstrained problem (≤5 variables) → Newton-Raphson let smallObjective: (VectorN
) -> Double = { x in (x[0] - 1)*(x[0] - 1) + (x[1] - 2)*(x[1] - 2) + (x[2] - 3)*(x[2] - 3) } let smallAnalysis = AdaptiveOptimizer
>().analyzeProblem( initialGuess: VectorN([0.0, 0.0, 0.0]), constraints: [], hasGradient: false ) print("\nSmall unconstrained (3 variables):") print(" Recommended: \(smallAnalysis.recommendedAlgorithm)") print(" Reason: \(smallAnalysis.reason)") // Large unconstrained problem (>100 variables) → Gradient Descent let largeAnalysis = AdaptiveOptimizer
>().analyzeProblem( initialGuess: VectorN(repeating: 0.0, count: 150), constraints: [], hasGradient: false ) print("\nLarge unconstrained (150 variables):") print(" Recommended: \(largeAnalysis.recommendedAlgorithm)") print(" Reason: \(largeAnalysis.reason)") // Problem with inequality constraints → InequalityOptimizer let inequalityAnalysis = AdaptiveOptimizer
>().analyzeProblem( initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: constraints, // Has inequalities (long-only) hasGradient: false ) print("\nWith inequality constraints:") print(" Recommended: \(inequalityAnalysis.recommendedAlgorithm)") print(" Reason: \(inequalityAnalysis.reason)") // Problem with only equality constraints → ConstrainedOptimizer let equalityOnly = [MultivariateConstraint
>.budgetConstraint] let equalityAnalysis = AdaptiveOptimizer
>().analyzeProblem( initialGuess: VectorN.equalWeights(dimension: assets.count), constraints: equalityOnly, hasGradient: false ) print("\nWith only equality constraints:") print(" Recommended: \(equalityAnalysis.recommendedAlgorithm)") print(" Reason: \(equalityAnalysis.reason)") print("\n" + String(repeating: "=", count: 60)) print("✓ AdaptiveOptimizer automatically selects the best algorithm") print(" based on problem characteristics!") print(String(repeating: "=", count: 60)) // Use ParallelOptimizer for problems with multiple local minima let parallelOptimizer = ParallelOptimizer
>( algorithm: .inequality, // Use inequality-constrained optimizer numberOfStarts: 20, // Try 20 different starting points maxIterations: 1000, tolerance: 1e-6 ) // Define search region for starting points let searchRegion = ( lower: VectorN(repeating: 0.0, count: assets.count), upper: VectorN(repeating: 1.0, count: assets.count) ) // Run optimization in parallel (async/await) let parallelResult = try await parallelOptimizer.optimize( objective: portfolioObjective, searchRegion: searchRegion, constraints: constraints ) print("Best solution found across \(parallelResult.allResults.count) attempts") print("Success rate: \(parallelResult.successRate.percent())") print("Objective value: \(parallelResult.objectiveValue.number())") do { // Compare different optimizers on the same problem struct OptimizerComparison { let objective: (VectorN
) -> Double let initialGuess: VectorN
let constraints: [MultivariateConstraint
>] func compare() throws { print("Optimizer Performance Comparison") print("═══════════════════════════════════════════════") // Test 1: Gradient Descent let startGD = Date() let gdOptimizer = MultivariateGradientDescent
>( learningRate: 0.01, maxIterations: 1000, tolerance: 1e-6 ) let gdResult = try gdOptimizer.minimize( function: objective, gradient: { try numericalGradient(objective, at: $0) }, initialGuess: initialGuess ) let gdTime = Date().timeIntervalSince(startGD) print("Gradient Descent:") print(" Value: \(gdResult.value.number(4))") print(" Time: \(gdTime.number(2))s") print(" Iterations: \(gdResult.iterations)") // // Test 2: Newton-Raphson (if problem is small) // if initialGuess.dimension <= 10 { // let startNR = Date() // let nrOptimizer = MultivariateNewtonRaphson
>( // maxIterations: 1000, // tolerance: 1e-6 // ) // let nrResult = try nrOptimizer.minimize( // function: objective, // gradient: { try numericalGradient(objective, at: $0) }, // hessian: { try numericalHessian(objective, at: $0) }, // initialGuess: initialGuess // ) // let nrTime = Date().timeIntervalSince(startNR) // // print("\nNewton-Raphson:") // print(" Value: \(nrResult.value.number(4))") // print(" Time: \(nrTime.number(2))s") // print(" Iterations: \(nrResult.iterations)") // } // Test 3: Adaptive (let it choose) let startAdaptive = Date() let adaptiveOptimizer = AdaptiveOptimizer
>() let adaptiveResult = try adaptiveOptimizer.optimize( objective: objective, initialGuess: initialGuess, constraints: constraints ) let adaptiveTime = Date().timeIntervalSince(startAdaptive) print("\nAdaptive Optimizer:") print(" Algorithm chosen: \(adaptiveResult.algorithmUsed)") print(" Value: \(adaptiveResult.objectiveValue.number(4))") print(" Time: \(adaptiveTime.number(2))s") print(" Iterations: \(adaptiveResult.iterations)") } } // Run comparison let comparison = OptimizerComparison( objective: portfolioObjective, initialGuess: VectorN.equalWeights(dimension: 4), constraints: constraints ) try comparison.compare() } catch let error as BusinessMathError { print("ERROR:\n\t\(error.localizedDescription)") } // MARK: - Real-World Application // Problem dimensions let numFacilities = 12 let numProducts = 8 let numVariables = numFacilities * numProducts // 96 variables // Cost structure ($/unit for each facility-product combination) // Lower costs for specialized facilities, higher for general purpose let productionCosts = (0..
) -> Double = { production in var totalCost = 0.0 // Production costs with volume discounts for i in 0..
volumeDiscountThreshold { let discountedAmount = quantity - volumeDiscountThreshold totalCost += productionCosts[i] * volumeDiscountThreshold totalCost += productionCosts[i] * volumeDiscountRate * discountedAmount } else { totalCost += baseCost } } return totalCost } // Current production (starting point) // Distribute demand equally across facilities initially let currentProduction = VectorN((0..
>] = [] for facility in 0..
>] = [] for product in 0..
>.nonNegativity(dimension: numVariables) let allConstraints = capacityConstraints + demandConstraints + nonNegativityConstraints // Let AdaptiveOptimizer analyze and choose do { print(String(repeating: "=", count: 70)) print("SUPPLY CHAIN OPTIMIZATION: MULTI-FACILITY PRODUCTION") print(String(repeating: "=", count: 70)) print("Facilities: \(numFacilities)") print("Products: \(numProducts)") print("Variables: \(numVariables)") print("Total demand: \(productDemands.reduce(0, +).number(0)) units/month") print("Total capacity: \(facilityCapacities.reduce(0, +).number(0)) units/month") print() let supplyChainOptimizer = AdaptiveOptimizer
>( maxIterations: 2000, tolerance: 1e-5 ) // First, analyze what algorithm will be selected let analysis = supplyChainOptimizer.analyzeProblem( initialGuess: currentProduction, constraints: allConstraints, hasGradient: false ) print("Problem Analysis:") print(" Size: \(analysis.size) variables") print(" Constraints: \(analysis.hasConstraints)") print(" Inequalities: \(analysis.hasInequalities)") print(" Recommended: \(analysis.recommendedAlgorithm)") print(" Reason: \(analysis.reason)") print() // Run optimization let startTime = Date() let supplyChainResult = try supplyChainOptimizer.optimize( objective: totalCostObjective, initialGuess: currentProduction, constraints: allConstraints ) let elapsedTime = Date().timeIntervalSince(startTime) print("Supply Chain Optimization Results:") print(" Algorithm Selected: \(supplyChainResult.algorithmUsed)") print(" Total Cost: \(supplyChainResult.objectiveValue.currency())") print(" Time: \(elapsedTime.number())s") print(" Iterations: \(supplyChainResult.iterations)") print(" Converged: \(supplyChainResult.converged)") // Calculate cost savings vs initial let initialCost = totalCostObjective(currentProduction) let savings = initialCost - supplyChainResult.objectiveValue let savingsPercent = (savings / initialCost) print("\nCost Savings:") print(" Initial cost: \(initialCost.currency())") print(" Optimized cost: \(supplyChainResult.objectiveValue.currency())") print(" Savings: \(savings.currency()) (\(savingsPercent.percent(1)))") // Show production summary var facilitiesUsed = 0 for facility in 0..
1.0 { facilitiesUsed += 1 } } print("\nProduction Summary:") print(" Active facilities: \(facilitiesUsed)/\(numFacilities)") print(" Total units produced: \(supplyChainResult.solution.sum.number(0))") } catch { print("Optimization failed: \(error)") }
→ Full API Reference: BusinessMath Docs – Adaptive Selection Guide
Experiments to Try
- Algorithm Racing: Compare 5 algorithms on portfolio optimization
- Problem Size Scaling: How does algorithm choice change from 10 to 1,000 variables?
- Custom Heuristics: Build a problem analyzer for your domain
- Timeout Sensitivity: How does allowed time affect algorithm choice?
Next Steps
Tomorrow: We’ll conclude Week 9 with Parallel Optimization, using multiple CPU cores to speed up large-scale problems.
Next Week: Week 10 explores Performance Benchmarking and advanced algorithms (L-BFGS, Conjugate Gradient, Simulated Annealing).
Series: [Week 9 of 12] | Topic: [Part 5 - Business Applications] | Case Studies: [4/6 Complete]
Topics Covered: Adaptive algorithms • Algorithm selection • Performance profiling • Multi-algorithm racing • Problem analysis
Playgrounds: [Week 1-9 available] • [Next: Parallel optimization]
Tagged with: optimization, metaheuristics