pub fn create_continual_task(
task_id: String,
task_type: TaskType,
data: Array2<f64>,
labels: Array1<usize>,
train_ratio: f64,
) -> ContinualTaskExpand 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}