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 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}