globalMOO Documentation
  • globalMOO API Documentation
  • core
    • Authentication
    • Core Concepts
    • Getting Started with globalMOO
    • Error Handling
    • Event Handling
    • SDK Initialization
    • Debugging & Logging
  • schemas
    • Account Schema
    • Model Schema
    • Project Schema
    • Trial Schema
    • Objective Schema
    • Result Schema
    • Inverse Schema
  • quickstart
    • Your First Optimization with globalMOO
  • endpoints
    • accounts
      • Account Endpoints
      • Register Account
    • inverse
      • Inverse Optimization Endpoints
      • Initialize Inverse Optimization
      • Load Inverse Output
      • Suggest Inverse Step
    • models
      • Create Model
      • Model Endpoints
      • List Models
    • objectives
      • Objective Endpoints
      • Load Objectives
    • outputs
      • Output Endpoints
      • Load Output Cases
      • Load Developed Outputs
    • projects
      • Create Project
      • Project Endpoints
    • trials
      • Trial Endpoints
      • Read Trial
Powered by GitBook
On this page
  • What You'll Build
  • Prerequisites
  • Step 1: Installation and Setup
  • Step 2: Define Your Function
  • Step 3: Create a Model and Project
  • Step 4: Run Initial Learning Cases
  • Step 5: Set Optimization Goals
  • Step 6: Run the Optimization Loop
  • Complete Code
  • What's Next?
  • Common Issues
  1. quickstart

Your First Optimization with globalMOO

PreviousquickstartNextendpoints

Last updated 1 month ago

This guide will take you from zero to your first working optimization in about 15 minutes. We'll create a simple but complete example that demonstrates the key features of globalMOO.

Try it interactively: Follow along with this guide in our

What You'll Build

We'll optimize a simple function with two inputs to achieve desired outputs. This example will teach you:

  • How to set up authentication

  • How to create a model and project

  • How to run an optimization

  • How to interpret and use the results

Prerequisites

  • Python 3.10 or higher

  • A globalMOO API key (get one at https://api.globalmoo.ai/)

  • Basic Python knowledge

Step 1: Installation and Setup

  1. Install the SDK (use the appropriate package manager for your language):

pip install globalmoo-sdk
npm install @globalmoo/globalmoo-sdk
composer require globalmoo/globalmoo-php
  1. Create a new file and add the necessary imports and setup:

import logging
from typing import List
from dotenv import load_dotenv

from globalmoo.client import Client
from globalmoo.request.create_model import CreateModel
from globalmoo.request.create_project import CreateProject
from globalmoo.request.load_output_cases import LoadOutputCases
from globalmoo.request.load_objectives import LoadObjectives
from globalmoo.request.suggest_inverse import SuggestInverse
from globalmoo.request.load_inversed_output import LoadInversedOutput
from globalmoo.enums.input_type import InputType
from globalmoo.enums.objective_type import ObjectiveType

# Configure logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('httpx').setLevel(logging.WARNING)
logger = logging.getLogger(__name__)

# Load environment variables
load_dotenv()

# Initialize client using environment variables
client = Client()
const globalMOO = require('globalmoo');
const dotenv = require('dotenv');

// Load environment variables
dotenv.config();

// Initialize client using environment variables
const client = new globalMOO();
require_once 'vendor/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

// Initialize client using environment variables
$client = new GlobalMOO\Client();

Or if you prefer to specify credentials directly:

from globalmoo.credentials import Credentials
credentials = Credentials(
    api_key="your-api-key",
    base_uri="https://api.globalmoo.ai/api"
)
client = Client(credentials=credentials)
const client = new globalMOO({
    apiKey: "your-api-key",
    baseUri: "https://api.globalmoo.ai/api"
});
$client = new GlobalMOO\Client([
    'api_key' => 'your-api-key',
    'base_uri' => 'https://api.globalmoo.ai/api'
]);

Step 2: Define Your Function

Let's optimize a simple linear function with 3 inputs and 5 outputs:

def my_function(inputs: List[float]) -> List[float]:
    """Simple linear function that we want to optimize."""
    v01 = inputs[0]
    v02 = inputs[1]
    v03 = inputs[2]
    
    o01 = v01 + v02 + v03                    # Sum of all inputs
    o02 = (v01 - 2.0) + (v02 - 2.0) + v03    # Shifted sum
    o03 = (v01 - 2.0) + v02 + (v03 - 2.0)    # Different shifted sum
    o04 = v01 + (v02 - 2.0) + (v03 - 2.0)    # Another variation
    o05 = 3.0 * v01 + 2.0 * v03 + 1.0 * v03  # Weighted sum
    
    return [o01, o02, o03, o04, o05]
function myFunction(inputs) {
    const [v01, v02, v03] = inputs;
    
    const o01 = v01 + v02 + v03;                    // Sum of all inputs
    const o02 = (v01 - 2.0) + (v02 - 2.0) + v03;    // Shifted sum
    const o03 = (v01 - 2.0) + v02 + (v03 - 2.0);    // Different shifted sum
    const o04 = v01 + (v02 - 2.0) + (v03 - 2.0);    // Another variation
    const o05 = 3.0 * v01 + 2.0 * v03 + 1.0 * v03;  // Weighted sum
    
    return [o01, o02, o03, o04, o05];
}
function myFunction(array $inputs): array {
    $v01 = $inputs[0];
    $v02 = $inputs[1];
    $v03 = $inputs[2];
    
    $o01 = $v01 + $v02 + $v03;                    // Sum of all inputs
    $o02 = ($v01 - 2.0) + ($v02 - 2.0) + $v03;    // Shifted sum
    $o03 = ($v01 - 2.0) + $v02 + ($v03 - 2.0);    // Different shifted sum
    $o04 = $v01 + ($v02 - 2.0) + ($v03 - 2.0);    // Another variation
    $o05 = 3.0 * $v01 + 2.0 * $v03 + 1.0 * $v03;  // Weighted sum
    
    return [$o01, $o02, $o03, $o04, $o05];
}

Step 3: Create a Model and Project

# Model configuration
MODEL_NAME = "My First Optimization"
INPUT_COUNT = 3
OUTPUT_COUNT = 5
MIN_VALUES = [0.0, 0.0, 0.0]
MAX_VALUES = [10.0, 10.0, 10.0]
INPUT_TYPES = [InputType.FLOAT] * INPUT_COUNT

# Create a model
model = client.execute_request(CreateModel(
    name=MODEL_NAME
))
logger.info(f"Created model with ID: {model.id}")

# Create a project with input specifications
project = client.execute_request(CreateProject(
    model_id=model.id,
    input_count=INPUT_COUNT,
    minimums=MIN_VALUES,
    maximums=MAX_VALUES,
    input_types=INPUT_TYPES,
    categories=[]  # Empty list since we have no categorical variables
))
logger.info(f"Created project with ID: {project.id}")
// Model configuration
const MODEL_NAME = "My First Optimization";
const INPUT_COUNT = 3;
const OUTPUT_COUNT = 5;
const MIN_VALUES = [0.0, 0.0, 0.0];
const MAX_VALUES = [10.0, 10.0, 10.0];
const INPUT_TYPES = Array(INPUT_COUNT).fill("float");

// Create a model
const model = await client.createModel({
    name: MODEL_NAME
});
console.log(`Created model with ID: ${model.id}`);

// Create a project with input specifications
const project = await client.createProject({
    modelId: model.id,
    inputCount: INPUT_COUNT,
    minimums: MIN_VALUES,
    maximums: MAX_VALUES,
    inputTypes: INPUT_TYPES,
    categories: []  // Empty list since we have no categorical variables
});
console.log(`Created project with ID: ${project.id}`);
// Model configuration
$MODEL_NAME = "My First Optimization";
$INPUT_COUNT = 3;
$OUTPUT_COUNT = 5;
$MIN_VALUES = [0.0, 0.0, 0.0];
$MAX_VALUES = [10.0, 10.0, 10.0];
$INPUT_TYPES = array_fill(0, $INPUT_COUNT, "float");

// Create a model
$model = $client->createModel([
    'name' => $MODEL_NAME
]);
echo "Created model with ID: {$model->id}\n";

// Create a project with input specifications
$project = $client->createProject([
    'model_id' => $model->id,
    'input_count' => $INPUT_COUNT,
    'minimums' => $MIN_VALUES,
    'maximums' => $MAX_VALUES,
    'input_types' => $INPUT_TYPES,
    'categories' => []  // Empty list since we have no categorical variables
]);
echo "Created project with ID: {$project->id}\n";

Step 4: Run Initial Learning Cases

# Get input cases from the project
input_cases = project.input_cases
logger.info(f"Received {len(input_cases)} input cases")

# Compute outputs for each input case
output_cases = [my_function(single_case) for single_case in input_cases]
logger.info(f"Computed {len(output_cases)} output cases")

# Create trial with the computed outputs
trial = client.execute_request(LoadOutputCases(
    model_id=model.id,
    project_id=project.id,
    output_count=OUTPUT_COUNT,
    output_cases=output_cases
))
logger.info(f"Successfully created trial with ID: {trial.id}")
// Get input cases from the project
const inputCases = project.inputCases;
console.log(`Received ${inputCases.length} input cases`);

// Compute outputs for each input case
const outputCases = inputCases.map(singleCase => myFunction(singleCase));
console.log(`Computed ${outputCases.length} output cases`);

// Create trial with the computed outputs
const trial = await client.loadOutputCases({
    modelId: model.id,
    projectId: project.id,
    outputCount: OUTPUT_COUNT,
    outputCases: outputCases
});
console.log(`Successfully created trial with ID: ${trial.id}`);
// Get input cases from the project
$inputCases = $project->getInputCases();
echo "Received " . count($inputCases) . " input cases\n";

// Compute outputs for each input case
$outputCases = array_map('myFunction', $inputCases);
echo "Computed " . count($outputCases) . " output cases\n";

// Create trial with the computed outputs
$trial = $client->loadOutputCases([
    'model_id' => $model->id,
    'project_id' => $project->id,
    'output_count' => $OUTPUT_COUNT,
    'output_cases' => $outputCases
]);
echo "Successfully created trial with ID: {$trial->id}\n";

Step 5: Set Optimization Goals

# Define our target values and how we want to achieve them
TRUTHCASE = [5.4321, 5.4321, 5.4321]       # The inputs we're trying to find
objectives = my_function(TRUTHCASE)          # The outputs we want to match

# Define how precise we want each objective to be
OBJECTIVE_TYPES = [ObjectiveType.PERCENT] * OUTPUT_COUNT  # Use percentage-based matching
PERCENT_BELOW = [-1.0] * OUTPUT_COUNT                    # Allow 1% below target
PERCENT_ABOVE = [ 1.0] * OUTPUT_COUNT                    # Allow 1% above target

# By convention, the last entry in input_cases is the center of the search space,
# which serves as a good starting point for the optimization
initial_input = input_cases[-1]
initial_output = output_cases[-1]

# Initialize the optimization
objective = client.execute_request(LoadObjectives(
    model_id=model.id,
    project_id=project.id,
    trial_id=trial.id,
    objectives=objectives,                # What outputs we want
    objective_types=OBJECTIVE_TYPES,      # How to match each output
    initial_input=initial_input,          # Where to start from
    initial_output=initial_output,        # Its corresponding output
    minimum_bounds=PERCENT_BELOW,      # How far below target is acceptable
    maximum_bounds=PERCENT_ABOVE,     # How far above target is acceptable
    desired_l1_norm=0.0               # Required, defaults to 0.0
))
logger.info("Initialized inverse optimization")
// Define our target values and how we want to achieve them
const TRUTHCASE = [5.4321, 5.4321, 5.4321];      // The inputs we're trying to find
const objectives = myFunction(TRUTHCASE);         // The outputs we want to match

// Define how precise we want each objective to be
const OBJECTIVE_TYPES = Array(OUTPUT_COUNT).fill("percent");  // Use percentage-based matching
const PERCENT_BELOW = Array(OUTPUT_COUNT).fill(-1.0);        // Allow 1% below target
const PERCENT_ABOVE = Array(OUTPUT_COUNT).fill(1.0);         // Allow 1% above target

// By convention, the last entry in input_cases is the center of the search space,
// which serves as a good starting point for the optimization
const initial_input = inputCases[inputCases.length - 1];
const initial_output = outputCases[outputCases.length - 1];

// Initialize the optimization
const objective = await client.loadObjectives({
    modelId: model.id,
    projectId: project.id,
    trialId: trial.id,
    objectives: objectives,               // What outputs we want
    objectiveTypes: OBJECTIVE_TYPES,      // How to match each output
    initialInput: initial_input,          // Where to start from
    initialOutput: initial_output,        // Its corresponding output
    minimumBounds: PERCENT_BELOW,        // How far below target is acceptable
    maximumBounds: PERCENT_ABOVE,        // How far above target is acceptable
    desiredL1Norm: 0.0                   // Required, defaults to 0.0
});
console.log("Initialized inverse optimization");
// Define our target values and how we want to achieve them
$TRUTHCASE = [5.4321, 5.4321, 5.4321];       // The inputs we're trying to find
$objectives = myFunction($TRUTHCASE);         // The outputs we want to match

// Define how precise we want each objective to be
$OBJECTIVE_TYPES = array_fill(0, $OUTPUT_COUNT, "percent");  // Use percentage-based matching
$PERCENT_BELOW = array_fill(0, $OUTPUT_COUNT, -1.0);        // Allow 1% below target
$PERCENT_ABOVE = array_fill(0, $OUTPUT_COUNT, 1.0);         // Allow 1% above target

// By convention, the last entry in input_cases is the center of the search space,
// which serves as a good starting point for the optimization
$initial_input = end($inputCases);
$initial_output = end($outputCases);

// Initialize the optimization
$objective = $client->loadObjectives([
    'model_id' => $model->id,
    'project_id' => $project->id,
    'trial_id' => $trial->id,
    'objectives' => $objectives,           // What outputs we want
    'objective_types' => $OBJECTIVE_TYPES, // How to match each output
    'initial_input' => $initial_input,     // Where to start from
    'initial_output' => $initial_output,   // Its corresponding output
    'minimum_bounds' => $PERCENT_BELOW,    // How far below target is acceptable
    'maximum_bounds' => $PERCENT_ABOVE,    // How far above target is acceptable
    'desired_l1_norm' => 0.0              // Required, defaults to 0.0
]);
echo "Initialized inverse optimization\n";

Other available objective types include:

  • ObjectiveType.EXACT: Match exactly within L1 norm

  • ObjectiveType.VALUE: Match within absolute error bounds

  • ObjectiveType.LESS_THAN: Keep output below target

  • ObjectiveType.LESS_THAN_EQUAL: Keep output at or below target

  • ObjectiveType.GREATER_THAN: Keep output above target

  • ObjectiveType.GREATER_THAN_EQUAL: Keep output at or above target

  • ObjectiveType.MINIMIZE: Minimize output down to target

  • ObjectiveType.MAXIMIZE: Maximize output up to target

Step 6: Run the Optimization Loop

# Run optimization loop
max_iterations = 10

for iteration in range(max_iterations):
    # Get next suggested experiment
    inverse = client.execute_request(SuggestInverse(
        model_id=model.id,
        project_id=project.id,
        trial_id=trial.id,
        objective_id=objective.id
    ))
    logger.info(f"Iteration {iteration + 1}: Received suggestion")
    
    # Run the experiment
    next_output = my_function(inverse.input)
    
    # Load the experimental results
    inverse = client.execute_request(LoadInversedOutput(
        model_id=model.id,
        project_id=project.id,
        trial_id=trial.id,
        objective_id=objective.id,
        output=next_output
    ))

    # Log detailed results
    logger.info("Current solution details:")
    logger.info(f"  Input: {[f'{x:.4f}' for x in inverse.input]}")
    logger.info(f"  Output: {[f'{x:.4f}' for x in next_output]}")
    logger.info(f"  Target: {[f'{x:.4f}' for x in objectives]}")
    
    if inverse.results:
        for result in inverse.results:
            logger.info(f"\nObjective {result.number}:")
            logger.info(f"  Type: {result.type}")
            logger.info(f"  Error: {result.error:.6f}")
            logger.info(f"  Satisfied: {'✓' if result.satisfied else '✗'}")
            logger.info(f"  Detail: {result.detail}")
    
    # Check if we've found a satisfactory solution
    if inverse.should_stop():
        if inverse.satisfied_at:
            logger.info("Found satisfactory solution!")
        else:
            logger.info(f"Search stopped: {inverse.get_stop_reason().description()}")
        break

    logger.info(f"Completed iteration {iteration + 1}")

# Report final results
logger.info("\nFinal Results:")
if inverse.satisfied_at:
    logger.info("Solution satisfied all objectives!")
    logger.info("Satisfaction details:")
    for i, (satisfied, detail) in enumerate(zip(inverse.get_satisfaction_status(), inverse.get_result_details())):
        logger.info(f"  Objective {i}: {'✓' if satisfied else '✗'} - {detail}")
else:
    logger.info("Solution did not satisfy all objectives")
    logger.info("Status per objective:")
    for i, (satisfied, detail) in enumerate(zip(inverse.get_satisfaction_status(), inverse.get_result_details())):
        logger.info(f"  Objective {i}: {'✓' if satisfied else '✗'} - {detail}")

logger.info(f"\nFinal solution:")
logger.info(f"  Input values: {[f'{x:.4f}' for x in inverse.input]}")
logger.info(f"  Output values: {[f'{x:.4f}' for x in next_output]}")
logger.info(f"  Target values: {[f'{x:.4f}' for x in objectives]}")
logger.info(f"  Error values: {[f'{e:.6f}' for e in inverse.get_objective_errors()]}")

# Don't forget to close the client
client.http_client.close()
logger.info("Closed client connection")
// Run optimization loop
const maxIterations = 10;

for (let iteration = 0; iteration < maxIterations; iteration++) {
    // Get next suggested experiment
    let inverse = await client.suggestInverse({
        modelId: model.id,
        projectId: project.id,
        trialId: trial.id,
        objectiveId: objective.id
    });
    console.log(`Iteration ${iteration + 1}: Received suggestion`);
    
    // Run the experiment
    const nextOutput = myFunction(inverse.input);
    
    // Load the experimental results
    inverse = await client.loadInversedOutput({
        modelId: model.id,
        projectId: project.id,
        trialId: trial.id,
        objectiveId: objective.id,
        output: nextOutput
    });

        // Log detailed results
    console.log('Current solution details:');
    console.log(`  Input: ${inverse.input.map(x => x.toFixed(4))}`);
    console.log(`  Output: ${nextOutput.map(x => x.toFixed(4))}`);
    console.log(`  Target: ${objectives.map(x => x.toFixed(4))}`);
    
    if (inverse.results) {
        inverse.results.forEach(result => {
            console.log(`\nObjective ${result.number}:`);
            console.log(`  Type: ${result.type}`);
            console.log(`  Error: ${result.error.toFixed(6)}`);
            console.log(`  Satisfied: ${result.satisfied ? '✓' : '✗'}`);
            console.log(`  Detail: ${result.detail}`);
        });
    }
    
        // Check if we've found a satisfactory solution
    if (inverse.shouldStop()) {
        if (inverse.satisfiedAt) {
            console.log('Found satisfactory solution!');
        } else {
            console.log(`Search stopped: ${inverse.getStopReason().description}`);
        }
        break;
    }

    console.log(`Completed iteration ${iteration + 1}`);
}

// Report final results
console.log('\nFinal Results:');
if (inverse.satisfiedAt) {
    console.log('Solution satisfied all objectives!');
    console.log('Satisfaction details:');
    inverse.results.forEach((result, i) => {
        console.log(`  Objective ${i}: ${result.satisfied ? '✓' : '✗'} - ${result.detail}`);
    });
} else {
    console.log('Solution did not satisfy all objectives');
    console.log('Status per objective:');
    inverse.results.forEach((result, i) => {
        console.log(`  Objective ${i}: ${result.satisfied ? '✓' : '✗'} - ${result.detail}`);
    });
}

console.log('\nFinal solution:');
console.log(`  Input values: ${inverse.input.map(x => x.toFixed(4))}`);
console.log(`  Output values: ${nextOutput.map(x => x.toFixed(4))}`);
console.log(`  Target values: ${objectives.map(x => x.toFixed(4))}`);
console.log(`  Error values: ${inverse.getObjectiveErrors().map(x => x.toFixed(6))}`);

} finally {
    if (typeof client !== 'undefined') {
        await client.close();
        console.log('Closed client connection');
    }
}
// Run optimization loop
$maxIterations = 10;

for ($iteration = 0; $iteration < $maxIterations; $iteration++) {
    // Get next suggested experiment
    $inverse = $client->suggestInverse([
        'model_id' => $model->id,
        'project_id' => $project->id,
        'trial_id' => $trial->id,
        'objective_id' => $objective->id
    ]);
    echo "Iteration " . ($iteration + 1) . ": Received suggestion\n";
    
    // Run the experiment
    $nextOutput = myFunction($inverse->input);
    
    // Load the experimental results
    $inverse = $client->loadInversedOutput([
        'model_id' => $model->id,
        'project_id' => $project->id,
        'trial_id' => $trial->id,
        'objective_id' => $objective->id,
        'output' => $nextOutput
    ]);

    // Log detailed results
    echo "Current solution details:\n";
    echo "  Input: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $inverse->input)) . "]\n";
    echo "  Output: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $nextOutput)) . "]\n";
    echo "  Target: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $objectives)) . "]\n";
    
    if ($inverse->results) {
        foreach ($inverse->results as $result) {
            echo "\nObjective {$result->number}:\n";
            echo "  Type: {$result->type}\n";
            echo "  Error: " . number_format($result->error, 6) . "\n";
            echo "  Satisfied: " . ($result->satisfied ? '✓' : '✗') . "\n";
            echo "  Detail: {$result->detail}\n";
        }
    }
    
    // Check if we've found a satisfactory solution
    if ($inverse->shouldStop()) {
        if ($inverse->satisfiedAt) {
            echo "Found satisfactory solution!\n";
        } else {
            echo "Search stopped: " . $inverse->getStopReason()->description() . "\n";
        }
        break;
    }

    echo "Completed iteration " . ($iteration + 1) . "\n";
}

// Report final results
echo "\nFinal Results:\n";
if ($inverse->satisfiedAt) {
    echo "Solution satisfied all objectives!\n";
    echo "Satisfaction details:\n";
    foreach ($inverse->results as $i => $result) {
        echo "  Objective $i: " . ($result->satisfied ? '✓' : '✗') . " - {$result->detail}\n";
    }
} else {
    echo "Solution did not satisfy all objectives\n";
    echo "Status per objective:\n";
    foreach ($inverse->results as $i => $result) {
        echo "  Objective $i: " . ($result->satisfied ? '✓' : '✗') . " - {$result->detail}\n";
    }
}

echo "\nFinal solution:\n";
echo "  Input values: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $inverse->input)) . "]\n";
echo "  Output values: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $nextOutput)) . "]\n";
echo "  Target values: [" . implode(", ", array_map(fn($x) => number_format($x, 4), $objectives)) . "]\n";
echo "  Error values: [" . implode(", ", array_map(fn($x) => number_format($x, 6), $inverse->getObjectiveErrors())) . "]\n";

} finally {
    if (isset($client)) {
        $client->close();
        echo "Closed client connection\n";
    }
}

Complete Code

The complete code is available in the examples directory as linear_example.py.

What's Next?

Now that you have your first optimization working, you can:

  1. Try different objective types (EXACT, VALUE, LESS_THAN, etc.)

  2. Learn about different input types (integers, categories) in the tutorials

  3. Explore more complex optimization scenarios

  4. Check out the example gallery for real-world applications

Common Issues

  1. Authentication errors

    • Check your API key in .env file or credentials

    • Ensure you're using the correct base URI

  2. Optimization not converging

    • Try increasing max_iterations

    • Check if your target values are achievable

    • Consider relaxing your objective criteria

  3. Need help?

    • Contact support@globalmoo.com

    • Check our documentation at https://docs.globalmoo.ai

Interactive Google Colab Notebook