Source code for piglot.objectives.design

"""Module for curve fitting objectives"""
from __future__ import annotations
from typing import Dict, Any
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from piglot.parameter import ParameterSet
from piglot.solver import read_solver
from piglot.solver.solver import OutputResult
from piglot.utils.assorted import read_custom_module
from piglot.utils.reductions import read_reduction
from piglot.utils.scalarisations import read_scalarisation
from piglot.utils.composition.responses import EndpointFlattenUtility
from piglot.utils.response_transformer import ResponseTransformer, read_response_transformer
from piglot.objectives.response_objective import ResponseSingleObjective, ResponseObjective


[docs] class DesignSingleObjective(ResponseSingleObjective): """Single objective for design optimisation objectives."""
[docs] def plot(self, axis: plt.Axes, raw_results: Dict[str, OutputResult]) -> Dict[Line2D, str]: """Plot the response for this objective. Parameters ---------- axis : plt.Axes Axis to plot the response on. raw_results : Dict[str, OutputResult] Raw responses from the solver. Returns ------- Dict[Line2D, str] Mapping of lines to response names (for dynamically updating plots). """ # Plot the response lines: Dict[Line2D, str] = {} for prediction in self.prediction: response = raw_results[prediction] line, = axis.plot(response.get_time(), response.get_data(), label=prediction) lines[line] = prediction return lines
[docs] @classmethod def read(cls, name: str, config: Dict[str, Any], output_dir: str) -> DesignSingleObjective: """Read the objective spec from the configuration dictionary. Parameters ---------- name : str Name of the objective. config : Dict[str, Any] Configuration dictionary. output_dir: str Output directory. Returns ------- ResponseSingleObjective Single objective to use. """ # Prediction parsing if 'prediction' not in config: raise ValueError(f"Missing prediction for design target '{name}'.") # Sanitise prediction field prediction = config['prediction'] if isinstance(prediction, str): prediction = [prediction] elif not isinstance(prediction, list): raise ValueError(f"Invalid prediction '{prediction}' for design target '{name}'.") # Read the quantity if 'quantity' not in config: raise ValueError(f"Missing quantity for design target '{name}'.") return DesignSingleObjective( name, prediction, read_reduction(config['quantity']), maximise=bool(config.get('maximise', False)), weight=float(config.get('weight', 1.0)), bounds=config.get('bounds', None), flatten_utility=( EndpointFlattenUtility(int(config['n_points'])) if 'n_points' in config else None ), prediction_transform=( read_response_transformer(config['transformers']) if 'transformers' in config else None ), )
[docs] class ResponseDesignObjective(ResponseObjective): """Class for design of response-based objectives."""
[docs] @classmethod def read( cls, config: Dict[str, Any], parameters: ParameterSet, output_dir: str, ) -> ResponseDesignObjective: """Read the objective from a configuration dictionary. Parameters ---------- config : Dict[str, Any] Terms from the configuration dictionary. parameters : ParameterSet Set of parameters for this problem. output_dir : str Path to the output directory. Returns ------- ResponseDesignObjective Objective function to optimise. """ # Read the solver if 'solver' not in config: raise ValueError("Missing solver for design objective.") solver = read_solver(config['solver'], parameters, output_dir) # Read the targets if 'targets' not in config: raise ValueError("Missing targets for design objective.") objectives = [ DesignSingleObjective.read(target_name, target_config, output_dir) for target_name, target_config in config.pop('targets').items() ] # Sanitise the objectives under composition composite = bool(config.get('composite', False)) if composite: for objective in objectives: if objective.flatten_utility is None: raise ValueError( "All objectives must have a number of points specified for the composition." ) # Read transformers transformers: Dict[str, ResponseTransformer] = {} if 'transformers' in config: for name, transformer_config in config.pop('transformers').items(): transformers[name] = read_response_transformer(transformer_config) # Read custom class (if any) target_class: type[ResponseDesignObjective] = ResponseDesignObjective if 'custom_class' in config: target_class = read_custom_module(config['custom_class'], ResponseDesignObjective) return target_class( parameters, solver, objectives, output_dir, scalarisation=( read_scalarisation(config['scalarisation'], objectives) if 'scalarisation' in config else None ), stochastic=bool(config.get('stochastic', False)), composite=composite, full_composite=bool(config.get('full_composite', True)), transformers=transformers, )