Skip to content

Latest commit

 

History

History
270 lines (207 loc) · 6.78 KB

File metadata and controls

270 lines (207 loc) · 6.78 KB

Interactive Evolution Tutorial

Interactive Genetic Algorithms (IGA) incorporate human feedback into the evolutionary process. Instead of an automated fitness function, users evaluate candidates through ratings, comparisons, or selections.

When to Use Interactive Evolution

Ideal for:

  • Aesthetic optimization (art, design, music)
  • Subjective preferences (user interfaces)
  • Hard-to-formalize objectives
  • Creative exploration

Challenges:

  • User fatigue limits evaluations
  • Noisy, inconsistent feedback
  • Slower convergence than automated GA

Evaluation Modes

Fugue-evo supports multiple ways to gather user feedback:

Mode User Action Best For
Rating Score each candidate 1-10 Absolute quality assessment
Pairwise Choose better of two Relative comparisons
Batch Selection Pick best N from batch Quick approximate ranking

Complete Example

{{#include ../../../examples/interactive_evolution.rs}}

Source: examples/interactive_evolution.rs

Running the Example

cargo run --example interactive_evolution

This example simulates user feedback. In a real application, you would replace the simulation with actual UI interaction.

Key Components

Building an Interactive GA

let mut iga = InteractiveGABuilder::<RealVector, (), (), ()>::new()
    .population_size(12)
    .elitism_count(2)
    .evaluation_mode(EvaluationMode::Rating)
    .batch_size(4)
    .min_coverage(0.8)
    .max_generations(5)
    .aggregation_model(AggregationModel::DirectRating {
        default_rating: 5.0,
    })
    .bounds(bounds)
    .selection(TournamentSelection::new(2))
    .crossover(SbxCrossover::new(15.0))
    .mutation(PolynomialMutation::new(20.0))
    .build()?;

Key parameters:

  • evaluation_mode: How users provide feedback
  • batch_size: Candidates shown per evaluation round
  • min_coverage: Fraction of population needing evaluation
  • aggregation_model: How to combine multiple evaluations

The Step Loop

loop {
    match iga.step(&mut rng) {
        StepResult::NeedsEvaluation(request) => {
            // Present to user, get feedback
            let response = get_user_response(&request);
            iga.provide_response(response);
        }

        StepResult::GenerationComplete { generation, best_fitness, coverage } => {
            println!("Generation {} complete", generation);
        }

        StepResult::Complete(result) => {
            println!("Evolution complete!");
            break;
        }
    }
}

Handling Evaluation Requests

Rating Mode:

EvaluationRequest::RateCandidates { candidates, .. } => {
    // Show candidates to user
    for candidate in candidates {
        display_candidate(&candidate.genome);
    }
    // Collect ratings
    let ratings: Vec<(CandidateId, f64)> = /* user input */;
    EvaluationResponse::ratings(ratings)
}

Pairwise Mode:

EvaluationRequest::PairwiseComparison { candidate_a, candidate_b, .. } => {
    // Show both candidates
    display_comparison(&candidate_a.genome, &candidate_b.genome);
    // Get user's choice
    let winner = /* user choice */;
    EvaluationResponse::winner(winner)
}

Batch Selection:

EvaluationRequest::BatchSelection { candidates, select_count, .. } => {
    // Show all candidates
    for c in candidates { display_candidate(&c.genome); }
    // User selects best N
    let selected: Vec<CandidateId> = /* user picks */;
    EvaluationResponse::selected(selected)
}

Aggregation Models

How to combine feedback into fitness estimates:

Direct Rating

AggregationModel::DirectRating { default_rating: 5.0 }

Uses ratings directly as fitness. Unevaluated candidates get the default.

Implicit Ranking

AggregationModel::ImplicitRanking {
    selected_bonus: 1.0,
    not_selected_penalty: 0.3,
    base_fitness: 5.0,
}

For batch selection mode:

  • Selected candidates get bonus
  • Non-selected get penalty
  • Accumulates over evaluations

Bradley-Terry Model

For pairwise comparisons, estimates latent "skill" from win/loss records using the Bradley-Terry statistical model.

Reducing User Fatigue

Smaller Population

.population_size(12)

Fewer candidates = fewer evaluations needed.

Coverage Threshold

.min_coverage(0.5)  // Only evaluate 50% of population

Not every candidate needs evaluation each generation.

Batch Size Tuning

.batch_size(4)  // Show 4 at a time
  • Too small: Many rounds, tedious
  • Too large: Overwhelming, poor decisions

Evaluation Budget

.max_evaluations(100)  // Stop after 100 user interactions

Simulating User Feedback

For testing, simulate user preferences:

struct SimulatedUser {
    target: Vec<f64>,
}

impl SimulatedUser {
    fn rate(&self, genome: &RealVector) -> f64 {
        let distance: f64 = genome.genes().iter()
            .zip(self.target.iter())
            .map(|(g, t)| (g - t).powi(2))
            .sum::<f64>()
            .sqrt();

        // Closer to target = higher rating
        10.0 - distance.min(9.0)
    }
}

This allows testing IGA logic without human interaction.

Real-World Integration

Web Application

// Pseudocode for web integration
async fn evolution_endpoint(state: &mut IgaState) -> Response {
    match state.iga.step(&mut state.rng) {
        StepResult::NeedsEvaluation(request) => {
            // Return candidates to frontend
            Json(CandidatesForEvaluation::from(request))
        }
        // ...
    }
}

async fn feedback_endpoint(feedback: UserFeedback, state: &mut IgaState) {
    let response = EvaluationResponse::from(feedback);
    state.iga.provide_response(response);
}

GUI Application

fn update(&mut self, message: Message) {
    match message {
        Message::NextStep => {
            if let StepResult::NeedsEvaluation(req) = self.iga.step(&mut self.rng) {
                self.current_request = Some(req);
            }
        }
        Message::UserRated(ratings) => {
            let response = EvaluationResponse::ratings(ratings);
            self.iga.provide_response(response);
        }
    }
}

Exercises

  1. Different modes: Compare Rating vs Batch Selection modes
  2. Noisy preferences: Add randomness to simulated user, observe robustness
  3. Visualization: Display RealVector as colors/shapes for visual evaluation

Next Steps