#[allow(dead_code)]
use scirs2_core::ndarray::{s, Array1, Array2};
use scirs2_core::numeric::Float;
use scirs2_core::random::Rng;
use scirs2_core::RngExt;
use scirs2_core::random::Rng as SCRRng;
use std::collections::{HashMap, VecDeque};
use std::fmt::Debug;
use super::{
architecture_space::{ComponentType, OptimizerComponent},
OptimizerArchitecture, SearchResult, SearchSpaceConfig,
};
use crate::error::{OptimError, Result};
pub trait ArchitectureController<T: Float + Debug + Send + Sync + 'static>: Send + Sync {
fn initialize(&mut self, searchspace: &SearchSpaceConfig) -> Result<()>;
fn generate_architecture(
&mut self,
context: &SearchContext<T>,
) -> Result<OptimizerArchitecture<T>>;
fn update_with_results(&mut self, results: &[SearchResult<T>]) -> Result<()>;
fn get_statistics(&self) -> ControllerStatistics<T>;
fn name(&self) -> &str;
fn reset(&mut self) -> Result<()>;
}
#[derive(Debug, Clone)]
pub struct SearchContext<T: Float + Debug + Send + Sync + 'static> {
pub generation: usize,
pub history: Vec<SearchResult<T>>,
pub best_performance: T,
pub average_performance: T,
pub resource_budget: ResourceBudget<T>,
pub preferences: SearchPreferences,
}
#[derive(Debug, Clone)]
pub struct ResourceBudget<T: Float + Debug + Send + Sync + 'static> {
pub memory_gb: T,
pub computation_flops: T,
pub time_seconds: T,
pub energy_kwh: T,
}
#[derive(Debug, Clone)]
pub struct SearchPreferences {
pub exploration_factor: f64,
pub complexity_preference: ComplexityPreference,
pub domain_preferences: Vec<DomainPreference>,
}
#[derive(Debug, Clone, Copy)]
pub enum ComplexityPreference {
Simple,
Moderate,
Complex,
Adaptive,
}
#[derive(Debug, Clone)]
pub struct DomainPreference {
pub domain: String,
pub weight: f64,
pub constraints: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ControllerStatistics<T: Float + Debug + Send + Sync + 'static> {
pub total_generated: usize,
pub success_rate: f64,
pub avg_generation_time_ms: f64,
pub diversity_score: T,
pub controller_metrics: HashMap<String, T>,
}
pub struct RNNController<
T: Float
+ Default
+ Clone
+ Send
+ Sync
+ 'static
+ std::iter::Sum
+ for<'a> std::iter::Sum<&'a T>
+ scirs2_core::ndarray::ScalarOperand,
> {
config: RNNControllerConfig,
rnn_layers: Vec<RNNLayer<T>>,
output_layer: OutputLayer<T>,
hidden_states: Vec<Array1<T>>,
cell_states: Vec<Array1<T>>,
embedding_layer: EmbeddingLayer<T>,
search_space: Option<SearchSpaceConfig>,
statistics: ControllerStatistics<T>,
training_history: VecDeque<TrainingBatch<T>>,
action_space: ActionSpace,
generation_count: usize,
}
#[derive(Debug, Clone)]
pub struct RNNControllerConfig {
pub hiddensize: usize,
pub numlayers: usize,
pub rnn_type: RNNType,
pub dropout_rate: f64,
pub learning_rate: f64,
pub temperature: f64,
pub use_attention: bool,
pub max_sequence_length: usize,
}
#[derive(Debug, Clone, Copy)]
pub enum RNNType {
LSTM,
GRU,
RNN,
}
#[derive(Debug, Clone)]
pub struct RNNLayer<T: Float + Debug + Send + Sync + 'static> {
layer_type: RNNType,
weight_ih: Array2<T>,
weight_hh: Array2<T>,
bias_ih: Array1<T>,
bias_hh: Array1<T>,
layer_norm: Option<LayerNorm<T>>,
dropout_mask: Option<Array1<bool>>,
}
#[derive(Debug, Clone)]
pub struct LayerNorm<T: Float + Debug + Send + Sync + 'static> {
scale: Array1<T>,
shift: Array1<T>,
eps: T,
}
#[derive(Debug, Clone)]
pub struct OutputLayer<T: Float + Debug + Send + Sync + 'static> {
weight: Array2<T>,
bias: Array1<T>,
activation: ActivationType,
}
#[derive(Debug, Clone, Copy)]
pub enum ActivationType {
Linear,
Softmax,
Sigmoid,
Tanh,
ReLU,
}
#[derive(Debug, Clone)]
pub struct EmbeddingLayer<T: Float + Debug + Send + Sync + 'static> {
embeddings: Array2<T>,
_vocab_size: usize,
embeddingdim: usize,
}
#[derive(Debug, Clone)]
pub struct TrainingBatch<T: Float + Debug + Send + Sync + 'static> {
inputs: Vec<Array1<usize>>,
targets: Vec<Array1<usize>>,
rewards: Vec<T>,
lengths: Vec<usize>,
}
#[derive(Debug, Clone)]
pub struct ActionSpace {
component_types: Vec<ComponentType>,
connection_types: Vec<String>,
hyperparameter_ranges: HashMap<ComponentType, Vec<(String, f64, f64)>>,
max_components: usize,
}
pub struct TransformerController<T: Float + Debug + Send + Sync + 'static> {
config: TransformerConfig,
layers: Vec<TransformerLayer<T>>,
positional_encoding: PositionalEncoding<T>,
input_embedding: EmbeddingLayer<T>,
output_projection: OutputLayer<T>,
layer_norm: LayerNorm<T>,
search_space: Option<SearchSpaceConfig>,
statistics: ControllerStatistics<T>,
generation_count: usize,
}
#[derive(Debug, Clone)]
pub struct TransformerConfig {
pub _model_dim: usize,
pub numheads: usize,
pub numlayers: usize,
pub ffdim: usize,
pub dropout_rate: f64,
pub learning_rate: f64,
pub temperature: f64,
pub max_sequence_length: usize,
}
#[derive(Debug, Clone)]
pub struct TransformerLayer<T: Float + Debug + Send + Sync + 'static> {
attention: MultiHeadAttention<T>,
feed_forward: FeedForward<T>,
norm1: LayerNorm<T>,
norm2: LayerNorm<T>,
dropout: f64,
}
#[derive(Debug, Clone)]
pub struct MultiHeadAttention<T: Float + Debug + Send + Sync + 'static> {
numheads: usize,
head_dim: usize,
query_proj: Array2<T>,
key_proj: Array2<T>,
value_proj: Array2<T>,
output_proj: Array2<T>,
dropout: f64,
}
#[derive(Debug, Clone)]
pub struct FeedForward<T: Float + Debug + Send + Sync + 'static> {
linear1: LinearLayer<T>,
linear2: LinearLayer<T>,
activation: ActivationType,
dropout: f64,
}
#[derive(Debug, Clone)]
pub struct LinearLayer<T: Float + Debug + Send + Sync + 'static> {
weight: Array2<T>,
bias: Array1<T>,
}
#[derive(Debug, Clone)]
pub struct PositionalEncoding<T: Float + Debug + Send + Sync + 'static> {
encoding: Array2<T>,
max_length: usize,
_model_dim: usize,
}
pub struct RandomController<T: Float + Debug + Send + Sync + 'static> {
component_types: Vec<ComponentType>,
search_space: Option<SearchSpaceConfig>,
statistics: ControllerStatistics<T>,
seed: Option<u64>,
generation_count: usize,
}
pub struct EvolutionaryController<T: Float + Debug + Send + Sync + 'static> {
population: Vec<ControllerGenome<T>>,
population_size: usize,
mutation_rate: f64,
crossover_rate: f64,
elite_size: usize,
search_space: Option<SearchSpaceConfig>,
statistics: ControllerStatistics<T>,
generation_count: usize,
}
#[derive(Debug, Clone)]
pub struct ControllerGenome<T: Float + Debug + Send + Sync + 'static> {
encoding: Vec<T>,
fitness: T,
age: usize,
performance_history: Vec<T>,
}
impl<
T: Float
+ Default
+ Clone
+ Send
+ Sync
+ 'static
+ std::iter::Sum
+ for<'a> std::iter::Sum<&'a T>
+ scirs2_core::ndarray::ScalarOperand,
> RNNController<T>
{
pub fn new(hiddensize: usize, numlayers: usize, _vocab_size: usize) -> Result<Self> {
let config = RNNControllerConfig {
hiddensize,
numlayers,
rnn_type: RNNType::LSTM,
dropout_rate: 0.1,
learning_rate: 0.001,
temperature: 1.0,
use_attention: false,
max_sequence_length: 50,
};
let mut rnn_layers = Vec::new();
for i in 0..numlayers {
let input_size = if i == 0 { hiddensize } else { hiddensize };
rnn_layers.push(RNNLayer::new(RNNType::LSTM, input_size, hiddensize)?);
}
let output_layer = OutputLayer::new(hiddensize, _vocab_size, ActivationType::Softmax)?;
let embedding_layer = EmbeddingLayer::new(_vocab_size, hiddensize)?;
let hidden_states = vec![Array1::zeros(hiddensize); numlayers];
let cell_states = vec![Array1::zeros(hiddensize); numlayers];
Ok(Self {
config,
rnn_layers,
output_layer,
hidden_states,
cell_states,
embedding_layer,
search_space: None,
statistics: ControllerStatistics::default(),
training_history: VecDeque::new(),
action_space: ActionSpace::default(),
generation_count: 0,
})
}
fn forward(&mut self, inputsequence: &[usize]) -> Result<Array2<T>> {
let seq_len = inputsequence.len();
let _vocab_size = self.action_space.component_types.len();
let mut outputs = Array2::zeros((seq_len, _vocab_size));
for state in &mut self.hidden_states {
state.fill(T::zero());
}
for state in &mut self.cell_states {
state.fill(T::zero());
}
for (t, &input_token) in inputsequence.iter().enumerate() {
let embedded = self.embedding_layer.forward(input_token)?;
let mut layer_input = embedded;
for (layer_idx, layer) in self.rnn_layers.iter_mut().enumerate() {
let (hidden_output, cell_output) = layer.forward(
&layer_input,
&self.hidden_states[layer_idx],
&self.cell_states[layer_idx],
)?;
self.hidden_states[layer_idx] = hidden_output.clone();
self.cell_states[layer_idx] = cell_output;
layer_input = hidden_output;
}
let output = self.output_layer.forward(&layer_input)?;
outputs.row_mut(t).assign(&output);
}
Ok(outputs)
}
fn sample_architecture(&mut self) -> Result<OptimizerArchitecture<T>> {
let mut components = Vec::new();
let mut sequence = Vec::new();
sequence.push(0);
for _ in 0..self.config.max_sequence_length {
let logits = self.forward(&sequence)?;
let last_logits = logits.row(logits.nrows() - 1);
let token = self.sample_from_logits(&last_logits.to_owned())?;
if token == 1 {
break;
}
sequence.push(token);
if token >= 2 && token < self.action_space.component_types.len() + 2 {
let component_type = self.action_space.component_types[token - 2].clone();
let component = self.create_component_from_type(component_type)?;
components.push(component);
}
}
if components.is_empty() {
let default_component = self.create_component_from_type(ComponentType::Adam)?;
components.push(default_component);
}
Ok(OptimizerArchitecture {
components,
connections: Vec::new(),
metadata: HashMap::new(),
})
}
fn sample_from_logits(&self, logits: &Array1<T>) -> Result<usize> {
let scaled_logits = logits.mapv(|x| x / scirs2_core::numeric::NumCast::from(self.config.temperature).unwrap_or_else(|| T::zero()));
let max_logit = scaled_logits
.iter()
.cloned()
.fold(T::neg_infinity(), |a, b| if a > b { a } else { b });
let exp_logits = scaled_logits.mapv(|x| (x - max_logit).exp());
let sum_exp = exp_logits.sum();
let probs = exp_logits / sum_exp;
let mut rng = scirs2_core::random::thread_rng();
let rand_val = rng.random::<f64>();
let mut cumulative = 0.0;
for (i, &prob) in probs.iter().enumerate() {
cumulative += prob.to_f64().unwrap_or(0.0);
if cumulative >= rand_val {
return Ok(i);
}
}
Ok(probs.len() - 1) }
fn create_component_from_type(
&self,
component_type: ComponentType,
) -> Result<OptimizerComponent<T>> {
let mut hyperparameters = HashMap::new();
match component_type {
ComponentType::Adam => {
hyperparameters.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
hyperparameters.insert("beta1".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
hyperparameters.insert("beta2".to_string(), scirs2_core::numeric::NumCast::from(0.999).unwrap_or_else(|| T::zero()));
hyperparameters.insert("epsilon".to_string(), scirs2_core::numeric::NumCast::from(1e-8).unwrap_or_else(|| T::zero()));
}
ComponentType::SGD => {
hyperparameters.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.01).unwrap_or_else(|| T::zero()));
hyperparameters.insert("momentum".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
hyperparameters.insert("weight_decay".to_string(), scirs2_core::numeric::NumCast::from(0.0001).unwrap_or_else(|| T::zero()));
}
_ => {
hyperparameters.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
}
}
Ok(OptimizerComponent {
component_type,
hyperparameters,
connections: Vec::new(),
})
}
}
impl<
T: Float
+ Default
+ Clone
+ Send
+ Sync
+ 'static
+ std::iter::Sum
+ for<'a> std::iter::Sum<&'a T>
+ scirs2_core::ndarray::ScalarOperand,
> ArchitectureController<T> for RNNController<T>
{
fn initialize(&mut self, searchspace: &SearchSpaceConfig) -> Result<()> {
self.search_space = Some(searchspace.clone());
self.action_space = ActionSpace {
component_types: searchspace
.optimizer_components
.iter()
.map(|c| c.componenttype.clone())
.collect(),
connection_types: vec!["sequential".to_string(), "parallel".to_string()],
hyperparameter_ranges: HashMap::new(),
max_components: 10,
};
self.generation_count = 0;
Ok(())
}
fn generate_architecture(
&mut self,
context: &SearchContext<T>,
) -> Result<OptimizerArchitecture<T>> {
let architecture = self.sample_architecture()?;
self.generation_count += 1;
self.statistics.total_generated += 1;
Ok(architecture)
}
fn update_with_results(&mut self, results: &[SearchResult<T>]) -> Result<()> {
let mut batch = TrainingBatch {
inputs: Vec::new(),
targets: Vec::new(),
rewards: Vec::new(),
lengths: Vec::new(),
};
for result in results {
let reward = result
.evaluation_results
.metric_scores
.get(&super::EvaluationMetric::FinalPerformance)
.cloned()
.unwrap_or(T::zero());
batch.rewards.push(reward);
let input_seq = self.architecture_to_sequence(&result.architecture)?;
let seq_len = input_seq.len();
batch.inputs.push(Array1::from_vec(input_seq.clone()));
batch.targets.push(Array1::from_vec(input_seq)); batch.lengths.push(seq_len);
}
self.training_history.push_back(batch);
if self.training_history.len() > 100 {
self.training_history.pop_front();
}
let avg_reward = if !results.is_empty() {
results
.iter()
.filter_map(|r| {
r.evaluation_results
.metric_scores
.get(&super::EvaluationMetric::FinalPerformance)
})
.sum::<T>()
/ T::from(results.len()).expect("unwrap failed")
} else {
T::zero()
};
self.statistics
.controller_metrics
.insert("avg_reward".to_string(), avg_reward);
Ok(())
}
fn get_statistics(&self) -> ControllerStatistics<T> {
self.statistics.clone()
}
fn name(&self) -> &str {
"RNNController"
}
fn reset(&mut self) -> Result<()> {
for state in &mut self.hidden_states {
state.fill(T::zero());
}
for state in &mut self.cell_states {
state.fill(T::zero());
}
self.generation_count = 0;
Ok(())
}
}
impl<
T: Float
+ Default
+ Clone
+ Send
+ Sync
+ 'static
+ std::iter::Sum
+ for<'a> std::iter::Sum<&'a T>
+ scirs2_core::ndarray::ScalarOperand,
> RNNController<T>
{
fn architecture_to_sequence(
&self,
architecture: &OptimizerArchitecture<T>,
) -> Result<Vec<usize>> {
let mut sequence = vec![0];
for component in &architecture.components {
if let Some(pos) = self
.action_space
.component_types
.iter()
.position(|x| *x == component.component_type)
{
sequence.push(pos + 2); }
}
sequence.push(1); Ok(sequence)
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + 'static + scirs2_core::ndarray::ScalarOperand>
TransformerController<T>
{
pub fn new(_model_dim: usize, numheads: usize, numlayers: usize) -> Result<Self> {
let config = TransformerConfig {
_model_dim,
numheads,
numlayers,
ffdim: _model_dim * 4,
dropout_rate: 0.1,
learning_rate: 0.001,
temperature: 1.0,
max_sequence_length: 50,
};
let mut layers = Vec::new();
for _ in 0..numlayers {
layers.push(TransformerLayer::new(_model_dim, numheads, _model_dim * 4)?);
}
let positional_encoding = PositionalEncoding::new(config.max_sequence_length, _model_dim)?;
let input_embedding = EmbeddingLayer::new(1000, _model_dim)?; let output_projection = OutputLayer::new(_model_dim, 1000, ActivationType::Softmax)?;
let layer_norm = LayerNorm::new(_model_dim)?;
Ok(Self {
config,
layers,
positional_encoding,
input_embedding,
output_projection,
layer_norm,
search_space: None,
statistics: ControllerStatistics::default(),
generation_count: 0,
})
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + std::iter::Sum> ArchitectureController<T>
for TransformerController<T>
{
fn initialize(&mut self, searchspace: &SearchSpaceConfig) -> Result<()> {
self.search_space = Some(searchspace.clone());
self.generation_count = 0;
Ok(())
}
fn generate_architecture(
&mut self,
context: &SearchContext<T>,
) -> Result<OptimizerArchitecture<T>> {
use super::architecture_space::{ComponentType, OptimizerComponent};
let component = OptimizerComponent {
component_type: ComponentType::Adam,
hyperparameters: {
let mut params = HashMap::new();
params.insert("learning_rate".to_string(), scirs2_core::numeric::NumCast::from(0.001).unwrap_or_else(|| T::zero()));
params.insert("beta1".to_string(), scirs2_core::numeric::NumCast::from(0.9).unwrap_or_else(|| T::zero()));
params.insert("beta2".to_string(), scirs2_core::numeric::NumCast::from(0.999).unwrap_or_else(|| T::zero()));
params
},
connections: Vec::new(),
};
self.generation_count += 1;
self.statistics.total_generated += 1;
Ok(OptimizerArchitecture {
components: vec![component],
connections: Vec::new(),
metadata: HashMap::new(),
})
}
fn update_with_results(&mut self, results: &[SearchResult<T>]) -> Result<()> {
Ok(())
}
fn get_statistics(&self) -> ControllerStatistics<T> {
self.statistics.clone()
}
fn name(&self) -> &str {
"TransformerController"
}
fn reset(&mut self) -> Result<()> {
self.generation_count = 0;
Ok(())
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + std::iter::Sum> RandomController<T> {
pub fn new(_vocabsize: usize) -> Result<Self> {
Ok(Self {
component_types: vec![
ComponentType::Adam,
ComponentType::SGD,
ComponentType::AdaGrad,
],
search_space: None,
statistics: ControllerStatistics::default(),
seed: None,
generation_count: 0,
})
}
}
impl<T: Float + Debug + Default + Clone + Send + Sync + std::iter::Sum> ArchitectureController<T>
for RandomController<T>
{
fn initialize(&mut self, searchspace: &SearchSpaceConfig) -> Result<()> {
self.search_space = Some(searchspace.clone());
self.component_types = searchspace
.optimizer_components
.iter()
.map(|c| c.componenttype.clone())
.collect();
self.generation_count = 0;
Ok(())
}
fn generate_architecture(
&mut self,
context: &SearchContext<T>,
) -> Result<OptimizerArchitecture<T>> {
use super::architecture_space::{ComponentType, OptimizerComponent};
let mut rng = scirs2_core::random::thread_rng();
let component_type =
self.component_types[rng.gen_range(0..self.component_types.len())].clone();
let mut hyperparameters = HashMap::new();
match component_type {
ComponentType::Adam => {
hyperparameters.insert(
"learning_rate".to_string(),
T::from(rng.random::<f64>() * 0.01).expect("unwrap failed"),
);
hyperparameters.insert(
"beta1".to_string(),
T::from(0.8 + rng.random::<f64>() * 0.19).expect("unwrap failed"),
);
hyperparameters.insert(
"beta2".to_string(),
T::from(0.9 + rng.random::<f64>() * 0.099).expect("unwrap failed"),
);
}
ComponentType::SGD => {
hyperparameters.insert(
"learning_rate".to_string(),
T::from(rng.random::<f64>() * 0.1).expect("unwrap failed"),
);
hyperparameters.insert(
"momentum".to_string(),
T::from(rng.random::<f64>() * 0.99).expect("unwrap failed"),
);
}
_ => {
hyperparameters.insert(
"learning_rate".to_string(),
T::from(rng.random::<f64>() * 0.01).expect("unwrap failed"),
);
}
}
let component = OptimizerComponent {
component_type,
hyperparameters,
connections: Vec::new(),
};
self.generation_count += 1;
self.statistics.total_generated += 1;
Ok(OptimizerArchitecture {
components: vec![component],
connections: Vec::new(),
metadata: HashMap::new(),
})
}
fn update_with_results(&mut self, results: &[SearchResult<T>]) -> Result<()> {
Ok(())
}
fn get_statistics(&self) -> ControllerStatistics<T> {
self.statistics.clone()
}
fn name(&self) -> &str {
"RandomController"
}
fn reset(&mut self) -> Result<()> {
self.generation_count = 0;
Ok(())
}
}
impl<T: Float + Debug + Default + Clone + 'static + scirs2_core::ndarray::ScalarOperand + Send + Sync> RNNLayer<T> {
fn new(layer_type: RNNType, input_size: usize, hiddensize: usize) -> Result<Self> {
let gate_size = match layer_type {
RNNType::LSTM => hiddensize * 4,
RNNType::GRU => hiddensize * 3,
RNNType::RNN => hiddensize,
};
Ok(Self {
layer_type,
weight_ih: Array2::zeros((gate_size, input_size)),
weight_hh: Array2::zeros((gate_size, hiddensize)),
bias_ih: Array1::zeros(gate_size),
bias_hh: Array1::zeros(gate_size),
layer_norm: None,
dropout_mask: None,
})
}
fn forward(
&self,
input: &Array1<T>,
hidden: &Array1<T>,
cell: &Array1<T>,
) -> Result<(Array1<T>, Array1<T>)> {
match self.layer_type {
RNNType::LSTM => self.lstm_forward(input, hidden, cell),
RNNType::GRU => self.gru_forward(input, hidden),
RNNType::RNN => self.rnn_forward(input, hidden),
}
}
fn lstm_forward(
&self,
input: &Array1<T>,
hidden: &Array1<T>,
cell: &Array1<T>,
) -> Result<(Array1<T>, Array1<T>)> {
let hiddensize = hidden.len();
let gi = self.weight_ih.dot(input) + &self.bias_ih;
let gh = self.weight_hh.dot(hidden) + &self.bias_hh;
let combined = gi + gh;
let input_gate = Self::sigmoid(&combined.slice(s![0..hiddensize]).to_owned());
let forget_gate = Self::sigmoid(&combined.slice(s![hiddensize..2 * hiddensize]).to_owned());
let cell_gate = Self::tanh(
&combined
.slice(s![2 * hiddensize..3 * hiddensize])
.to_owned(),
);
let output_gate = Self::sigmoid(
&combined
.slice(s![3 * hiddensize..4 * hiddensize])
.to_owned(),
);
let new_cell = &forget_gate * cell + &input_gate * &cell_gate;
let new_hidden = &output_gate * &Self::tanh(&new_cell);
Ok((new_hidden, new_cell))
}
fn gru_forward(&self, input: &Array1<T>, hidden: &Array1<T>) -> Result<(Array1<T>, Array1<T>)> {
let hiddensize = hidden.len();
let gi = self.weight_ih.dot(input) + &self.bias_ih;
let gh = self.weight_hh.dot(hidden) + &self.bias_hh;
let reset_gate = Self::sigmoid(
&(gi.slice(s![0..hiddensize]).to_owned() + gh.slice(s![0..hiddensize]).to_owned()),
);
let update_gate = Self::sigmoid(
&(gi.slice(s![hiddensize..2 * hiddensize]).to_owned()
+ gh.slice(s![hiddensize..2 * hiddensize]).to_owned()),
);
let new_gate = Self::tanh(
&(gi.slice(s![2 * hiddensize..3 * hiddensize]).to_owned()
+ &reset_gate * &gh.slice(s![2 * hiddensize..3 * hiddensize]).to_owned()),
);
let one_minus_update = update_gate.mapv(|x| T::one() - x);
let new_hidden = &update_gate * hidden + &one_minus_update * &new_gate;
Ok((new_hidden.clone(), new_hidden))
}
fn rnn_forward(&self, input: &Array1<T>, hidden: &Array1<T>) -> Result<(Array1<T>, Array1<T>)> {
let gi = self.weight_ih.dot(input) + &self.bias_ih;
let gh = self.weight_hh.dot(hidden) + &self.bias_hh;
let new_hidden = Self::tanh(&(gi + gh));
Ok((new_hidden.clone(), new_hidden))
}
fn sigmoid(x: &Array1<T>) -> Array1<T> {
x.mapv(|xi| T::one() / (T::one() + (-xi).exp()))
}
fn tanh(x: &Array1<T>) -> Array1<T> {
x.mapv(|xi| xi.tanh())
}
}
impl<T: Float + Debug + Default + Clone + 'static + scirs2_core::ndarray::ScalarOperand + Send + Sync> OutputLayer<T> {
fn new(input_size: usize, outputsize: usize, activation: ActivationType) -> Result<Self> {
Ok(Self {
weight: Array2::zeros((outputsize, input_size)),
bias: Array1::zeros(outputsize),
activation,
})
}
fn forward(&self, input: &Array1<T>) -> Result<Array1<T>> {
let output = self.weight.dot(input) + &self.bias;
match self.activation {
ActivationType::Linear => Ok(output),
ActivationType::Softmax => Ok(Self::softmax(&output)),
ActivationType::Sigmoid => Ok(Self::sigmoid(&output)),
ActivationType::Tanh => Ok(output.mapv(|x| x.tanh())),
ActivationType::ReLU => Ok(output.mapv(|x| if x > T::zero() { x } else { T::zero() })),
}
}
fn softmax(x: &Array1<T>) -> Array1<T> {
let max_val = x
.iter()
.cloned()
.fold(T::neg_infinity(), |a, b| if a > b { a } else { b });
let exp_x = x.mapv(|xi| (xi - max_val).exp());
let sum_exp = exp_x.sum();
exp_x / sum_exp
}
fn sigmoid(x: &Array1<T>) -> Array1<T> {
x.mapv(|xi| T::one() / (T::one() + (-xi).exp()))
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> EmbeddingLayer<T> {
fn new(_vocab_size: usize, embeddingdim: usize) -> Result<Self> {
Ok(Self {
embeddings: Array2::zeros((_vocab_size, embeddingdim)),
_vocab_size,
embeddingdim,
})
}
fn forward(&self, token: usize) -> Result<Array1<T>> {
if token >= self._vocab_size {
return Err(OptimError::InvalidConfig(format!(
"Token {} out of vocabulary",
token
)));
}
Ok(self.embeddings.row(token).to_owned())
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> TransformerLayer<T> {
fn new(_model_dim: usize, numheads: usize, ffdim: usize) -> Result<Self> {
Ok(Self {
attention: MultiHeadAttention::new(_model_dim, numheads)?,
feed_forward: FeedForward::new(_model_dim, ffdim)?,
norm1: LayerNorm::new(_model_dim)?,
norm2: LayerNorm::new(_model_dim)?,
dropout: 0.1,
})
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> MultiHeadAttention<T> {
fn new(_model_dim: usize, numheads: usize) -> Result<Self> {
let head_dim = _model_dim / numheads;
Ok(Self {
numheads,
head_dim,
query_proj: Array2::zeros((_model_dim, _model_dim)),
key_proj: Array2::zeros((_model_dim, _model_dim)),
value_proj: Array2::zeros((_model_dim, _model_dim)),
output_proj: Array2::zeros((_model_dim, _model_dim)),
dropout: 0.1,
})
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> FeedForward<T> {
fn new(input_dim: usize, ffdim: usize) -> Result<Self> {
Ok(Self {
linear1: LinearLayer::new(input_dim, ffdim)?,
linear2: LinearLayer::new(ffdim, input_dim)?,
activation: ActivationType::ReLU,
dropout: 0.1,
})
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> LinearLayer<T> {
fn new(input_dim: usize, outputdim: usize) -> Result<Self> {
Ok(Self {
weight: Array2::zeros((outputdim, input_dim)),
bias: Array1::zeros(outputdim),
})
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> LayerNorm<T> {
fn new(dim: usize) -> Result<Self> {
Ok(Self {
scale: Array1::ones(dim),
shift: Array1::zeros(dim),
eps: scirs2_core::numeric::NumCast::from(1e-6).unwrap_or_else(|| T::zero()),
})
}
}
impl<T: Float + Debug + Send + Sync + 'static + Default + Clone> PositionalEncoding<T> {
fn new(max_length: usize, _model_dim: usize) -> Result<Self> {
let mut encoding = Array2::zeros((max_length, _model_dim));
for pos in 0..max_length {
for i in 0.._model_dim / 2 {
let angle = pos as f64 / 10000_f64.powf(2.0 * i as f64 / _model_dim as f64);
encoding[[pos, 2 * i]] = T::from(angle.sin()).expect("unwrap failed");
encoding[[pos, 2 * i + 1]] = T::from(angle.cos()).expect("unwrap failed");
}
}
Ok(Self {
encoding,
max_length,
_model_dim,
})
}
}
impl Default for ActionSpace {
fn default() -> Self {
Self {
component_types: vec![
ComponentType::Adam,
ComponentType::SGD,
ComponentType::AdaGrad,
],
connection_types: vec!["sequential".to_string(), "parallel".to_string()],
hyperparameter_ranges: HashMap::new(),
max_components: 10,
}
}
}
impl<T: Float + Debug + Default + Send + Sync> Default for ControllerStatistics<T> {
fn default() -> Self {
Self {
total_generated: 0,
success_rate: 0.0,
avg_generation_time_ms: 0.0,
diversity_score: T::zero(),
controller_metrics: HashMap::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rnn_controller_creation() {
let controller = RNNController::<f64>::new(256, 2, 100);
assert!(controller.is_ok());
let controller = controller.expect("unwrap failed");
assert_eq!(controller.name(), "RNNController");
}
#[test]
fn test_transformer_controller_creation() {
let controller = TransformerController::<f64>::new(512, 8, 4);
assert!(controller.is_ok());
let controller = controller.expect("unwrap failed");
assert_eq!(controller.name(), "TransformerController");
}
#[test]
fn test_random_controller_creation() {
let controller = RandomController::<f64>::new(100);
assert!(controller.is_ok());
let controller = controller.expect("unwrap failed");
assert_eq!(controller.name(), "RandomController");
}
}