create_continual_task

Function create_continual_task 

Source
pub fn create_continual_task(
    task_id: String,
    task_type: TaskType,
    data: Array2<f64>,
    labels: Array1<usize>,
    train_ratio: f64,
) -> ContinualTask
Expand description

Helper function to create a simple continual task

Examples found in repository?
examples/quantum_continual_learning.rs (lines 622-628)
579fn generate_diverse_tasks(
580    num_tasks: usize,
581    samples_per_task: usize,
582    feature_dim: usize,
583) -> Vec<ContinualTask> {
584    let mut tasks = Vec::new();
585
586    for i in 0..num_tasks {
587        let task_type = match i % 3 {
588            0 => "classification",
589            1 => "pattern_recognition",
590            _ => "feature_detection",
591        };
592
593        // Generate task-specific data with different distributions
594        let data = Array2::from_shape_fn((samples_per_task, feature_dim), |(row, col)| {
595            match i % 3 {
596                0 => {
597                    // Gaussian-like distribution
598                    let center = i as f64 * 0.2;
599                    0.2f64.mul_add(fastrand::f64() - 0.5, center)
600                }
601                1 => {
602                    // Sinusoidal pattern
603                    let freq = (i + 1) as f64;
604                    0.3f64.mul_add(
605                        (freq * row as f64).mul_add(0.1, col as f64 * 0.2).sin(),
606                        0.5,
607                    )
608                }
609                _ => {
610                    // Random with task-specific bias
611                    let bias = i as f64 * 0.1;
612                    fastrand::f64().mul_add(0.6, bias)
613                }
614            }
615        });
616
617        let labels = Array1::from_shape_fn(samples_per_task, |row| {
618            let features_sum = data.row(row).sum();
619            usize::from(features_sum > feature_dim as f64 * 0.5)
620        });
621
622        let task = create_continual_task(
623            format!("{task_type}_{i}"),
624            TaskType::Classification { num_classes: 2 },
625            data,
626            labels,
627            0.8,
628        );
629
630        tasks.push(task);
631    }
632
633    tasks
634}
635
636/// Generate related tasks for transfer learning
637fn generate_related_tasks(
638    num_tasks: usize,
639    samples_per_task: usize,
640    feature_dim: usize,
641) -> Vec<ContinualTask> {
642    let mut tasks = Vec::new();
643    let base_pattern = Array1::from_shape_fn(feature_dim, |i| (i as f64 * 0.3).sin());
644
645    for i in 0..num_tasks {
646        // Each task is a variation of the base pattern
647        let variation_strength = (i as f64).mul_add(0.1, 0.1);
648
649        let data = Array2::from_shape_fn((samples_per_task, feature_dim), |(row, col)| {
650            let base_value = base_pattern[col];
651            let variation = variation_strength * (row as f64).mul_add(0.05, col as f64 * 0.1).cos();
652            let noise = 0.05 * (fastrand::f64() - 0.5);
653            (base_value + variation + noise).max(0.0).min(1.0)
654        });
655
656        let labels = Array1::from_shape_fn(samples_per_task, |row| {
657            let correlation = data
658                .row(row)
659                .iter()
660                .zip(base_pattern.iter())
661                .map(|(&x, &y)| x * y)
662                .sum::<f64>();
663            usize::from(correlation > 0.5)
664        });
665
666        let task = create_continual_task(
667            format!("related_task_{i}"),
668            TaskType::Classification { num_classes: 2 },
669            data,
670            labels,
671            0.8,
672        );
673
674        tasks.push(task);
675    }
676
677    tasks
678}
679
680/// Generate tasks with varying complexity
681fn generate_varying_complexity_tasks(
682    num_tasks: usize,
683    samples_per_task: usize,
684    feature_dim: usize,
685) -> Vec<ContinualTask> {
686    let mut tasks = Vec::new();
687
688    for i in 0..num_tasks {
689        let complexity = (i + 1) as f64; // Increasing complexity
690
691        let data = Array2::from_shape_fn((samples_per_task, feature_dim), |(row, col)| {
692            // More complex decision boundaries for later tasks
693            let x = row as f64 / samples_per_task as f64;
694            let y = col as f64 / feature_dim as f64;
695
696            let value = match i {
697                0 => {
698                    if x > 0.5 {
699                        1.0
700                    } else {
701                        0.0
702                    }
703                } // Simple linear
704                1 => {
705                    if x.mul_add(x, y * y) > 0.25 {
706                        1.0
707                    } else {
708                        0.0
709                    }
710                } // Circular
711                2 => {
712                    if (x * 4.0).sin() * (y * 4.0).cos() > 0.0 {
713                        1.0
714                    } else {
715                        0.0
716                    }
717                } // Sinusoidal
718                _ => {
719                    // Very complex pattern
720                    let pattern = (x * 8.0)
721                        .sin()
722                        .mul_add((y * 8.0).cos(), (x * y * 16.0).sin());
723                    if pattern > 0.0 {
724                        1.0
725                    } else {
726                        0.0
727                    }
728                }
729            };
730
731            0.1f64.mul_add(fastrand::f64() - 0.5, value) // Add noise
732        });
733
734        let labels = Array1::from_shape_fn(samples_per_task, |row| {
735            // Complex labeling based on multiple features
736            let features = data.row(row);
737            let decision_value = features
738                .iter()
739                .enumerate()
740                .map(|(j, &x)| x * (j as f64 * complexity).mul_add(0.1, 1.0))
741                .sum::<f64>();
742
743            usize::from(decision_value > feature_dim as f64 * 0.5)
744        });
745
746        let task = create_continual_task(
747            format!("complex_task_{i}"),
748            TaskType::Classification { num_classes: 2 },
749            data,
750            labels,
751            0.8,
752        );
753
754        tasks.push(task);
755    }
756
757    tasks
758}
759
760/// Generate challenging task sequence
761fn generate_challenging_sequence(
762    num_tasks: usize,
763    samples_per_task: usize,
764    feature_dim: usize,
765) -> Vec<ContinualTask> {
766    let mut tasks = Vec::new();
767
768    for i in 0..num_tasks {
769        // Alternating between different types of challenges
770        let challenge_type = i % 4;
771
772        let data = Array2::from_shape_fn((samples_per_task, feature_dim), |(row, col)| {
773            match challenge_type {
774                0 => {
775                    // High-frequency patterns
776                    let freq = (i as f64).mul_add(2.0, 10.0);
777                    0.4f64.mul_add((freq * row as f64 * 0.01).sin(), 0.5)
778                }
779                1 => {
780                    // Overlapping distributions
781                    let center1 = (i as f64).mul_add(0.05, 0.3);
782                    let center2 = (i as f64).mul_add(-0.05, 0.7);
783                    if row % 2 == 0 {
784                        0.15f64.mul_add(fastrand::f64() - 0.5, center1)
785                    } else {
786                        0.15f64.mul_add(fastrand::f64() - 0.5, center2)
787                    }
788                }
789                2 => {
790                    // Non-linear patterns
791                    let x = row as f64 / samples_per_task as f64;
792                    let y = col as f64 / feature_dim as f64;
793                    let pattern = (i as f64).mul_add(0.1, x.mul_add(x, -(y * y))).tanh();
794                    0.3f64.mul_add(pattern, 0.5)
795                }
796                _ => {
797                    // Sparse patterns
798                    if fastrand::f64() < 0.2 {
799                        0.2f64.mul_add(fastrand::f64(), 0.8)
800                    } else {
801                        0.1 * fastrand::f64()
802                    }
803                }
804            }
805        });
806
807        let labels = Array1::from_shape_fn(samples_per_task, |row| {
808            let features = data.row(row);
809            match challenge_type {
810                0 => usize::from(features.sum() > feature_dim as f64 * 0.5),
811                1 => usize::from(features[0] > 0.5),
812                2 => usize::from(
813                    features
814                        .iter()
815                        .enumerate()
816                        .map(|(j, &x)| x * (j as f64 + 1.0))
817                        .sum::<f64>()
818                        > 2.0,
819                ),
820                _ => usize::from(features.iter().filter(|&&x| x > 0.5).count() > feature_dim / 2),
821            }
822        });
823
824        let task = create_continual_task(
825            format!("challenge_{i}"),
826            TaskType::Classification { num_classes: 2 },
827            data,
828            labels,
829            0.8,
830        );
831
832        tasks.push(task);
833    }
834
835    tasks
836}
837
838/// Generate tasks with increasing difficulty
839fn generate_increasing_difficulty_tasks(
840    num_tasks: usize,
841    samples_per_task: usize,
842    feature_dim: usize,
843) -> Vec<ContinualTask> {
844    let mut tasks = Vec::new();
845
846    for i in 0..num_tasks {
847        let difficulty = (i + 1) as f64;
848        let noise_level = 0.05 + difficulty * 0.02;
849        let pattern_complexity = 1.0 + difficulty * 0.5;
850
851        let data = Array2::from_shape_fn((samples_per_task, feature_dim), |(row, col)| {
852            let x = row as f64 / samples_per_task as f64;
853            let y = col as f64 / feature_dim as f64;
854
855            // Increasingly complex patterns
856            let base_pattern = (x * pattern_complexity * std::f64::consts::PI).sin()
857                * (y * pattern_complexity * std::f64::consts::PI).cos();
858
859            let pattern_value = 0.3f64.mul_add(base_pattern, 0.5);
860            let noise = noise_level * (fastrand::f64() - 0.5);
861
862            (pattern_value + noise).max(0.0).min(1.0)
863        });
864
865        let labels = Array1::from_shape_fn(samples_per_task, |row| {
866            let features = data.row(row);
867
868            // Increasingly complex decision boundaries
869            let decision_value = features
870                .iter()
871                .enumerate()
872                .map(|(j, &x)| {
873                    let weight = 1.0 + (j as f64 * difficulty * 0.1).sin();
874                    x * weight
875                })
876                .sum::<f64>();
877
878            let threshold = feature_dim as f64 * 0.5 * (1.0 + difficulty * 0.1);
879            usize::from(decision_value > threshold)
880        });
881
882        let task = create_continual_task(
883            format!("difficulty_{}", i + 1),
884            TaskType::Classification { num_classes: 2 },
885            data,
886            labels,
887            0.8,
888        );
889
890        tasks.push(task);
891    }
892
893    tasks
894}