@@ -350,80 +350,82 @@ def read_from_output_dir(self) -> None:
350
350
exp = _OptimizerOnlyExperiment (self ._output_dir )
351
351
self .data .read_from_experiment (exp )
352
352
353
- def observe_optimizer (
354
- self ,
355
- optimizer : BasicOptimizer ,
356
- ) -> None :
357
- optimizer .add_observer (
358
- EventType .START_OPTIMIZER_STEP , self ._on_start_optimization
359
- )
353
+ def observe_optimizer (self , optimizer : BasicOptimizer ) -> None :
360
354
optimizer .add_observer (
361
355
EventType .FINISHED_EVALUATION , self ._on_batch_evaluation_finished
362
356
)
363
357
optimizer .add_observer (
364
- EventType .FINISHED_OPTIMIZER_STEP ,
365
- self ._on_optimization_finished ,
358
+ EventType .FINISHED_OPTIMIZER_STEP , self ._on_optimization_finished
366
359
)
367
360
368
- def _on_start_optimization (self , event : Event ) -> None :
369
- def _format_control_names (control_names ):
370
- converted_names = []
371
- for name in control_names :
372
- converted = f"{ name [0 ]} _{ name [1 ]} "
373
- if len (name ) > 2 :
374
- converted += f"-{ name [2 ]} "
375
- converted_names .append (converted )
376
-
377
- return converted_names
378
-
379
- config = event .config
380
-
381
- # Note: We probably do not have to store
382
- # all of this information, consider removing.
361
+ def init (self , everest_config : EverestConfig ) -> None :
383
362
self .data .controls = polars .DataFrame (
384
363
{
385
364
"control_name" : polars .Series (
386
- _format_control_names ( config . variables . names ) , dtype = polars .String
365
+ everest_config . formatted_control_names , dtype = polars .String
387
366
),
388
367
}
389
368
)
369
+
390
370
# TODO: The weight and normalization keys are only used by the everest api,
391
371
# with everviz. They should be removed in the long run.
372
+ weights = np .fromiter (
373
+ (
374
+ 1.0 if obj .weight is None else obj .weight
375
+ for obj in everest_config .objective_functions
376
+ ),
377
+ dtype = np .float64 ,
378
+ )
392
379
self .data .objective_functions = polars .DataFrame (
393
380
{
394
- "objective_name" : config .objectives .names ,
395
- "weight" : polars .Series (
396
- config .objectives .weights , dtype = polars .Float64
397
- ),
398
- "normalization" : polars .Series ( # Q: Is this correct?
399
- [1.0 / s for s in config .objectives .scales ],
381
+ "objective_name" : everest_config .objective_names ,
382
+ "weight" : polars .Series (weights / sum (weights ), dtype = polars .Float64 ),
383
+ "normalization" : polars .Series (
384
+ [
385
+ 1.0 if obj .normalization is None else obj .normalization
386
+ for obj in everest_config .objective_functions
387
+ ],
400
388
dtype = polars .Float64 ,
401
389
),
402
390
}
403
391
)
404
392
405
- if config . nonlinear_constraints is not None :
393
+ if everest_config . output_constraints is not None :
406
394
self .data .nonlinear_constraints = polars .DataFrame (
407
395
{
408
- "constraint_name" : config . nonlinear_constraints . names ,
396
+ "constraint_name" : everest_config . constraint_names ,
409
397
}
410
398
)
399
+ else :
400
+ self .data .nonlinear_constraints = None
411
401
412
402
self .data .realization_weights = polars .DataFrame (
413
403
{
414
404
"realization" : polars .Series (
415
- config . realizations . names , dtype = polars .UInt32
405
+ everest_config . model . realizations , dtype = polars .UInt32
416
406
),
417
407
}
418
408
)
419
409
420
410
def _store_function_results (self , results : FunctionResults ) -> _EvaluationResults :
411
+ names = {
412
+ "variable" : self .data .controls ["control_name" ],
413
+ "objective" : self .data .objective_functions ["objective_name" ],
414
+ "nonlinear_constraint" : (
415
+ self .data .nonlinear_constraints ["constraint_name" ]
416
+ if self .data .nonlinear_constraints is not None
417
+ else None
418
+ ),
419
+ "realization" : self .data .realization_weights ["realization" ],
420
+ }
421
+
421
422
# We could select only objective values,
422
423
# but we select all to also get the constraint values (if they exist)
423
424
realization_objectives = polars .from_pandas (
424
425
results .to_dataframe (
425
426
"evaluations" ,
426
427
select = ["objectives" , "evaluation_ids" ],
428
+ names = names ,
427
429
).reset_index (),
428
430
).select (
429
431
"batch_id" ,
@@ -438,6 +440,7 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult
438
440
results .to_dataframe (
439
441
"evaluations" ,
440
442
select = ["constraints" , "evaluation_ids" ],
443
+ names = names ,
441
444
).reset_index (),
442
445
).select (
443
446
"batch_id" ,
@@ -452,7 +455,9 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult
452
455
)
453
456
454
457
batch_constraints = polars .from_pandas (
455
- results .to_dataframe ("functions" , select = ["constraints" ]).reset_index ()
458
+ results .to_dataframe (
459
+ "functions" , select = ["constraints" ], names = names
460
+ ).reset_index ()
456
461
).select ("batch_id" , "nonlinear_constraint" , "constraints" )
457
462
458
463
batch_constraints = batch_constraints .rename (
@@ -480,12 +485,13 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult
480
485
results .to_dataframe (
481
486
"functions" ,
482
487
select = ["objectives" , "weighted_objective" ],
488
+ names = names ,
483
489
).reset_index ()
484
490
).select ("batch_id" , "objective" , "objectives" , "weighted_objective" )
485
491
486
492
realization_controls = polars .from_pandas (
487
493
results .to_dataframe (
488
- "evaluations" , select = ["variables" , "evaluation_ids" ]
494
+ "evaluations" , select = ["variables" , "evaluation_ids" ], names = names
489
495
).reset_index ()
490
496
).select (
491
497
"batch_id" ,
@@ -535,8 +541,19 @@ def _store_function_results(self, results: FunctionResults) -> _EvaluationResult
535
541
}
536
542
537
543
def _store_gradient_results (self , results : GradientResults ) -> _GradientResults :
544
+ names = {
545
+ "variable" : self .data .controls ["control_name" ],
546
+ "objective" : self .data .objective_functions ["objective_name" ],
547
+ "nonlinear_constraint" : (
548
+ self .data .nonlinear_constraints ["constraint_name" ]
549
+ if self .data .nonlinear_constraints is not None
550
+ else None
551
+ ),
552
+ "realization" : self .data .realization_weights ["realization" ],
553
+ }
554
+
538
555
perturbation_objectives = polars .from_pandas (
539
- results .to_dataframe ("evaluations" ).reset_index ()
556
+ results .to_dataframe ("evaluations" , names = names ).reset_index ()
540
557
).select (
541
558
[
542
559
"batch_id" ,
@@ -560,7 +577,7 @@ def _store_gradient_results(self, results: GradientResults) -> _GradientResults:
560
577
561
578
if results .gradients is not None :
562
579
batch_objective_gradient = polars .from_pandas (
563
- results .to_dataframe ("gradients" ).reset_index ()
580
+ results .to_dataframe ("gradients" , names = names ).reset_index ()
564
581
).select (
565
582
[
566
583
"batch_id" ,
@@ -678,7 +695,7 @@ def _on_batch_evaluation_finished(self, event: Event) -> None:
678
695
logger .debug ("Storing batch results dataframes" )
679
696
680
697
converted_results = tuple (
681
- convert_to_maximize (result ) for result in event .results
698
+ convert_to_maximize (result ) for result in event .data . get ( " results" , [])
682
699
)
683
700
results : list [FunctionResults | GradientResults ] = []
684
701
0 commit comments