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