scirs2_ndimage/biological_vision_inspired/
predictive_coding.rs1use scirs2_core::ndarray::{Array3, Array4, ArrayView2};
7use scirs2_core::numeric::{Float, FromPrimitive};
8
9use super::config::{BiologicalVisionConfig, PredictiveCodingSystem};
10use crate::error::{NdimageError, NdimageResult};
11
12pub fn predictive_coding_visual_processing<T>(
17 image_sequence: &[ArrayView2<T>],
18 config: &BiologicalVisionConfig,
19) -> NdimageResult<PredictiveCodingSystem>
20where
21 T: Float + FromPrimitive + Copy + Send + Sync,
22{
23 if image_sequence.is_empty() {
24 return Err(NdimageError::InvalidInput(
25 "Empty image sequence".to_string(),
26 ));
27 }
28
29 let (height, width) = image_sequence[0].dim();
30 let mut predictive_system = initialize_predictive_coding_system(height, width, config)?;
31
32 for (t, image) in image_sequence.iter().enumerate() {
34 generate_predictions(&mut predictive_system, t, config)?;
36
37 compute_prediction_errors(&mut predictive_system, image, config)?;
39
40 update_prediction_models(&mut predictive_system, config)?;
42
43 estimate_prediction_confidence(&mut predictive_system, config)?;
45
46 adapt_to_prediction_errors(&mut predictive_system, config)?;
48 }
49
50 Ok(predictive_system)
51}
52
53pub fn initialize_predictive_coding_system(
55 height: usize,
56 width: usize,
57 config: &BiologicalVisionConfig,
58) -> NdimageResult<PredictiveCodingSystem> {
59 let num_levels = config.cortical_layers;
60 let mut prediction_models = Vec::new();
61 let mut prediction_errors = Vec::new();
62 let mut temporal_predictions = Vec::new();
63 let mut confidence_estimates = Vec::new();
64
65 for level in 0..num_levels {
66 let level_height = height / (level + 1);
67 let level_width = width / (level + 1);
68 let num_features = 2_usize.pow(level as u32 + 3);
69
70 prediction_models.push(Array3::zeros((num_features, level_height, level_width)));
72
73 prediction_errors.push(Array3::zeros((num_features, level_height, level_width)));
75
76 temporal_predictions.push(Array4::zeros((
78 config.motion_prediction_window,
79 num_features,
80 level_height,
81 level_width,
82 )));
83
84 confidence_estimates.push(Array3::zeros((num_features, level_height, level_width)));
86 }
87
88 Ok(PredictiveCodingSystem {
89 prediction_models,
90 prediction_errors,
91 temporal_predictions,
92 confidence_estimates,
93 })
94}
95
96pub fn generate_predictions(
98 system: &mut PredictiveCodingSystem,
99 time: usize,
100 config: &BiologicalVisionConfig,
101) -> NdimageResult<()> {
102 let num_levels = system.prediction_models.len();
103
104 for level in (0..num_levels - 1).rev() {
106 let higher_level = level + 1;
107
108 let (pred_features, pred_height, pred_width) = system.prediction_models[level].dim();
110 let (higher_features, higher_height, higher_width) =
111 system.prediction_models[higher_level].dim();
112
113 for pred_f in 0..pred_features {
115 for pred_y in 0..pred_height {
116 for pred_x in 0..pred_width {
117 let higher_y = pred_y * higher_height / pred_height;
119 let higher_x = pred_x * higher_width / pred_width;
120
121 if higher_y < higher_height && higher_x < higher_width {
122 let mut prediction = 0.0;
123
124 for higher_f in 0..higher_features.min(pred_features) {
126 prediction += system.prediction_models[higher_level]
127 [(higher_f, higher_y, higher_x)];
128 }
129
130 system.prediction_models[level][(pred_f, pred_y, pred_x)] =
131 prediction / higher_features.min(pred_features) as f64;
132 }
133 }
134 }
135 }
136 }
137
138 Ok(())
139}
140
141pub fn compute_prediction_errors<T>(
143 system: &mut PredictiveCodingSystem,
144 image: &ArrayView2<T>,
145 config: &BiologicalVisionConfig,
146) -> NdimageResult<()>
147where
148 T: Float + FromPrimitive + Copy,
149{
150 let (img_height, img_width) = image.dim();
151
152 if let Some(prediction_errors) = system.prediction_errors.get_mut(0) {
154 let (num_features, level_height, level_width) = prediction_errors.dim();
155
156 for feature_idx in 0..num_features {
157 for y in 0..level_height {
158 for x in 0..level_width {
159 let img_y = y * img_height / level_height;
161 let img_x = x * img_width / level_width;
162
163 if img_y < img_height && img_x < img_width {
164 let actual_value = image[(img_y, img_x)].to_f64().unwrap_or(0.0);
165 let predicted_value = system.prediction_models[0][(feature_idx, y, x)];
166 let error = actual_value - predicted_value;
167
168 prediction_errors[(feature_idx, y, x)] = error;
169 }
170 }
171 }
172 }
173 }
174
175 for level in 1..system.prediction_errors.len() {
177 let (current_features, current_height, current_width) =
178 system.prediction_errors[level].dim();
179 let (lower_features, lower_height, lower_width) = system.prediction_errors[level - 1].dim();
180
181 for feature_idx in 0..current_features {
182 for y in 0..current_height {
183 for x in 0..current_width {
184 let mut error_sum = 0.0;
186 let mut count = 0;
187
188 let scale_y = lower_height / current_height;
189 let scale_x = lower_width / current_width;
190
191 for dy in 0..scale_y {
192 for dx in 0..scale_x {
193 let lower_y = y * scale_y + dy;
194 let lower_x = x * scale_x + dx;
195
196 if lower_y < lower_height && lower_x < lower_width {
197 for lower_f in 0..lower_features.min(current_features) {
198 error_sum += system.prediction_errors[level - 1]
199 [(lower_f, lower_y, lower_x)]
200 .abs();
201 count += 1;
202 }
203 }
204 }
205 }
206
207 system.prediction_errors[level][(feature_idx, y, x)] = if count > 0 {
208 error_sum / count as f64
209 } else {
210 0.0
211 };
212 }
213 }
214 }
215 }
216
217 Ok(())
218}
219
220pub fn update_prediction_models(
222 system: &mut PredictiveCodingSystem,
223 config: &BiologicalVisionConfig,
224) -> NdimageResult<()> {
225 let learning_rate = 0.01;
226
227 for level in 0..system.prediction_models.len() {
229 let (num_features, height, width) = system.prediction_models[level].dim();
230
231 for feature_idx in 0..num_features {
232 for y in 0..height {
233 for x in 0..width {
234 let error = system.prediction_errors[level][(feature_idx, y, x)];
235 let current_prediction = system.prediction_models[level][(feature_idx, y, x)];
236
237 let updated_prediction = current_prediction + learning_rate * error;
239 system.prediction_models[level][(feature_idx, y, x)] = updated_prediction;
240 }
241 }
242 }
243 }
244
245 Ok(())
246}
247
248pub fn estimate_prediction_confidence(
250 system: &mut PredictiveCodingSystem,
251 config: &BiologicalVisionConfig,
252) -> NdimageResult<()> {
253 for level in 0..system.confidence_estimates.len() {
254 let (num_features, height, width) = system.confidence_estimates[level].dim();
255
256 for feature_idx in 0..num_features {
257 for y in 0..height {
258 for x in 0..width {
259 let error = system.prediction_errors[level][(feature_idx, y, x)].abs();
260
261 let confidence = 1.0 / (1.0 + error);
263 system.confidence_estimates[level][(feature_idx, y, x)] = confidence;
264 }
265 }
266 }
267 }
268
269 Ok(())
270}
271
272pub fn adapt_to_prediction_errors(
274 system: &mut PredictiveCodingSystem,
275 config: &BiologicalVisionConfig,
276) -> NdimageResult<()> {
277 let adaptation_rate = 0.001;
278
279 for level in 0..system.prediction_models.len() {
281 let (num_features, height, width) = system.prediction_models[level].dim();
282
283 for feature_idx in 0..num_features {
284 for y in 0..height {
285 for x in 0..width {
286 let error = system.prediction_errors[level][(feature_idx, y, x)];
287
288 if error.abs() > config.prediction_error_threshold {
290 let current_model = system.prediction_models[level][(feature_idx, y, x)];
291 let adapted_model =
292 current_model * (1.0 - adaptation_rate) + error * adaptation_rate;
293 system.prediction_models[level][(feature_idx, y, x)] = adapted_model;
294 }
295 }
296 }
297 }
298 }
299
300 Ok(())
301}