Working with Result Sets¶
Result sets are a powerful feature in OptiScope that allow you to organize and track different subsets of solutions within an optimization result.
What are Result Sets?¶
A ResultSet represents a named subset of solutions (points) within an OptimizationResult. They are useful for:
- Organizing solutions by different criteria (e.g., Pareto front, feasible solutions, top-ranked)
- Tracking analysis results (e.g., filtered Pareto front, knee points)
- Visualizing subsets with different colors or markers
- Comparing different selections side-by-side
Creating Result Sets¶
Manual Creation¶
Create a result set by specifying the indices of solutions:
from optiscope.core.result_set import ResultSet
import numpy as np
# Create a result set manually
custom_set = ResultSet(
name="high_efficiency",
indices=[0, 5, 10, 15, 20], # Indices of solutions in the result
created_by="manual_selection",
description="Solutions with efficiency > 0.8"
)
# Add the set to your result
result.add_set(custom_set)
From Boolean Mask¶
Create a result set from a boolean mask (common when filtering):
import numpy as np
# Create a boolean mask
mask = result.objectives.iloc[:, 0] < 100 # First objective < 100
# Convert mask to indices and create result set
indices = np.where(mask)[0].tolist()
filtered_set = ResultSet(
name="low_cost",
indices=indices,
created_by="filtering",
description="Solutions with cost < 100"
)
result.add_set(filtered_set)
From Analysis Results¶
Most analysis functions return indices or masks that can be converted to result sets:
from optiscope.analysis import identify_pareto_front
import numpy as np
# Identify Pareto front
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.metadata.optimization_directions
)
# Create result set from Pareto front
pareto_set = ResultSet(
name="pareto_front",
indices=np.where(pareto_mask)[0].tolist(),
created_by="pareto_analysis",
description="Non-dominated solutions"
)
result.add_set(pareto_set)
Accessing Result Sets¶
List All Result Sets¶
# Get all result set names
print(result.sets.keys())
# Get a specific result set
pareto_set = result.sets["pareto_front"]
print(f"Pareto front has {len(pareto_set.indices)} solutions")
Get Solutions from a Result Set¶
# Get the result set
my_set = result.sets["high_efficiency"]
# Get the solutions (objectives) in this set
set_objectives = result.objectives.iloc[my_set.indices]
set_design_vars = result.design_vars.iloc[my_set.indices]
print(f"Result set '{my_set.name}' contains {len(my_set.indices)} solutions")
print(f"Objectives:\n{set_objectives}")
Practical Examples¶
Example 1: Creating Multiple Result Sets¶
from optiscope.analysis import identify_pareto_front, topsis
import numpy as np
# 1. Create Pareto front result set
pareto_mask = identify_pareto_front(
objectives=result.objectives,
directions=result.metadata.optimization_directions
)
result.add_set(ResultSet(
name="pareto_front",
indices=np.where(pareto_mask)[0].tolist(),
created_by="analysis",
description="All Pareto-optimal solutions"
))
# 2. Create top 10 by TOPSIS
scores = topsis(
objectives=result.objectives,
weights=[0.4, 0.3, 0.3],
directions=result.metadata.optimization_directions
)
top_10_indices = np.argsort(scores)[-10:][::-1].tolist()
result.add_set(ResultSet(
name="top_10_topsis",
indices=top_10_indices,
created_by="topsis",
description="Top 10 solutions by TOPSIS"
))
# 3. Create feasible solutions set
if result.constraints is not None:
feasible_mask = np.all(result.constraints.iloc[:, :] <= 0, axis=1)
result.add_set(ResultSet(
name="feasible",
indices=np.where(feasible_mask)[0].tolist(),
created_by="feasibility_check",
description="Solutions satisfying all constraints"
))
print(f"Created {len(result.sets)} result sets:")
for name, rs in result.sets.items():
print(f" - {name}: {len(rs.indices)} solutions")
Example 2: Comparing Result Sets¶
# Compare overlap between result sets
pareto_indices = set(result.sets["pareto_front"].indices)
top_10_indices = set(result.sets["top_10_topsis"].indices)
overlap = pareto_indices & top_10_indices
print(f"Overlap between Pareto front and top 10: {len(overlap)} solutions")
# Find solutions in Pareto front but not in top 10
pareto_only = pareto_indices - top_10_indices
print(f"Solutions in Pareto front only: {len(pareto_only)}")
Example 3: Nested Result Sets¶
Create a result set from another result set:
from optiscope.analysis import adaptive_smart_pareto_filter
import numpy as np
# Get Pareto front
pareto_set = result.sets["pareto_front"]
pareto_indices = np.array(pareto_set.indices)
# Apply Smart Pareto Filter to the Pareto front
filtered_indices = adaptive_smart_pareto_filter(
objectives=result.objectives.iloc[pareto_indices],
target_reduction=0.3,
min_points=10,
normalize=True
)
# Map back to original indices
final_indices = pareto_indices[filtered_indices].tolist()
# Create filtered result set
result.add_set(ResultSet(
name="filtered_pareto",
indices=final_indices,
created_by="smart_pareto_filter",
description=f"Representative subset of Pareto front ({len(final_indices)} points)"
))
Using Result Sets in Visualization¶
Result sets can be highlighted in plots:
from optiscope.plotting import plot_parallel_coordinates, plot_scatter_matrix
# Show only specific result sets
fig = plot_parallel_coordinates(
result,
result_sets=["pareto_front", "top_10_topsis"],
color_by="Set", # Color by result set membership
title="Pareto Front vs Top 10 TOPSIS"
)
fig.show()
# Scatter matrix with result sets
fig = plot_scatter_matrix(
result,
variables=["objective_0", "objective_1", "objective_2"],
result_sets=["pareto_front", "filtered_pareto"],
color_by="Set",
marker_by="Set",
title="Pareto Front Analysis"
)
fig.show()
Saving and Loading Result Sets¶
Result sets are automatically saved when you save the optimization result:
from optiscope.io import save_results, load_results
# Save result with all result sets
save_results(result, "results_with_sets.csv")
# Load result (result sets are restored)
loaded_result = load_results("results_with_sets.csv")
print(f"Loaded {len(loaded_result.sets)} result sets")
Best Practices¶
- Use descriptive names: Choose clear, meaningful names for result sets
- Add descriptions: Include detailed descriptions explaining how the set was created
- Track provenance: Use the
created_byfield to record which analysis created the set - Avoid duplicates: Check if a result set already exists before creating a new one
- Clean up: Remove unused result sets to keep your data organized