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