use super::{
ActivationType, LearnedOptimizationConfig, LearnedOptimizer, MetaOptimizerState,
OptimizationProblem, TrainingTask,
};
use crate::error::OptimizeResult;
use crate::result::OptimizeResults;
use scirs2_core::ndarray::{Array1, Array2, Array3, ArrayView1};
use scirs2_core::random::{Rng, RngExt};
use std::collections::{HashMap, VecDeque};
#[derive(Debug, Clone)]
pub struct FewShotLearningOptimizer {
config: LearnedOptimizationConfig,
meta_learner: MetaLearnerNetwork,
fast_adapter: FastAdaptationMechanism,
similarity_matcher: ProblemSimilarityMatcher,
experience_memory: ExperienceMemory,
meta_state: MetaOptimizerState,
adaptation_stats: FewShotAdaptationStats,
current_task_context: Option<TaskContext>,
}
#[derive(Debug, Clone)]
pub struct MetaLearnerNetwork {
feature_extractor: FeatureExtractor,
context_encoder: ContextEncoder,
parameter_generator: ParameterGenerator,
update_network: UpdateNetwork,
memory_networks: Vec<MemoryNetwork>,
}
#[derive(Debug, Clone)]
pub struct FeatureExtractor {
conv_layers: Vec<ConvLayer>,
dense_layers: Vec<DenseLayer>,
attention_mechanism: FeatureAttention,
feature_dim: usize,
}
#[derive(Debug, Clone)]
pub struct ConvLayer {
weights: Array3<f64>,
bias: Array1<f64>,
kernel_size: usize,
stride: usize,
activation: ActivationType,
}
#[derive(Debug, Clone)]
pub struct DenseLayer {
weights: Array2<f64>,
bias: Array1<f64>,
activation: ActivationType,
}
#[derive(Debug, Clone)]
pub struct FeatureAttention {
query_weights: Array2<f64>,
key_weights: Array2<f64>,
value_weights: Array2<f64>,
attention_scores: Array1<f64>,
}
#[derive(Debug, Clone)]
pub struct ContextEncoder {
lstm: LSTMCell,
embedding_layer: Array2<f64>,
aggregation_network: Array2<f64>,
context_dim: usize,
}
#[derive(Debug, Clone)]
pub struct LSTMCell {
w_i: Array2<f64>,
w_f: Array2<f64>,
w_c: Array2<f64>,
w_o: Array2<f64>,
hidden_state: Array1<f64>,
cell_state: Array1<f64>,
}
#[derive(Debug, Clone)]
pub struct ParameterGenerator {
generator_network: Array2<f64>,
conditioning_network: Array2<f64>,
output_projection: Array2<f64>,
param_dim: usize,
}
#[derive(Debug, Clone)]
pub struct UpdateNetwork {
update_network: Array2<f64>,
meta_gradient_network: Array2<f64>,
lr_network: Array2<f64>,
update_history: VecDeque<Array1<f64>>,
}
#[derive(Debug, Clone)]
pub struct MemoryNetwork {
memory_bank: Array2<f64>,
memory_keys: Array2<f64>,
memory_values: Array2<f64>,
access_patterns: Vec<Array1<f64>>,
memory_size: usize,
}
#[derive(Debug, Clone)]
pub struct FastAdaptationMechanism {
gradient_adapter: GradientBasedAdapter,
prototype_adapter: PrototypeBasedAdapter,
maml_adapter: MAMLAdapter,
strategy_selector: AdaptationStrategySelector,
}
#[derive(Debug, Clone)]
pub struct GradientBasedAdapter {
meta_lr: f64,
inner_lr: f64,
adaptation_steps: usize,
gradient_accumulator: Array1<f64>,
}
#[derive(Debug, Clone)]
pub struct PrototypeBasedAdapter {
prototypes: Array2<f64>,
prototype_labels: Vec<String>,
distance_metric: DistanceMetric,
adaptation_weights: Array1<f64>,
}
#[derive(Debug, Clone)]
pub enum DistanceMetric {
Euclidean,
Cosine,
Mahalanobis { covariance_inv: Array2<f64> },
Learned { distance_network: Array2<f64> },
}
#[derive(Debug, Clone)]
pub struct MAMLAdapter {
meta_parameters: Array1<f64>,
task_parameters: HashMap<String, Array1<f64>>,
inner_optimizer: InnerLoopOptimizer,
meta_optimizer: MetaOptimizer,
}
#[derive(Debug, Clone)]
pub struct InnerLoopOptimizer {
learning_rate: f64,
momentum: f64,
velocity: Array1<f64>,
}
#[derive(Debug, Clone)]
pub struct MetaOptimizer {
meta_learning_rate: f64,
meta_momentum: f64,
meta_velocity: Array1<f64>,
}
#[derive(Debug, Clone)]
pub struct AdaptationStrategySelector {
strategy_scores: HashMap<String, f64>,
selection_network: Array2<f64>,
current_strategy: AdaptationStrategy,
}
#[derive(Debug, Clone)]
pub enum AdaptationStrategy {
Gradient,
Prototype,
MAML,
Hybrid { weights: Array1<f64> },
}
#[derive(Debug, Clone)]
pub struct ProblemSimilarityMatcher {
problem_embeddings: HashMap<String, Array1<f64>>,
similarity_network: Array2<f64>,
similarity_threshold: f64,
similarity_cache: HashMap<(String, String), f64>,
}
#[derive(Debug, Clone)]
pub struct ExperienceMemory {
support_set: Vec<SupportExample>,
query_set: Vec<QueryExample>,
capacity: usize,
episodic_memory: VecDeque<Episode>,
}
#[derive(Debug, Clone)]
pub struct SupportExample {
problem_encoding: Array1<f64>,
trajectory: OptimizationTrajectory,
success: bool,
metadata: HashMap<String, f64>,
}
#[derive(Debug, Clone)]
pub struct QueryExample {
problem_encoding: Array1<f64>,
target_strategy: Array1<f64>,
expected_performance: f64,
}
#[derive(Debug, Clone)]
pub struct Episode {
task_id: String,
support_examples: Vec<SupportExample>,
query_examples: Vec<QueryExample>,
adaptation_performance: f64,
timestamp: usize,
}
#[derive(Debug, Clone)]
pub struct OptimizationTrajectory {
parameter_history: Vec<Array1<f64>>,
objective_history: Vec<f64>,
gradient_history: Vec<Array1<f64>>,
step_size_history: Vec<f64>,
total_steps: usize,
}
#[derive(Debug, Clone)]
pub struct FewShotAdaptationStats {
adaptation_speed: f64,
transfer_efficiency: f64,
support_examples_used: usize,
adaptation_success_rate: f64,
meta_learning_progress: f64,
}
#[derive(Debug, Clone)]
pub struct TaskContext {
task_description: String,
problem_characteristics: Array1<f64>,
available_support: Vec<String>,
adaptation_budget: usize,
performance_target: f64,
}
impl FewShotLearningOptimizer {
pub fn new(config: LearnedOptimizationConfig) -> Self {
let feature_dim = config.hidden_size;
let meta_learner = MetaLearnerNetwork::new(feature_dim);
let fast_adapter = FastAdaptationMechanism::new(config.inner_learning_rate);
let similarity_matcher = ProblemSimilarityMatcher::new(feature_dim);
let experience_memory = ExperienceMemory::new(1000);
Self {
config,
meta_learner,
fast_adapter,
similarity_matcher,
experience_memory,
meta_state: MetaOptimizerState {
meta_params: Array1::zeros(feature_dim),
network_weights: Array2::zeros((feature_dim, feature_dim)),
performance_history: Vec::new(),
adaptation_stats: super::AdaptationStatistics::default(),
episode: 0,
},
adaptation_stats: FewShotAdaptationStats::default(),
current_task_context: None,
}
}
pub fn few_shot_adapt(
&mut self,
support_examples: &[SupportExample],
target_problem: &OptimizationProblem,
) -> OptimizeResult<()> {
let support_features = self.extract_support_features(support_examples)?;
let similar_problems = self.find_similar_problems(target_problem)?;
let strategy = self.select_adaptation_strategy(&support_features, &similar_problems)?;
match strategy {
AdaptationStrategy::Gradient => {
self.gradient_based_adaptation(support_examples)?;
}
AdaptationStrategy::Prototype => {
self.prototype_based_adaptation(support_examples)?;
}
AdaptationStrategy::MAML => {
self.maml_adaptation(support_examples)?;
}
AdaptationStrategy::Hybrid { weights } => {
self.hybrid_adaptation(support_examples, &weights)?;
}
}
self.update_adaptation_stats(support_examples.len())?;
Ok(())
}
fn extract_support_features(
&self,
support_examples: &[SupportExample],
) -> OptimizeResult<Array2<f64>> {
let num_examples = support_examples.len();
let feature_dim = self.meta_learner.feature_extractor.feature_dim;
let mut features = Array2::zeros((num_examples, feature_dim));
for (i, example) in support_examples.iter().enumerate() {
let extracted_features = self
.meta_learner
.feature_extractor
.extract(&example.problem_encoding)?;
for j in 0..feature_dim.min(extracted_features.len()) {
features[[i, j]] = extracted_features[j];
}
}
Ok(features)
}
fn find_similar_problems(
&self,
target_problem: &OptimizationProblem,
) -> OptimizeResult<Vec<String>> {
let target_encoding = self.encode_problem_for_similarity(target_problem)?;
let mut similarities = Vec::new();
for (problem_id, problem_embedding) in &self.similarity_matcher.problem_embeddings {
let similarity = self.compute_similarity(&target_encoding, problem_embedding)?;
if similarity > self.similarity_matcher.similarity_threshold {
similarities.push((problem_id.clone(), similarity));
}
}
similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
Ok(similarities.into_iter().take(5).map(|(id, _)| id).collect())
}
fn encode_problem_for_similarity(
&self,
problem: &OptimizationProblem,
) -> OptimizeResult<Array1<f64>> {
let mut encoding = Array1::zeros(self.meta_learner.feature_extractor.feature_dim);
encoding[0] = (problem.dimension as f64).ln();
encoding[1] = (problem.max_evaluations as f64).ln();
encoding[2] = problem.target_accuracy.ln().abs();
match problem.problem_class.as_str() {
"quadratic" => encoding[3] = 1.0,
"neural_network" => encoding[4] = 1.0,
"sparse" => {
encoding[5] = 1.0;
encoding[6] = 1.0;
}
_ => {} }
Ok(encoding)
}
fn compute_similarity(
&self,
encoding1: &Array1<f64>,
encoding2: &Array1<f64>,
) -> OptimizeResult<f64> {
let dot_product = encoding1
.iter()
.zip(encoding2.iter())
.map(|(&a, &b)| a * b)
.sum::<f64>();
let norm1 = (encoding1.iter().map(|&x| x * x).sum::<f64>()).sqrt();
let norm2 = (encoding2.iter().map(|&x| x * x).sum::<f64>()).sqrt();
if norm1 > 0.0 && norm2 > 0.0 {
Ok(dot_product / (norm1 * norm2))
} else {
Ok(0.0)
}
}
fn select_adaptation_strategy(
&self,
support_features: &Array2<f64>,
similar_problems: &[String],
) -> OptimizeResult<AdaptationStrategy> {
let num_support = support_features.nrows();
let num_similar = similar_problems.len();
if num_support <= 2 {
Ok(AdaptationStrategy::Prototype)
} else if num_similar > 3 {
Ok(AdaptationStrategy::MAML)
} else if num_support > 10 {
Ok(AdaptationStrategy::Gradient)
} else {
Ok(AdaptationStrategy::Hybrid {
weights: Array1::from(vec![0.3, 0.4, 0.3]),
})
}
}
fn gradient_based_adaptation(
&mut self,
support_examples: &[SupportExample],
) -> OptimizeResult<()> {
let all_gradients: Result<Vec<_>, _> = support_examples
.iter()
.map(|example| self.compute_meta_gradients(example))
.collect();
let all_gradients = all_gradients?;
let adapter = &mut self.fast_adapter.gradient_adapter;
for meta_gradients in all_gradients {
for (i, &grad) in meta_gradients.iter().enumerate() {
if i < adapter.gradient_accumulator.len() {
adapter.gradient_accumulator[i] += adapter.meta_lr * grad;
}
}
}
Ok(())
}
fn prototype_based_adaptation(
&mut self,
support_examples: &[SupportExample],
) -> OptimizeResult<()> {
let adapter = &mut self.fast_adapter.prototype_adapter;
for (i, example) in support_examples.iter().enumerate() {
if i < adapter.prototypes.nrows() {
for (j, &feature) in example.problem_encoding.iter().enumerate() {
if j < adapter.prototypes.ncols() {
adapter.prototypes[[i, j]] =
0.9 * adapter.prototypes[[i, j]] + 0.1 * feature;
}
}
}
}
Ok(())
}
fn maml_adaptation(&mut self, support_examples: &[SupportExample]) -> OptimizeResult<()> {
let adapter = &mut self.fast_adapter.maml_adapter;
for example in support_examples {
let inner_gradients = self.compute_inner_gradients(example)?;
self.apply_inner_update(&inner_gradients)?;
}
Ok(())
}
fn hybrid_adaptation(
&mut self,
support_examples: &[SupportExample],
weights: &Array1<f64>,
) -> OptimizeResult<()> {
if weights.len() >= 3 {
if weights[0] > 0.0 {
self.gradient_based_adaptation(support_examples)?;
}
if weights[1] > 0.0 {
self.prototype_based_adaptation(support_examples)?;
}
if weights[2] > 0.0 {
self.maml_adaptation(support_examples)?;
}
}
Ok(())
}
fn compute_meta_gradients(&self, example: &SupportExample) -> OptimizeResult<Array1<f64>> {
let mut gradients = Array1::zeros(self.meta_state.meta_params.len());
if !example.trajectory.objective_history.is_empty() {
let improvement = example
.trajectory
.objective_history
.first()
.copied()
.unwrap_or(0.0)
- example
.trajectory
.objective_history
.last()
.copied()
.unwrap_or(0.0);
for i in 0..gradients.len() {
gradients[i] =
improvement * (scirs2_core::random::rng().random::<f64>() - 0.5) * 0.01;
}
}
Ok(gradients)
}
fn compute_inner_gradients(&self, example: &SupportExample) -> OptimizeResult<Array1<f64>> {
let mut gradients = Array1::zeros(self.meta_state.meta_params.len());
if !example.trajectory.gradient_history.is_empty() {
if let Some(last_gradient) = example.trajectory.gradient_history.last() {
for (i, &grad) in last_gradient.iter().enumerate() {
if i < gradients.len() {
gradients[i] = grad * 0.1; }
}
}
}
Ok(gradients)
}
fn apply_inner_update(&mut self, gradients: &Array1<f64>) -> OptimizeResult<()> {
let lr = self.fast_adapter.maml_adapter.inner_optimizer.learning_rate;
for (i, &grad) in gradients.iter().enumerate() {
if i < self.meta_state.meta_params.len() {
self.meta_state.meta_params[i] -= lr * grad;
}
}
Ok(())
}
fn update_adaptation_stats(&mut self, num_support_examples: usize) -> OptimizeResult<()> {
self.adaptation_stats.support_examples_used = num_support_examples;
self.adaptation_stats.adaptation_speed = 1.0 / (num_support_examples as f64 + 1.0);
self.adaptation_stats.transfer_efficiency = if num_support_examples > 0 {
1.0 / num_support_examples as f64
} else {
0.0
};
Ok(())
}
pub fn generate_optimization_strategy(
&self,
problem: &OptimizationProblem,
) -> OptimizeResult<OptimizationStrategy> {
let problem_encoding = self.encode_problem_for_similarity(problem)?;
let strategy_params = self
.meta_learner
.parameter_generator
.generate(&problem_encoding)?;
Ok(OptimizationStrategy {
step_size_schedule: self.generate_step_size_schedule(&strategy_params)?,
direction_computation: DirectionComputation::GradientBased {
momentum: strategy_params.get(0).copied().unwrap_or(0.9),
},
convergence_criteria: ConvergenceCriteria {
tolerance: strategy_params.get(1).copied().unwrap_or(1e-6),
max_nit: problem.max_evaluations,
},
adaptation_rate: strategy_params.get(2).copied().unwrap_or(0.01),
})
}
fn generate_step_size_schedule(
&self,
strategy_params: &Array1<f64>,
) -> OptimizeResult<StepSizeSchedule> {
let initial_step = strategy_params.get(3).copied().unwrap_or(0.01);
let decay_rate = strategy_params.get(4).copied().unwrap_or(0.99);
Ok(StepSizeSchedule::Exponential {
initial_step,
decay_rate,
})
}
pub fn get_adaptation_stats(&self) -> &FewShotAdaptationStats {
&self.adaptation_stats
}
pub fn add_experience(
&mut self,
problem: &OptimizationProblem,
trajectory: OptimizationTrajectory,
) {
let problem_encoding = self
.encode_problem_for_similarity(problem)
.unwrap_or_default();
let support_example = SupportExample {
problem_encoding,
trajectory,
success: true, metadata: HashMap::new(),
};
self.experience_memory.add_support_example(support_example);
}
}
#[derive(Debug, Clone)]
pub struct OptimizationStrategy {
pub step_size_schedule: StepSizeSchedule,
pub direction_computation: DirectionComputation,
pub convergence_criteria: ConvergenceCriteria,
pub adaptation_rate: f64,
}
#[derive(Debug, Clone)]
pub enum StepSizeSchedule {
Constant {
step_size: f64,
},
Exponential {
initial_step: f64,
decay_rate: f64,
},
Polynomial {
initial_step: f64,
power: f64,
},
Adaptive {
base_step: f64,
adaptation_factor: f64,
},
}
#[derive(Debug, Clone)]
pub enum DirectionComputation {
GradientBased { momentum: f64 },
QuasiNewton { method: String },
TrustRegion { radius: f64 },
Adaptive { method_weights: Array1<f64> },
}
#[derive(Debug, Clone)]
pub struct ConvergenceCriteria {
pub tolerance: f64,
pub max_nit: usize,
}
impl MetaLearnerNetwork {
pub fn new(feature_dim: usize) -> Self {
Self {
feature_extractor: FeatureExtractor::new(feature_dim),
context_encoder: ContextEncoder::new(feature_dim),
parameter_generator: ParameterGenerator::new(feature_dim),
update_network: UpdateNetwork::new(feature_dim),
memory_networks: vec![MemoryNetwork::new(feature_dim, 100)],
}
}
}
impl FeatureExtractor {
pub fn new(feature_dim: usize) -> Self {
Self {
conv_layers: vec![],
dense_layers: vec![
DenseLayer::new(feature_dim, feature_dim * 2, ActivationType::ReLU),
DenseLayer::new(feature_dim * 2, feature_dim, ActivationType::ReLU),
],
attention_mechanism: FeatureAttention::new(feature_dim),
feature_dim,
}
}
pub fn extract(&self, problem_encoding: &Array1<f64>) -> OptimizeResult<Array1<f64>> {
let mut features = problem_encoding.clone();
for layer in &self.dense_layers {
features = layer.forward(&features.view())?;
}
features = self.attention_mechanism.apply(&features)?;
Ok(features)
}
}
impl DenseLayer {
pub fn new(input_size: usize, output_size: usize, activation: ActivationType) -> Self {
let weights = Array2::from_shape_fn((output_size, input_size), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * (2.0 / input_size as f64).sqrt()
});
let bias = Array1::zeros(output_size);
Self {
weights,
bias,
activation,
}
}
pub fn forward(&self, input: &ArrayView1<f64>) -> OptimizeResult<Array1<f64>> {
let mut output = Array1::zeros(self.bias.len());
for i in 0..output.len() {
for j in 0..input.len().min(self.weights.ncols()) {
output[i] += self.weights[[i, j]] * input[j];
}
output[i] += self.bias[i];
output[i] = self.activation.apply(output[i]);
}
Ok(output)
}
}
impl FeatureAttention {
pub fn new(feature_dim: usize) -> Self {
Self {
query_weights: Array2::from_shape_fn((feature_dim, feature_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
key_weights: Array2::from_shape_fn((feature_dim, feature_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
value_weights: Array2::from_shape_fn((feature_dim, feature_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
attention_scores: Array1::zeros(feature_dim),
}
}
pub fn apply(&self, features: &Array1<f64>) -> OptimizeResult<Array1<f64>> {
let mut attended_features = Array1::zeros(features.len());
for i in 0..attended_features.len() {
let attention_weight = (i as f64 / features.len() as f64).exp(); attended_features[i] = attention_weight * features.get(i).copied().unwrap_or(0.0);
}
let sum = attended_features.sum();
if sum > 0.0 {
attended_features /= sum;
}
Ok(attended_features)
}
}
impl ContextEncoder {
pub fn new(context_dim: usize) -> Self {
Self {
lstm: LSTMCell::new(context_dim),
embedding_layer: Array2::from_shape_fn((context_dim, 100), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
aggregation_network: Array2::from_shape_fn((context_dim, context_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
context_dim,
}
}
}
impl LSTMCell {
pub fn new(hidden_size: usize) -> Self {
Self {
w_i: Array2::from_shape_fn((hidden_size, hidden_size * 2), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
w_f: Array2::from_shape_fn((hidden_size, hidden_size * 2), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
w_c: Array2::from_shape_fn((hidden_size, hidden_size * 2), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
w_o: Array2::from_shape_fn((hidden_size, hidden_size * 2), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
hidden_state: Array1::zeros(hidden_size),
cell_state: Array1::zeros(hidden_size),
}
}
}
impl ParameterGenerator {
pub fn new(param_dim: usize) -> Self {
Self {
generator_network: Array2::from_shape_fn((param_dim, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
conditioning_network: Array2::from_shape_fn((param_dim, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
output_projection: Array2::from_shape_fn((param_dim, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
param_dim,
}
}
pub fn generate(&self, encoding: &Array1<f64>) -> OptimizeResult<Array1<f64>> {
let mut params: Array1<f64> = Array1::zeros(self.param_dim);
for i in 0..params.len() {
for j in 0..encoding.len().min(self.generator_network.ncols()) {
params[i] += self.generator_network[[i, j]] * encoding[j];
}
params[i] = params[i].tanh(); }
Ok(params)
}
}
impl UpdateNetwork {
pub fn new(param_dim: usize) -> Self {
Self {
update_network: Array2::from_shape_fn((param_dim, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
meta_gradient_network: Array2::from_shape_fn((param_dim, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
lr_network: Array2::from_shape_fn((1, param_dim), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
update_history: VecDeque::with_capacity(100),
}
}
}
impl MemoryNetwork {
pub fn new(feature_dim: usize, memory_size: usize) -> Self {
Self {
memory_bank: Array2::zeros((memory_size, feature_dim)),
memory_keys: Array2::zeros((memory_size, feature_dim)),
memory_values: Array2::zeros((memory_size, feature_dim)),
access_patterns: Vec::new(),
memory_size,
}
}
}
impl FastAdaptationMechanism {
pub fn new(inner_lr: f64) -> Self {
Self {
gradient_adapter: GradientBasedAdapter::new(inner_lr),
prototype_adapter: PrototypeBasedAdapter::new(),
maml_adapter: MAMLAdapter::new(),
strategy_selector: AdaptationStrategySelector::new(),
}
}
}
impl GradientBasedAdapter {
pub fn new(inner_lr: f64) -> Self {
Self {
meta_lr: 0.001,
inner_lr,
adaptation_steps: 5,
gradient_accumulator: Array1::zeros(100),
}
}
}
impl Default for PrototypeBasedAdapter {
fn default() -> Self {
Self::new()
}
}
impl PrototypeBasedAdapter {
pub fn new() -> Self {
Self {
prototypes: Array2::zeros((10, 100)),
prototype_labels: vec!["default".to_string(); 10],
distance_metric: DistanceMetric::Euclidean,
adaptation_weights: Array1::ones(10),
}
}
}
impl Default for MAMLAdapter {
fn default() -> Self {
Self::new()
}
}
impl MAMLAdapter {
pub fn new() -> Self {
Self {
meta_parameters: Array1::zeros(100),
task_parameters: HashMap::new(),
inner_optimizer: InnerLoopOptimizer::new(),
meta_optimizer: MetaOptimizer::new(),
}
}
}
impl Default for InnerLoopOptimizer {
fn default() -> Self {
Self::new()
}
}
impl InnerLoopOptimizer {
pub fn new() -> Self {
Self {
learning_rate: 0.01,
momentum: 0.9,
velocity: Array1::zeros(100),
}
}
}
impl Default for MetaOptimizer {
fn default() -> Self {
Self::new()
}
}
impl MetaOptimizer {
pub fn new() -> Self {
Self {
meta_learning_rate: 0.001,
meta_momentum: 0.9,
meta_velocity: Array1::zeros(100),
}
}
}
impl Default for AdaptationStrategySelector {
fn default() -> Self {
Self::new()
}
}
impl AdaptationStrategySelector {
pub fn new() -> Self {
let mut strategy_scores = HashMap::new();
strategy_scores.insert("gradient".to_string(), 0.5);
strategy_scores.insert("prototype".to_string(), 0.5);
strategy_scores.insert("maml".to_string(), 0.5);
Self {
strategy_scores,
selection_network: Array2::from_shape_fn((4, 10), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
current_strategy: AdaptationStrategy::Gradient,
}
}
}
impl ProblemSimilarityMatcher {
pub fn new(feature_dim: usize) -> Self {
Self {
problem_embeddings: HashMap::new(),
similarity_network: Array2::from_shape_fn((1, feature_dim * 2), |_| {
(scirs2_core::random::rng().random::<f64>() - 0.5) * 0.1
}),
similarity_threshold: 0.7,
similarity_cache: HashMap::new(),
}
}
}
impl ExperienceMemory {
pub fn new(capacity: usize) -> Self {
Self {
support_set: Vec::new(),
query_set: Vec::new(),
capacity,
episodic_memory: VecDeque::with_capacity(capacity),
}
}
pub fn add_support_example(&mut self, example: SupportExample) {
if self.support_set.len() >= self.capacity {
self.support_set.remove(0);
}
self.support_set.push(example);
}
}
impl Default for FewShotAdaptationStats {
fn default() -> Self {
Self {
adaptation_speed: 0.0,
transfer_efficiency: 0.0,
support_examples_used: 0,
adaptation_success_rate: 0.0,
meta_learning_progress: 0.0,
}
}
}
impl LearnedOptimizer for FewShotLearningOptimizer {
fn meta_train(&mut self, training_tasks: &[TrainingTask]) -> OptimizeResult<()> {
for task in training_tasks {
let support_examples = self.create_support_examples_from_task(task)?;
self.few_shot_adapt(&support_examples, &task.problem)?;
self.update_meta_learner(&support_examples)?;
}
Ok(())
}
fn adapt_to_problem(
&mut self,
problem: &OptimizationProblem,
initial_params: &ArrayView1<f64>,
) -> OptimizeResult<()> {
let similar_problems = self.find_similar_problems(problem)?;
let support_examples = self.create_support_examples_from_similar(&similar_problems)?;
self.few_shot_adapt(&support_examples, problem)?;
Ok(())
}
fn optimize<F>(
&mut self,
objective: F,
initial_params: &ArrayView1<f64>,
) -> OptimizeResult<OptimizeResults<f64>>
where
F: Fn(&ArrayView1<f64>) -> f64,
{
let default_problem = OptimizationProblem {
name: "few_shot".to_string(),
dimension: initial_params.len(),
problem_class: "general".to_string(),
metadata: HashMap::new(),
max_evaluations: 1000,
target_accuracy: 1e-6,
};
let strategy = self.generate_optimization_strategy(&default_problem)?;
let mut current_params = initial_params.to_owned();
let mut best_value = objective(initial_params);
let mut iterations = 0;
for iter in 0..strategy.convergence_criteria.max_nit {
iterations = iter;
let step_size = match &strategy.step_size_schedule {
StepSizeSchedule::Constant { step_size } => *step_size,
StepSizeSchedule::Exponential {
initial_step,
decay_rate,
} => initial_step * decay_rate.powi(iter as i32),
StepSizeSchedule::Polynomial {
initial_step,
power,
} => initial_step / (1.0 + iter as f64).powf(*power),
StepSizeSchedule::Adaptive {
base_step,
adaptation_factor,
} => base_step * (1.0 + adaptation_factor * iter as f64 / 100.0),
};
let direction = self.compute_direction(
&objective,
¤t_params,
&strategy.direction_computation,
)?;
for i in 0..current_params.len().min(direction.len()) {
current_params[i] -= step_size * direction[i];
}
let current_value = objective(¤t_params.view());
if current_value < best_value {
best_value = current_value;
}
if (best_value - current_value).abs() < strategy.convergence_criteria.tolerance {
break;
}
}
Ok(OptimizeResults::<f64> {
x: current_params,
fun: best_value,
success: true,
nit: iterations,
message: "Few-shot learning optimization completed".to_string(),
..OptimizeResults::default()
})
}
fn get_state(&self) -> &MetaOptimizerState {
&self.meta_state
}
fn reset(&mut self) {
self.experience_memory = ExperienceMemory::new(1000);
self.adaptation_stats = FewShotAdaptationStats::default();
self.current_task_context = None;
}
}
impl FewShotLearningOptimizer {
fn create_support_examples_from_task(
&self,
task: &TrainingTask,
) -> OptimizeResult<Vec<SupportExample>> {
let problem_encoding = self.encode_problem_for_similarity(&task.problem)?;
let trajectory = OptimizationTrajectory {
parameter_history: vec![Array1::zeros(task.problem.dimension)],
objective_history: vec![1.0],
gradient_history: vec![Array1::zeros(task.problem.dimension)],
step_size_history: vec![0.01],
total_steps: 1,
};
Ok(vec![SupportExample {
problem_encoding,
trajectory,
success: true,
metadata: HashMap::new(),
}])
}
fn update_meta_learner(&mut self, _support_examples: &[SupportExample]) -> OptimizeResult<()> {
self.meta_state.episode += 1;
Ok(())
}
fn create_support_examples_from_similar(
&self,
_similar_problems: &[String],
) -> OptimizeResult<Vec<SupportExample>> {
Ok(vec![])
}
fn compute_direction<F>(
&self,
objective: &F,
params: &Array1<f64>,
direction_method: &DirectionComputation,
) -> OptimizeResult<Array1<f64>>
where
F: Fn(&ArrayView1<f64>) -> f64,
{
match direction_method {
DirectionComputation::GradientBased { momentum: _ } => {
let h = 1e-6;
let f0 = objective(¶ms.view());
let mut gradient = Array1::zeros(params.len());
for i in 0..params.len() {
let mut params_plus = params.clone();
params_plus[i] += h;
let f_plus = objective(¶ms_plus.view());
gradient[i] = (f_plus - f0) / h;
}
Ok(gradient)
}
_ => {
let h = 1e-6;
let f0 = objective(¶ms.view());
let mut gradient = Array1::zeros(params.len());
for i in 0..params.len() {
let mut params_plus = params.clone();
params_plus[i] += h;
let f_plus = objective(¶ms_plus.view());
gradient[i] = (f_plus - f0) / h;
}
Ok(gradient)
}
}
}
}
#[allow(dead_code)]
pub fn few_shot_optimize<F>(
objective: F,
initial_params: &ArrayView1<f64>,
support_examples: &[SupportExample],
config: Option<LearnedOptimizationConfig>,
) -> super::Result<OptimizeResults<f64>>
where
F: Fn(&ArrayView1<f64>) -> f64,
{
let config = config.unwrap_or_default();
let mut optimizer = FewShotLearningOptimizer::new(config);
let problem = OptimizationProblem {
name: "few_shot_target".to_string(),
dimension: initial_params.len(),
problem_class: "general".to_string(),
metadata: HashMap::new(),
max_evaluations: 1000,
target_accuracy: 1e-6,
};
optimizer.few_shot_adapt(support_examples, &problem)?;
optimizer.optimize(objective, initial_params)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_few_shot_optimizer_creation() {
let config = LearnedOptimizationConfig::default();
let optimizer = FewShotLearningOptimizer::new(config);
assert_eq!(optimizer.adaptation_stats.support_examples_used, 0);
}
#[test]
fn test_feature_extractor() {
let extractor = FeatureExtractor::new(32);
let encoding = Array1::from(vec![1.0, 2.0, 3.0]);
let features = extractor.extract(&encoding).expect("Operation failed");
assert_eq!(features.len(), 32);
}
#[test]
fn test_parameter_generator() {
let generator = ParameterGenerator::new(16);
let encoding = Array1::from(vec![0.5, -0.3, 0.8]);
let params = generator.generate(&encoding).expect("Operation failed");
assert_eq!(params.len(), 16);
assert!(params.iter().all(|&x| x >= -1.0 && x <= 1.0));
}
#[test]
fn test_similarity_computation() {
let config = LearnedOptimizationConfig::default();
let optimizer = FewShotLearningOptimizer::new(config);
let encoding1 = Array1::from(vec![1.0, 0.0, 0.0]);
let encoding2 = Array1::from(vec![0.0, 1.0, 0.0]);
let similarity = optimizer
.compute_similarity(&encoding1, &encoding2)
.expect("Operation failed");
assert!(similarity >= 0.0 && similarity <= 1.0);
}
#[test]
fn test_few_shot_optimization() {
let objective = |x: &ArrayView1<f64>| x[0].powi(2) + x[1].powi(2);
let initial = Array1::from(vec![2.0, 2.0]);
let support_example = SupportExample {
problem_encoding: Array1::from(vec![1.0, 1.0, 0.0]),
trajectory: OptimizationTrajectory {
parameter_history: vec![Array1::from(vec![1.0, 1.0])],
objective_history: vec![2.0, 1.0],
gradient_history: vec![Array1::from(vec![0.5, 0.5])],
step_size_history: vec![0.01],
total_steps: 1,
},
success: true,
metadata: HashMap::new(),
};
let result = few_shot_optimize(objective, &initial.view(), &[support_example], None)
.expect("Operation failed");
assert!(result.fun >= 0.0);
assert_eq!(result.x.len(), 2);
assert!(result.success);
}
#[test]
fn test_adaptation_strategy_selection() {
let config = LearnedOptimizationConfig::default();
let optimizer = FewShotLearningOptimizer::new(config);
let support_features =
Array2::from_shape_fn((2, 10), |_| scirs2_core::random::rng().random::<f64>());
let similar_problems = vec!["problem1".to_string(), "problem2".to_string()];
let strategy = optimizer
.select_adaptation_strategy(&support_features, &similar_problems)
.expect("Operation failed");
match strategy {
AdaptationStrategy::Prototype => {}
AdaptationStrategy::MAML => {}
AdaptationStrategy::Gradient => {}
AdaptationStrategy::Hybrid { .. } => {}
}
}
}
#[allow(dead_code)]
pub fn placeholder() {
}