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