Aller au contenu

Optimiseur Aléatoire

Vue d'ensemble

L'optimiseur aléatoire est la méthode d'optimisation la plus simple disponible dans le framework ORENI. Il utilise un échantillonnage aléatoire de l'espace de recherche pour explorer les solutions possibles de rénovation énergétique.

Principe de fonctionnement

Échantillonnage aléatoire

L'optimiseur aléatoire fonctionne en :

  1. Génération aléatoire de designs dans l'espace de décision
  2. Évaluation de chaque design avec les fonctions de coût
  3. Calcul de la frontière de Pareto parmi tous les designs évalués
  4. Retour des meilleures solutions non-dominées

Avantages

  • Simplicité : Aucun paramètre complexe à ajuster
  • Rapidité : Exécution très rapide
  • Robustesse : Pas de risque de convergence prématurée
  • Exploration : Couvre bien l'espace de recherche

Inconvénients

  • Pas d'intelligence : N'apprend pas des évaluations précédentes
  • Convergence lente : Nécessite beaucoup d'évaluations
  • Efficacité limitée : Peut manquer des solutions optimales
  • Résultats aléatoires : Qualité dépend de la chance

Utilisation

Import et configuration

from oreni.optim.random_optimization import random_optimizer

# Configuration de base
uncertain_design, experience_design, uncertain_draws = random_optimizer(
    function=your_cost_function,
    decision_space=your_decision_space,
    uncertain_space=your_uncertain_space,
    n_designs=100,
    n_uncs=10,
    n_occ_rdm=1,
    n_jobs=4
)

Paramètres

Paramètre Type Défaut Description
function Callable - Fonction de coût à optimiser
decision_space DecisionSpace - Espace de décision
uncertain_space UncertainSpace - Espace d'incertitude
n_designs int 100 Nombre de designs à évaluer
n_uncs int 10 Nombre d'échantillons d'incertitude
n_occ_rdm int 1 Nombre d'échantillons d'occupation
n_jobs int 1 Nombre de jobs parallèles

Exemple complet

import pathlib
from examples.cabin import design_space_cabin, uncertain_space_cabin
from oreni.cost_functions.CostLifeCycleCost import CostLifeCycleCost
from oreni.cost_functions.CostLifeCycleAssessment import CostLifeCycleAssessment
from oreni.cost_functions.CostComfort_PMV_RoomLevel import CostComfort
from oreni.engine.SetAndRunSimulations import SetAndRunSimulations
from oreni.optim.random_optimization import random_optimizer

# Configuration des fonctions de coût
cost_functions = [
    CostLifeCycleCost(duration=20, discount_rate=0.01),
    CostLifeCycleAssessment(duration=20, energies_data=catalog.energies_data),
    CostComfort(output_step="Hourly")
]

function_labels = ["Life_Cycle_Cost", "Life_Cycle_Assessment", "Thermal_Comfort"]

# Configuration des simulations
simulations = SetAndRunSimulations(
    idf_file="cabin.idf",
    epw_file="cabin_hvac.json",
    decision_space=design_space_cabin,
    uncertain_space=uncertain_space_cabin,
    cost_functions=cost_functions
)

# Optimisation aléatoire
results = random_optimizer(
    function=simulations.compute_cost_functions,
    decision_space=design_space_cabin,
    uncertain_space=uncertain_space_cabin,
    n_designs=50,
    n_uncs=5,
    n_occ_rdm=1,
    n_jobs=4
)

uncertain_design, experience_design, uncertain_draws = results

Analyse des résultats

Frontière de Pareto

from oreni.functions.core_utilities import compute_pareto_ranks

# Calcul des rangs de Pareto
pareto_ranks = compute_pareto_ranks(
    uncertain_design,
    function_labels,
    [1, 1, 1]  # Tous les objectifs à minimiser
)

# Affichage des meilleures solutions
best_solutions = uncertain_design[pareto_ranks == 1]
print(f"Nombre de solutions Pareto optimales : {len(best_solutions)}")

Visualisation

import matplotlib.pyplot as plt

# Graphique 2D de la frontière de Pareto
plt.figure(figsize=(10, 6))
plt.scatter(uncertain_design["Life_Cycle_Cost"], 
           uncertain_design["Life_Cycle_Assessment"],
           c=pareto_ranks, cmap='viridis', alpha=0.7)
plt.colorbar(label='Rang de Pareto')
plt.xlabel("Coût du cycle de vie")
plt.ylabel("Émissions CO₂")
plt.title("Résultats de l'optimisation aléatoire")
plt.grid(True, alpha=0.3)
plt.show()

Bonnes pratiques

Choix du nombre de designs

Objectif Nombre de designs recommandé
Test rapide 10-20
Exploration initiale 50-100
Analyse complète 200-500
Validation 1000+

Parallélisation

# Utilisez la parallélisation pour accélérer
import multiprocessing

n_jobs = multiprocessing.cpu_count() - 1  # Utilise tous les CPU sauf un

results = random_optimizer(
    # ... autres paramètres ...
    n_jobs=n_jobs
)

Gestion de la mémoire

# Pour de gros problèmes, évaluez par batches
batch_size = 50
all_results = []

for i in range(0, total_designs, batch_size):
    batch_results = random_optimizer(
        # ... paramètres ...
        n_designs=min(batch_size, total_designs - i)
    )
    all_results.append(batch_results)

Cas d'usage recommandés

✅ Utilisez l'optimiseur aléatoire pour :

  • Tests rapides de nouvelles configurations
  • Exploration initiale de l'espace de recherche
  • Validation d'autres optimiseurs
  • Benchmarking de performances
  • Développement et debugging

❌ Évitez l'optimiseur aléatoire pour :

  • Optimisation finale de production
  • Problèmes coûteux (peu d'évaluations disponibles)
  • Recherche de solutions optimales précises
  • Comparaisons de performance entre optimiseurs

Comparaison avec d'autres optimiseurs

Aspect Aléatoire BoTorch
Simplicité ⭐⭐⭐⭐⭐ ⭐⭐
Convergence ⭐⭐⭐⭐⭐
Diversité ⭐⭐ ⭐⭐⭐
Efficacité ⭐⭐⭐⭐⭐
Robustesse ⭐⭐⭐⭐ ⭐⭐⭐

Exemples pratiques

Exemple 1 : Test rapide

# Test rapide d'une nouvelle configuration
results = random_optimizer(
    function=simulations.compute_cost_functions,
    decision_space=design_space_cabin,
    uncertain_space=uncertain_space_cabin,
    n_designs=20,  # Peu de designs pour un test rapide
    n_uncs=2,      # Peu d'échantillons d'incertitude
    n_jobs=4
)

Exemple 2 : Exploration complète

# Exploration complète de l'espace de recherche
results = random_optimizer(
    function=simulations.compute_cost_functions,
    decision_space=design_space_complex,
    uncertain_space=uncertain_space_complex,
    n_designs=500,  # Beaucoup de designs pour une exploration complète
    n_uncs=10,      # Plus d'échantillons pour la robustesse
    n_jobs=8        # Parallélisation maximale
)

Exemple 3 : Validation de BoTorch

# Comparaison avec BoTorch
import time

# Optimisation aléatoire
start_time = time.time()
random_results = random_optimizer(
    function=simulations.compute_cost_functions,
    decision_space=design_space_cabin,
    uncertain_space=uncertain_space_cabin,
    n_designs=100
)
random_time = time.time() - start_time

# Optimisation BoTorch
start_time = time.time()
botorch_results = botorch_multi_objective_optimizer(
    function=simulations.compute_cost_functions,
    decision_space=design_space_cabin,
    uncertain_space=uncertain_space_cabin,
    function_labels=function_labels,
    n_initial_points=10,
    n_optimization_iterations=10
)
botorch_time = time.time() - start_time

print(f"Temps aléatoire : {random_time:.2f}s")
print(f"Temps BoTorch : {botorch_time:.2f}s")

Dépannage

Problèmes courants

Mémoire insuffisante

# Réduisez le nombre de designs ou utilisez des batches
results = random_optimizer(
    n_designs=50,  # Au lieu de 500
    n_uncs=2       # Au lieu de 10
)

Temps d'exécution trop long

# Augmentez la parallélisation
results = random_optimizer(
    n_jobs=multiprocessing.cpu_count()  # Utilise tous les CPU
)

Résultats insuffisants

# Augmentez le nombre de designs
results = random_optimizer(
    n_designs=200,  # Plus de designs pour de meilleurs résultats
    n_uncs=10       # Plus d'échantillons d'incertitude
)

Ressources supplémentaires