1use crate::data_pipeline::PipelineStageProperties;
2use crate::data_types::descriptors::{
3 ImageFrameProperties, MiscDataDimensions, PercentageChannelDimensionality,
4 SegmentedImageFrameProperties,
5};
6use crate::data_types::{
7 GazeProperties, ImageFilteringSettings, ImageFrame, MiscData, Percentage, Percentage2D,
8 Percentage3D, Percentage4D, SegmentedImageFrame, SignedPercentage, SignedPercentage2D,
9 SignedPercentage3D, SignedPercentage4D,
10};
11use crate::feedbacks::FeedbackRegistrar;
12use crate::neuron_voxel_coding::xyzp::decoders::{
13 GazePropertiesNeuronVoxelXYZPDecoder, ImageFilteringSettingsNeuronVoxelXYZPDecoder,
14 MiscDataNeuronVoxelXYZPDecoder, PercentageNeuronVoxelXYZPDecoder,
15};
16use crate::neuron_voxel_coding::xyzp::encoders::{
17 BooleanNeuronVoxelXYZPEncoder, CartesianPlaneNeuronVoxelXYZPEncoder,
18 MiscDataNeuronVoxelXYZPEncoder, PercentageNeuronVoxelXYZPEncoder,
19 SegmentedImageFrameNeuronVoxelXYZPEncoder,
20};
21use crate::neuron_voxel_coding::xyzp::{NeuronVoxelXYZPDecoder, NeuronVoxelXYZPEncoder};
22use crate::wrapped_io_data::WrappedIOData;
23use feagi_structures::genomic::cortical_area::descriptors::{
24 CorticalChannelCount, CorticalChannelIndex, CorticalUnitIndex, NeuronDepth,
25};
26use feagi_structures::genomic::cortical_area::io_cortical_area_configuration_flag::PercentageNeuronPositioning;
27use feagi_structures::genomic::cortical_area::CorticalID;
28use feagi_structures::genomic::{MotorCorticalUnit, SensoryCorticalUnit};
29use feagi_structures::FeagiDataError;
30use serde::{Deserialize, Serialize};
31use std::collections::HashMap;
32
33#[derive(Serialize, Deserialize, Clone, Debug)]
36pub struct JSONInputOutputDefinition {
37 input_units_and_encoder_properties:
38 HashMap<SensoryCorticalUnit, Vec<(JSONUnitDefinition, JSONEncoderProperties)>>,
39 output_units_and_decoder_properties:
40 HashMap<MotorCorticalUnit, Vec<(JSONUnitDefinition, JSONDecoderProperties)>>,
41 feedbacks: FeedbackRegistrar,
42}
43
44impl JSONInputOutputDefinition {
45 pub fn new() -> JSONInputOutputDefinition {
46 JSONInputOutputDefinition {
47 input_units_and_encoder_properties: HashMap::new(),
48 output_units_and_decoder_properties: HashMap::new(),
49 feedbacks: FeedbackRegistrar::new(),
50 }
51 }
52
53 pub fn get_input_units_and_encoder_properties(
54 &self,
55 ) -> &HashMap<SensoryCorticalUnit, Vec<(JSONUnitDefinition, JSONEncoderProperties)>> {
56 &self.input_units_and_encoder_properties
57 }
58
59 pub fn get_output_units_and_decoder_properties(
60 &self,
61 ) -> &HashMap<MotorCorticalUnit, Vec<(JSONUnitDefinition, JSONDecoderProperties)>> {
62 &self.output_units_and_decoder_properties
63 }
64
65 pub fn verify_valid_structure(&self) -> Result<(), FeagiDataError> {
66 for units_and_encoders in self.input_units_and_encoder_properties.values() {
67 let mut unit_indexes: Vec<CorticalUnitIndex> = Vec::new();
68 for unit in units_and_encoders {
69 unit.0.verify_valid_structure()?;
70 if unit_indexes.contains(&unit.0.cortical_unit_index) {
71 return Err(FeagiDataError::DeserializationError(
72 "Duplicate cortical unit indexes found!".into(),
73 ));
74 }
75 unit_indexes.push(unit.0.cortical_unit_index);
76 }
77 }
78 for units_and_decoders in self.output_units_and_decoder_properties.values() {
79 let mut unit_indexes: Vec<CorticalUnitIndex> = Vec::new();
80 for unit in units_and_decoders {
81 unit.0.verify_valid_structure()?;
82 if unit_indexes.contains(&unit.0.cortical_unit_index) {
83 return Err(FeagiDataError::DeserializationError(
84 "Duplicate cortical unit indexes found!".into(),
85 ));
86 }
87 unit_indexes.push(unit.0.cortical_unit_index);
88 }
89 }
90
91 Ok(())
92 }
93
94 pub fn insert_motor(
95 &mut self,
96 motor: MotorCorticalUnit,
97 unit_definition: JSONUnitDefinition,
98 decoder_properties: JSONDecoderProperties,
99 ) {
100 if let std::collections::hash_map::Entry::Vacant(entry) =
101 self.output_units_and_decoder_properties.entry(motor)
102 {
103 entry.insert(vec![(unit_definition, decoder_properties)]);
104 return;
105 }
106 let vec = self
107 .output_units_and_decoder_properties
108 .get_mut(&motor)
109 .unwrap();
110 vec.push((unit_definition, decoder_properties));
111 }
112
113 pub fn insert_sensor(
114 &mut self,
115 sensor: SensoryCorticalUnit,
116 unit_definition: JSONUnitDefinition,
117 encoder_properties: JSONEncoderProperties,
118 ) {
119 if let std::collections::hash_map::Entry::Vacant(entry) =
120 self.input_units_and_encoder_properties.entry(sensor)
121 {
122 entry.insert(vec![(unit_definition, encoder_properties)]);
123 return;
124 }
125 let vec = self
126 .input_units_and_encoder_properties
127 .get_mut(&sensor)
128 .unwrap();
129 vec.push((unit_definition, encoder_properties));
130 }
131
132 pub(crate) fn get_feedbacks(&self) -> &FeedbackRegistrar {
133 &self.feedbacks
134 }
135 pub(crate) fn set_feedbacks(&mut self, feedbacks: FeedbackRegistrar) {
136 self.feedbacks = feedbacks;
137 }
138}
139
140impl Default for JSONInputOutputDefinition {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(Serialize, Deserialize, Clone, Debug)]
149pub struct JSONUnitDefinition {
150 pub(crate) friendly_name: Option<String>,
151 pub(crate) cortical_unit_index: CorticalUnitIndex,
152 pub(crate) io_configuration_flags: serde_json::Map<String, serde_json::Value>, pub(crate) device_grouping: Vec<JSONDeviceGrouping>,
154}
155
156impl JSONUnitDefinition {
157 pub fn verify_valid_structure(&self) -> Result<(), FeagiDataError> {
158 if self.device_grouping.is_empty() {
159 return Err(FeagiDataError::DeserializationError(
160 "Cannot have a cortical unit of 0 device grouping!".to_string(),
161 ));
162 }
163 let number_channels = self.device_grouping.len() as u32;
164 for device_grouping in &self.device_grouping {
165 if let Some(channel_override) = device_grouping.channel_index_override {
166 if *channel_override > number_channels {
167 return Err(FeagiDataError::DeserializationError(
168 "Device has invalid channel override!".to_string(),
169 ));
170 }
171 }
172
173 let _stages = &device_grouping.pipeline_stages;
174 }
176 Ok(())
177 }
178
179 pub fn get_channel_count(&self) -> Result<CorticalChannelCount, FeagiDataError> {
180 CorticalChannelCount::new(self.device_grouping.len() as u32)
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct JSONDeviceGrouping {
187 pub(crate) friendly_name: Option<String>,
188 pub(crate) device_properties: JSONDeviceProperties,
189 pub(crate) channel_index_override: Option<CorticalChannelIndex>,
190 pub(crate) pipeline_stages: Vec<PipelineStageProperties>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
197pub enum JSONEncoderProperties {
198 Boolean,
199 CartesianPlane(ImageFrameProperties),
200 MiscData(MiscDataDimensions),
201 Percentage(
202 NeuronDepth,
203 PercentageNeuronPositioning,
204 bool,
205 PercentageChannelDimensionality,
206 ),
207 SegmentedImageFrame(SegmentedImageFrameProperties),
208}
209
210impl JSONEncoderProperties {
211 pub fn to_box_encoder(
212 &self,
213 number_channels: CorticalChannelCount,
214 cortical_ids: &[CorticalID],
215 ) -> Result<Box<dyn NeuronVoxelXYZPEncoder + Sync + Send>, FeagiDataError> {
216 match self {
217 JSONEncoderProperties::Boolean => {
218 if cortical_ids.len() != 1 {
219 return Err(FeagiDataError::InternalError(
220 "Expected one cortical id!".to_string(),
221 ));
222 }
223 BooleanNeuronVoxelXYZPEncoder::new_box(
224 *cortical_ids.first().unwrap(),
225 number_channels,
226 )
227 }
228 JSONEncoderProperties::CartesianPlane(image_frame) => {
229 if cortical_ids.len() != 1 {
230 return Err(FeagiDataError::InternalError(
231 "Expected one cortical id!".to_string(),
232 ));
233 }
234 CartesianPlaneNeuronVoxelXYZPEncoder::new_box(
235 *cortical_ids.first().unwrap(),
236 image_frame,
237 number_channels,
238 )
239 }
240 JSONEncoderProperties::MiscData(misc_data_dimensions) => {
241 if cortical_ids.len() != 1 {
242 return Err(FeagiDataError::InternalError(
243 "Expected one cortical id!".to_string(),
244 ));
245 }
246 MiscDataNeuronVoxelXYZPEncoder::new_box(
247 *cortical_ids.first().unwrap(),
248 *misc_data_dimensions,
249 number_channels,
250 )
251 }
252 JSONEncoderProperties::Percentage(
253 neuron_depth,
254 percentage,
255 is_signed,
256 number_dimensions,
257 ) => {
258 if cortical_ids.len() != 1 {
259 return Err(FeagiDataError::InternalError(
260 "Expected one cortical id!".to_string(),
261 ));
262 }
263 PercentageNeuronVoxelXYZPEncoder::new_box(
264 *cortical_ids.first().unwrap(),
265 *neuron_depth,
266 number_channels,
267 *percentage,
268 *is_signed,
269 *number_dimensions,
270 )
271 }
272 JSONEncoderProperties::SegmentedImageFrame(segmented_properties) => {
273 if cortical_ids.len() != 9 {
274 return Err(FeagiDataError::InternalError(
275 "Expected nine cortical ids!".to_string(),
276 ));
277 }
278 let cortical_ids: [CorticalID; 9] = (*cortical_ids).try_into().map_err(|_| {
279 FeagiDataError::InternalError("Unable to get cortical ids!".to_string())
280 })?;
281 SegmentedImageFrameNeuronVoxelXYZPEncoder::new_box(
282 cortical_ids,
283 *segmented_properties,
284 number_channels,
285 )
286 }
287 }
288 }
289
290 pub fn default_wrapped_value(&self) -> Result<WrappedIOData, FeagiDataError> {
291 match self {
292 JSONEncoderProperties::Boolean => Ok(WrappedIOData::Boolean(false)),
293 JSONEncoderProperties::CartesianPlane(image_frame_properties) => {
294 Ok(WrappedIOData::ImageFrame(
295 ImageFrame::new_from_image_frame_properties(image_frame_properties)?,
296 ))
297 }
298 JSONEncoderProperties::MiscData(misc_data_dimensions) => Ok(WrappedIOData::MiscData(
299 MiscData::new(misc_data_dimensions)?,
300 )),
301 JSONEncoderProperties::Percentage(
302 _neuron_depth,
303 _percentage,
304 is_signed,
305 number_dimensions,
306 ) => match number_dimensions {
307 PercentageChannelDimensionality::D1 => {
308 if *is_signed {
309 Ok(WrappedIOData::SignedPercentage(
310 SignedPercentage::new_from_m1_1_unchecked(0.0),
311 ))
312 } else {
313 Ok(WrappedIOData::Percentage(Percentage::new_zero()))
314 }
315 }
316 PercentageChannelDimensionality::D2 => {
317 if *is_signed {
318 Ok(WrappedIOData::SignedPercentage_2D(
319 SignedPercentage2D::new_zero(),
320 ))
321 } else {
322 Ok(WrappedIOData::Percentage_2D(Percentage2D::new_zero()))
323 }
324 }
325 PercentageChannelDimensionality::D3 => {
326 if *is_signed {
327 Ok(WrappedIOData::SignedPercentage_3D(
328 SignedPercentage3D::new_zero(),
329 ))
330 } else {
331 Ok(WrappedIOData::Percentage_3D(Percentage3D::new_zero()))
332 }
333 }
334 PercentageChannelDimensionality::D4 => {
335 if *is_signed {
336 Ok(WrappedIOData::SignedPercentage_4D(
337 SignedPercentage4D::new_zero(),
338 ))
339 } else {
340 Ok(WrappedIOData::Percentage_4D(Percentage4D::new_zero()))
341 }
342 }
343 },
344 JSONEncoderProperties::SegmentedImageFrame(segmented_properties) => {
345 Ok(WrappedIOData::SegmentedImageFrame(
346 SegmentedImageFrame::from_segmented_image_frame_properties(
347 segmented_properties,
348 )?,
349 ))
350 }
351 }
352 }
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
356pub enum JSONDecoderProperties {
357 CartesianPlane(ImageFrameProperties),
358 MiscData(MiscDataDimensions),
359 Percentage(
360 NeuronDepth,
361 PercentageNeuronPositioning,
362 bool,
363 PercentageChannelDimensionality,
364 ),
365 GazeProperties(NeuronDepth, NeuronDepth, PercentageNeuronPositioning), ImageFilteringSettings(
367 NeuronDepth,
368 NeuronDepth,
369 NeuronDepth,
370 PercentageNeuronPositioning,
371 ), }
373
374impl JSONDecoderProperties {
375 pub fn to_box_decoder(
376 &self,
377 number_channels: CorticalChannelCount,
378 cortical_ids: &[CorticalID],
379 ) -> Result<Box<dyn NeuronVoxelXYZPDecoder + Sync + Send>, FeagiDataError> {
380 match self {
381 JSONDecoderProperties::CartesianPlane(image_frame_properties) => {
382 if cortical_ids.len() != 1 {
383 return Err(FeagiDataError::InternalError(
384 "Expected one cortical id!".to_string(),
385 ));
386 }
387 crate::neuron_voxel_coding::xyzp::decoders::CartesianPlaneNeuronVoxelXYZPDecoder::new_box(
388 *cortical_ids.first().unwrap(),
389 image_frame_properties,
390 number_channels,
391 )
392 }
393 JSONDecoderProperties::MiscData(misc_data_dimensions) => {
394 if cortical_ids.len() != 1 {
395 return Err(FeagiDataError::InternalError(
396 "Expected one cortical id!".to_string(),
397 ));
398 }
399 MiscDataNeuronVoxelXYZPDecoder::new_box(
400 *cortical_ids.first().unwrap(), *misc_data_dimensions,
402 number_channels,
403 )
404 }
405 JSONDecoderProperties::Percentage(
406 neuron_depth,
407 percentage_neuron_positioning,
408 is_signed,
409 dimension_count,
410 ) => {
411 if cortical_ids.len() != 1 {
412 return Err(FeagiDataError::InternalError(
413 "Expected one cortical id!".to_string(),
414 ));
415 }
416 PercentageNeuronVoxelXYZPDecoder::new_box(
417 *cortical_ids.first().unwrap(), *neuron_depth,
419 number_channels,
420 *percentage_neuron_positioning,
421 *is_signed,
422 *dimension_count,
423 )
424 }
425 JSONDecoderProperties::GazeProperties(
426 eccentricity_neuron_depth,
427 modularity_neuron_depth,
428 percentage_neuron_positioning,
429 ) => {
430 if cortical_ids.len() != 2 {
431 return Err(FeagiDataError::InternalError(
432 "Expected two cortical ids!".to_string(),
433 ));
434 }
435 GazePropertiesNeuronVoxelXYZPDecoder::new_box(
436 *cortical_ids.first().unwrap(), *cortical_ids.get(1).unwrap(), *eccentricity_neuron_depth,
439 *modularity_neuron_depth,
440 number_channels,
441 *percentage_neuron_positioning,
442 )
443 }
444 JSONDecoderProperties::ImageFilteringSettings(
445 brightness_z_depth,
446 contrast_z_depth,
447 diff_z_depth,
448 percentage_neuron_positioning,
449 ) => {
450 if cortical_ids.len() != 3 {
451 return Err(FeagiDataError::InternalError(
452 "Expected three cortical ids for ImageFilteringSettings!".to_string(),
453 ));
454 }
455 ImageFilteringSettingsNeuronVoxelXYZPDecoder::new_box(
456 *cortical_ids.first().unwrap(), *cortical_ids.get(1).unwrap(), *cortical_ids.get(2).unwrap(), *brightness_z_depth,
460 *contrast_z_depth,
461 *diff_z_depth,
462 number_channels,
463 *percentage_neuron_positioning,
464 )
465 }
466 }
467 }
468
469 pub fn default_wrapped_value(&self) -> Result<WrappedIOData, FeagiDataError> {
470 match self {
471 JSONDecoderProperties::CartesianPlane(image_frame_properties) => {
472 Ok(WrappedIOData::ImageFrame(
473 ImageFrame::new_from_image_frame_properties(image_frame_properties)?,
474 ))
475 }
476 JSONDecoderProperties::MiscData(misc_data_dimensions) => Ok(WrappedIOData::MiscData(
477 MiscData::new(misc_data_dimensions)?,
478 )),
479 JSONDecoderProperties::Percentage(
480 _neuron_depth,
481 _percentage_neuron_positioning,
482 is_signed,
483 number_dimensions,
484 ) => match number_dimensions {
485 PercentageChannelDimensionality::D1 => {
486 if *is_signed {
487 Ok(WrappedIOData::SignedPercentage(
488 SignedPercentage::new_from_m1_1_unchecked(0.0),
489 ))
490 } else {
491 Ok(WrappedIOData::Percentage(Percentage::new_zero()))
492 }
493 }
494 PercentageChannelDimensionality::D2 => {
495 if *is_signed {
496 Ok(WrappedIOData::SignedPercentage_2D(
497 SignedPercentage2D::new_zero(),
498 ))
499 } else {
500 Ok(WrappedIOData::Percentage_2D(Percentage2D::new_zero()))
501 }
502 }
503 PercentageChannelDimensionality::D3 => {
504 if *is_signed {
505 Ok(WrappedIOData::SignedPercentage_3D(
506 SignedPercentage3D::new_zero(),
507 ))
508 } else {
509 Ok(WrappedIOData::Percentage_3D(Percentage3D::new_zero()))
510 }
511 }
512 PercentageChannelDimensionality::D4 => {
513 if *is_signed {
514 Ok(WrappedIOData::SignedPercentage_4D(
515 SignedPercentage4D::new_zero(),
516 ))
517 } else {
518 Ok(WrappedIOData::Percentage_4D(Percentage4D::new_zero()))
519 }
520 }
521 },
522 JSONDecoderProperties::GazeProperties(
523 _eccentricity,
524 _modularity,
525 _percentage_neuron_positioning,
526 ) => Ok(WrappedIOData::GazeProperties(
527 GazeProperties::create_default_centered(),
528 )),
529 JSONDecoderProperties::ImageFilteringSettings(
530 _brightness,
531 _contrast,
532 _diff,
533 _percentage_neuron_positioning,
534 ) => Ok(WrappedIOData::ImageFilteringSettings(
535 ImageFilteringSettings::default(),
536 )),
537 }
538 }
539}
540
541pub type JSONDeviceProperties = HashMap<String, JSONDevicePropertyValue>;
548
549#[derive(Serialize, Deserialize)]
552#[serde(tag = "type", content = "value")]
553#[derive(Debug, Clone)]
554pub enum JSONDevicePropertyValue {
555 String(String),
556 Integer(i32),
557 Float(f32),
558 Dictionary(JSONDeviceProperties),
559}
560
561