Skip to main content

quantrs2_ml/
tutorials.rs

1//! Quantum Machine Learning Tutorials for QuantRS2-ML
2//!
3//! This module provides comprehensive, step-by-step tutorials for learning
4//! quantum machine learning concepts and practical implementation with QuantRS2.
5
6use crate::classical_ml_integration::{HybridPipelineManager, PipelineConfig};
7use crate::domain_templates::{Domain, DomainTemplateManager, TemplateConfig};
8use crate::error::{MLError, Result};
9use crate::keras_api::{
10    ActivationFunction, Dense, LossFunction, MetricType, OptimizerType, QuantumAnsatzType,
11    QuantumDense, Sequential,
12};
13use crate::model_zoo::{ModelZoo, QuantumModel};
14use crate::optimization::{OptimizationMethod, Optimizer};
15use crate::pytorch_api::{
16    ActivationType as PyTorchActivationType, QuantumLinear, QuantumModule, QuantumSequential,
17};
18use crate::qnn::{QNNBuilder, QuantumNeuralNetwork};
19use crate::qsvm::{FeatureMapType, QSVMParams, QSVM};
20use crate::variational::{VariationalAlgorithm, VariationalCircuit};
21use quantrs2_circuit::prelude::*;
22use quantrs2_core::prelude::*;
23use scirs2_core::ndarray::{Array1, Array2, ArrayD, Axis};
24use serde::{Deserialize, Serialize};
25use std::collections::HashMap;
26
27/// Tutorial manager for quantum ML education
28pub struct TutorialManager {
29    /// Available tutorials by category
30    tutorials: HashMap<TutorialCategory, Vec<Tutorial>>,
31    /// Interactive exercises
32    exercises: HashMap<String, Exercise>,
33    /// User progress tracking
34    progress: HashMap<String, TutorialProgress>,
35}
36
37/// Tutorial categories
38#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
39pub enum TutorialCategory {
40    /// Basic quantum computing concepts
41    Fundamentals,
42    /// Quantum neural networks
43    QuantumNeuralNetworks,
44    /// Quantum machine learning algorithms
45    Algorithms,
46    /// Variational quantum algorithms
47    Variational,
48    /// Quantum optimization
49    Optimization,
50    /// Hybrid quantum-classical methods
51    Hybrid,
52    /// Industry applications
53    Applications,
54    /// Advanced topics
55    Advanced,
56}
57
58/// Tutorial definition
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct Tutorial {
61    /// Tutorial ID
62    pub id: String,
63    /// Tutorial title
64    pub title: String,
65    /// Tutorial description
66    pub description: String,
67    /// Category
68    pub category: TutorialCategory,
69    /// Difficulty level
70    pub difficulty: DifficultyLevel,
71    /// Prerequisites
72    pub prerequisites: Vec<String>,
73    /// Learning objectives
74    pub learning_objectives: Vec<String>,
75    /// Estimated duration (minutes)
76    pub duration_minutes: usize,
77    /// Tutorial sections
78    pub sections: Vec<TutorialSection>,
79    /// Related exercises
80    pub exercises: Vec<String>,
81}
82
83/// Difficulty levels
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub enum DifficultyLevel {
86    /// Beginner level
87    Beginner,
88    /// Intermediate level
89    Intermediate,
90    /// Advanced level
91    Advanced,
92    /// Expert level
93    Expert,
94}
95
96/// Tutorial section
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct TutorialSection {
99    /// Section title
100    pub title: String,
101    /// Section content
102    pub content: String,
103    /// Code examples
104    pub code_examples: Vec<CodeExample>,
105    /// Interactive elements
106    pub interactive_elements: Vec<InteractiveElement>,
107    /// Key concepts
108    pub key_concepts: Vec<String>,
109}
110
111/// Code example
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct CodeExample {
114    /// Example title
115    pub title: String,
116    /// Example description
117    pub description: String,
118    /// Code content
119    pub code: String,
120    /// Expected output
121    pub expected_output: Option<String>,
122    /// Explanation
123    pub explanation: String,
124}
125
126/// Interactive element
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct InteractiveElement {
129    /// Element type
130    pub element_type: InteractiveType,
131    /// Element title
132    pub title: String,
133    /// Instructions
134    pub instructions: String,
135    /// Parameters
136    pub parameters: HashMap<String, String>,
137}
138
139/// Interactive element types
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub enum InteractiveType {
142    /// Visualization
143    Visualization,
144    /// Parameter adjustment
145    ParameterTuning,
146    /// Code completion
147    CodeCompletion,
148    /// Quiz question
149    Quiz,
150    /// Experiment
151    Experiment,
152}
153
154/// Exercise definition
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct Exercise {
157    /// Exercise ID
158    pub id: String,
159    /// Exercise title
160    pub title: String,
161    /// Exercise description
162    pub description: String,
163    /// Exercise type
164    pub exercise_type: ExerciseType,
165    /// Instructions
166    pub instructions: Vec<String>,
167    /// Starter code
168    pub starter_code: Option<String>,
169    /// Solution code
170    pub solution_code: String,
171    /// Test cases
172    pub test_cases: Vec<TestCase>,
173    /// Hints
174    pub hints: Vec<String>,
175}
176
177/// Exercise types
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub enum ExerciseType {
180    /// Coding exercise
181    Coding,
182    /// Circuit design
183    CircuitDesign,
184    /// Parameter optimization
185    ParameterOptimization,
186    /// Algorithm implementation
187    AlgorithmImplementation,
188    /// Data analysis
189    DataAnalysis,
190}
191
192/// Test case for exercises
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct TestCase {
195    /// Test description
196    pub description: String,
197    /// Input data
198    pub input: String,
199    /// Expected output
200    pub expected_output: String,
201    /// Points awarded
202    pub points: usize,
203}
204
205/// User progress tracking
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct TutorialProgress {
208    /// User ID
209    pub user_id: String,
210    /// Completed tutorials
211    pub completed_tutorials: Vec<String>,
212    /// Completed exercises
213    pub completed_exercises: Vec<String>,
214    /// Current tutorial
215    pub current_tutorial: Option<String>,
216    /// Progress scores
217    pub scores: HashMap<String, f64>,
218    /// Time spent (minutes)
219    pub time_spent: HashMap<String, usize>,
220}
221
222impl TutorialManager {
223    /// Create new tutorial manager
224    pub fn new() -> Self {
225        let mut manager = Self {
226            tutorials: HashMap::new(),
227            exercises: HashMap::new(),
228            progress: HashMap::new(),
229        };
230        manager.register_tutorials();
231        manager.register_exercises();
232        manager
233    }
234
235    /// Register all tutorials
236    fn register_tutorials(&mut self) {
237        self.register_fundamentals_tutorials();
238        self.register_qnn_tutorials();
239        self.register_algorithm_tutorials();
240        self.register_variational_tutorials();
241        self.register_optimization_tutorials();
242        self.register_hybrid_tutorials();
243        self.register_application_tutorials();
244        self.register_advanced_tutorials();
245    }
246
247    /// Register fundamentals tutorials
248    fn register_fundamentals_tutorials(&mut self) {
249        let mut tutorials = Vec::new();
250
251        // Introduction to Quantum Computing
252        tutorials.push(Tutorial {
253            id: "qc_intro".to_string(),
254            title: "Introduction to Quantum Computing".to_string(),
255            description: "Learn the fundamental concepts of quantum computing: qubits, superposition, entanglement, and quantum gates.".to_string(),
256            category: TutorialCategory::Fundamentals,
257            difficulty: DifficultyLevel::Beginner,
258            prerequisites: vec!["Basic linear algebra".to_string()],
259            learning_objectives: vec![
260                "Understand what qubits are and how they differ from classical bits".to_string(),
261                "Learn about superposition and quantum state representation".to_string(),
262                "Understand entanglement and its role in quantum computing".to_string(),
263                "Familiarize with basic quantum gates and circuits".to_string(),
264            ],
265            duration_minutes: 45,
266            sections: vec![
267                TutorialSection {
268                    title: "What are Qubits?".to_string(),
269                    content: "A qubit is the fundamental unit of quantum information. Unlike classical bits that can only be 0 or 1, qubits can exist in a superposition of both states simultaneously.".to_string(),
270                    code_examples: vec![
271                        CodeExample {
272                            title: "Creating a Qubit".to_string(),
273                            description: "Create a simple qubit in QuantRS2".to_string(),
274                            code: r#"
275use quantrs2_core::prelude::*;
276
277// Create a qubit in |0⟩ state
278let qubit = QubitState::new(Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0));
279
280// Create a qubit in superposition |+⟩ = (|0⟩ + |1⟩)/√2
281let superposition = QubitState::new(
282    Complex64::new(1.0/2.0_f64.sqrt(), 0.0),
283    Complex64::new(1.0/2.0_f64.sqrt(), 0.0)
284);
285"#.to_string(),
286                            expected_output: Some("Qubit states created successfully".to_string()),
287                            explanation: "This example shows how to create qubits in different states using QuantRS2.".to_string(),
288                        }
289                    ],
290                    interactive_elements: vec![
291                        InteractiveElement {
292                            element_type: InteractiveType::Visualization,
293                            title: "Bloch Sphere Visualization".to_string(),
294                            instructions: "Visualize different qubit states on the Bloch sphere".to_string(),
295                            parameters: HashMap::new(),
296                        }
297                    ],
298                    key_concepts: vec![
299                        "Qubits can be in superposition".to_string(),
300                        "Quantum states are represented by complex amplitudes".to_string(),
301                        "Measurement collapses the superposition".to_string(),
302                    ],
303                },
304                TutorialSection {
305                    title: "Quantum Gates".to_string(),
306                    content: "Quantum gates are the building blocks of quantum circuits. They perform unitary operations on qubits.".to_string(),
307                    code_examples: vec![
308                        CodeExample {
309                            title: "Basic Quantum Gates".to_string(),
310                            description: "Apply basic quantum gates using QuantRS2".to_string(),
311                            code: r#"
312use quantrs2_circuit::prelude::*;
313
314// Create a quantum circuit
315let mut circuit = QuantumCircuit::new(2);
316
317// Apply Hadamard gate to create superposition
318circuit.h(0);
319
320// Apply CNOT gate to create entanglement
321circuit.cnot(0, 1);
322
323// Apply Pauli-X gate (bit flip)
324circuit.x(1);
325
326// Apply Pauli-Z gate (phase flip)
327circuit.z(0);
328"#.to_string(),
329                            expected_output: Some("Circuit with basic gates created".to_string()),
330                            explanation: "This demonstrates the most common quantum gates and how to use them in circuits.".to_string(),
331                        }
332                    ],
333                    interactive_elements: vec![
334                        InteractiveElement {
335                            element_type: InteractiveType::Experiment,
336                            title: "Gate Effect Explorer".to_string(),
337                            instructions: "Experiment with different gates and see their effect on qubit states".to_string(),
338                            parameters: HashMap::new(),
339                        }
340                    ],
341                    key_concepts: vec![
342                        "Quantum gates are unitary operations".to_string(),
343                        "Hadamard gate creates superposition".to_string(),
344                        "CNOT gate creates entanglement".to_string(),
345                        "Pauli gates perform rotations".to_string(),
346                    ],
347                },
348            ],
349            exercises: vec!["qc_basic_gates".to_string(), "qc_bell_state".to_string()],
350        });
351
352        // Quantum Circuits and Measurement
353        tutorials.push(Tutorial {
354            id: "qc_circuits".to_string(),
355            title: "Quantum Circuits and Measurement".to_string(),
356            description: "Learn how to construct quantum circuits and understand quantum measurement.".to_string(),
357            category: TutorialCategory::Fundamentals,
358            difficulty: DifficultyLevel::Beginner,
359            prerequisites: vec!["qc_intro".to_string()],
360            learning_objectives: vec![
361                "Build quantum circuits with multiple qubits".to_string(),
362                "Understand quantum measurement and Born rule".to_string(),
363                "Learn about quantum circuit simulation".to_string(),
364                "Implement basic quantum algorithms".to_string(),
365            ],
366            duration_minutes: 60,
367            sections: vec![
368                TutorialSection {
369                    title: "Building Quantum Circuits".to_string(),
370                    content: "Quantum circuits are composed of quantum gates applied to qubits in a specific sequence.".to_string(),
371                    code_examples: vec![
372                        CodeExample {
373                            title: "Multi-Qubit Circuit".to_string(),
374                            description: "Create a circuit with multiple qubits and gates".to_string(),
375                            code: r#"
376use quantrs2_circuit::prelude::*;
377
378// Create a 3-qubit circuit
379let mut circuit = QuantumCircuit::new(3);
380
381// Create GHZ state: (|000⟩ + |111⟩)/√2
382circuit.h(0);           // Put first qubit in superposition
383circuit.cnot(0, 1);     // Entangle first and second qubits
384circuit.cnot(1, 2);     // Entangle second and third qubits
385
386// Add measurement
387circuit.measure_all();
388"#.to_string(),
389                            expected_output: Some("GHZ state circuit created".to_string()),
390                            explanation: "This creates a maximally entangled 3-qubit state called the GHZ state.".to_string(),
391                        }
392                    ],
393                    interactive_elements: vec![],
394                    key_concepts: vec![
395                        "Quantum circuits process quantum information".to_string(),
396                        "Gates are applied sequentially".to_string(),
397                        "Multi-qubit entanglement is possible".to_string(),
398                    ],
399                },
400            ],
401            exercises: vec!["qc_ghz_state".to_string()],
402        });
403
404        self.tutorials
405            .insert(TutorialCategory::Fundamentals, tutorials);
406    }
407
408    /// Register quantum neural networks tutorials
409    fn register_qnn_tutorials(&mut self) {
410        let mut tutorials = Vec::new();
411
412        // Introduction to Quantum Neural Networks
413        tutorials.push(Tutorial {
414            id: "qnn_intro".to_string(),
415            title: "Introduction to Quantum Neural Networks".to_string(),
416            description: "Learn the basics of quantum neural networks and how they differ from classical neural networks.".to_string(),
417            category: TutorialCategory::QuantumNeuralNetworks,
418            difficulty: DifficultyLevel::Intermediate,
419            prerequisites: vec!["qc_circuits".to_string(), "Basic neural networks".to_string()],
420            learning_objectives: vec![
421                "Understand quantum neural network architecture".to_string(),
422                "Learn about parameterized quantum circuits".to_string(),
423                "Implement a simple QNN for classification".to_string(),
424                "Compare QNN vs classical NN performance".to_string(),
425            ],
426            duration_minutes: 90,
427            sections: vec![
428                TutorialSection {
429                    title: "QNN Architecture".to_string(),
430                    content: "Quantum Neural Networks use parameterized quantum circuits to process and learn from data.".to_string(),
431                    code_examples: vec![
432                        CodeExample {
433                            title: "Simple QNN".to_string(),
434                            description: "Create a basic quantum neural network".to_string(),
435                            code: r#"
436use quantrs2_ml::prelude::*;
437
438// Create QNN builder
439let mut qnn_builder = QNNBuilder::new(4) // 4 qubits
440    .add_layer(QNNLayer::Embedding { rotation_gates: vec!["RY", "RZ"] })
441    .add_layer(QNNLayer::Entangling { entangling_gate: "CNOT" })
442    .add_layer(QNNLayer::Parameterized {
443        gates: vec!["RY", "RZ"],
444        num_parameters: 8
445    });
446
447// Build the QNN
448let mut qnn = qnn_builder.build()?;
449
450// Train on sample data
451let X = Array2::random((100, 4), Uniform::new(-1.0, 1.0)?);
452let y = Array1::from_vec(vec![0.0; 50].into_iter().chain(vec![1.0; 50]).collect());
453
454qnn.train(&X.into_dyn(), &y.into_dyn().insert_axis(Axis(1)))?;
455"#.to_string(),
456                            expected_output: Some("QNN trained successfully".to_string()),
457                            explanation: "This creates a parameterized quantum circuit that can learn from classical data.".to_string(),
458                        }
459                    ],
460                    interactive_elements: vec![
461                        InteractiveElement {
462                            element_type: InteractiveType::ParameterTuning,
463                            title: "QNN Hyperparameter Tuning".to_string(),
464                            instructions: "Adjust QNN parameters and observe training performance".to_string(),
465                            parameters: HashMap::new(),
466                        }
467                    ],
468                    key_concepts: vec![
469                        "QNNs use parameterized quantum circuits".to_string(),
470                        "Data encoding is crucial for QNN performance".to_string(),
471                        "Entangling layers create quantum correlations".to_string(),
472                    ],
473                },
474            ],
475            exercises: vec!["qnn_classification".to_string()],
476        });
477
478        self.tutorials
479            .insert(TutorialCategory::QuantumNeuralNetworks, tutorials);
480    }
481
482    /// Register algorithm tutorials
483    fn register_algorithm_tutorials(&mut self) {
484        let mut tutorials = Vec::new();
485
486        // Quantum Support Vector Machines
487        tutorials.push(Tutorial {
488            id: "qsvm_tutorial".to_string(),
489            title: "Quantum Support Vector Machines".to_string(),
490            description: "Learn how to implement and use Quantum Support Vector Machines for classification tasks.".to_string(),
491            category: TutorialCategory::Algorithms,
492            difficulty: DifficultyLevel::Intermediate,
493            prerequisites: vec!["qnn_intro".to_string(), "Classical SVM knowledge".to_string()],
494            learning_objectives: vec![
495                "Understand quantum kernel methods".to_string(),
496                "Implement QSVM for binary classification".to_string(),
497                "Compare quantum vs classical kernels".to_string(),
498                "Optimize QSVM hyperparameters".to_string(),
499            ],
500            duration_minutes: 75,
501            sections: vec![
502                TutorialSection {
503                    title: "Quantum Kernels".to_string(),
504                    content: "Quantum kernels map classical data to quantum feature spaces where linear separation may be easier.".to_string(),
505                    code_examples: vec![
506                        CodeExample {
507                            title: "QSVM Implementation".to_string(),
508                            description: "Create and train a Quantum SVM".to_string(),
509                            code: r#"
510use quantrs2_ml::prelude::*;
511
512// Create QSVM with ZZ feature map
513let qsvm_params = QSVMParams {
514    feature_map: FeatureMapType::ZZFeatureMap,
515    num_qubits: 4,
516    depth: 2,
517    entanglement: "linear".to_string(),
518    alpha: 1.0,
519};
520
521let mut qsvm = QSVM::new(qsvm_params)?;
522
523// Generate sample data
524let X = Array2::random((100, 4), Uniform::new(-1.0, 1.0)?);
525let y = Array1::from_vec((0..100).map(|i| if i < 50 { -1.0 } else { 1.0 }).collect());
526
527// Train the QSVM
528qsvm.fit(&X.into_dyn(), &y.into_dyn())?;
529
530// Make predictions
531let predictions = qsvm.predict(&X.into_dyn())?;
532"#.to_string(),
533                            expected_output: Some("QSVM trained and predictions made".to_string()),
534                            explanation: "This demonstrates training a QSVM with quantum kernels for classification.".to_string(),
535                        }
536                    ],
537                    interactive_elements: vec![],
538                    key_concepts: vec![
539                        "Quantum kernels exploit quantum feature spaces".to_string(),
540                        "Feature maps encode classical data into quantum states".to_string(),
541                        "Quantum advantage possible in high-dimensional spaces".to_string(),
542                    ],
543                },
544            ],
545            exercises: vec!["qsvm_iris".to_string()],
546        });
547
548        self.tutorials
549            .insert(TutorialCategory::Algorithms, tutorials);
550    }
551
552    /// Register variational algorithm tutorials
553    fn register_variational_tutorials(&mut self) {
554        let mut tutorials = Vec::new();
555
556        // Variational Quantum Eigensolver (VQE)
557        tutorials.push(Tutorial {
558            id: "vqe_tutorial".to_string(),
559            title: "Variational Quantum Eigensolver (VQE)".to_string(),
560            description: "Learn to implement VQE for finding ground state energies of quantum systems.".to_string(),
561            category: TutorialCategory::Variational,
562            difficulty: DifficultyLevel::Advanced,
563            prerequisites: vec!["qnn_intro".to_string(), "Quantum chemistry basics".to_string()],
564            learning_objectives: vec![
565                "Understand the VQE algorithm".to_string(),
566                "Implement VQE for small molecules".to_string(),
567                "Learn about ansatz design".to_string(),
568                "Optimize VQE parameters".to_string(),
569            ],
570            duration_minutes: 120,
571            sections: vec![
572                TutorialSection {
573                    title: "VQE Algorithm".to_string(),
574                    content: "VQE combines quantum circuits with classical optimization to find ground state energies.".to_string(),
575                    code_examples: vec![
576                        CodeExample {
577                            title: "VQE for H2 Molecule".to_string(),
578                            description: "Implement VQE to find H2 ground state energy".to_string(),
579                            code: r#"
580use quantrs2_ml::prelude::*;
581
582// Create VQE for H2 molecule
583let mut vqe = VariationalAlgorithm::new(2) // 2 qubits for H2
584    .with_ansatz("UCCSD") // Unitary Coupled Cluster ansatz
585    .with_optimizer(OptimizationMethod::LBFGS)
586    .build()?;
587
588// Define H2 Hamiltonian (simplified)
589let hamiltonian = Array2::from_shape_vec(
590    (4, 4),
591    vec![
592        -1.05, 0.0, 0.0, 0.0,
593        0.0, -0.4, -0.2, 0.0,
594        0.0, -0.2, -0.4, 0.0,
595        0.0, 0.0, 0.0, -1.05,
596    ]
597)?;
598
599// Run VQE optimization
600let result = vqe.minimize(&hamiltonian)?;
601println!("Ground state energy: {:.6}", result.energy);
602"#.to_string(),
603                            expected_output: Some("Ground state energy: -1.857275".to_string()),
604                            explanation: "This implements VQE to find the ground state energy of a hydrogen molecule.".to_string(),
605                        }
606                    ],
607                    interactive_elements: vec![
608                        InteractiveElement {
609                            element_type: InteractiveType::Visualization,
610                            title: "VQE Convergence Plot".to_string(),
611                            instructions: "Visualize how VQE energy converges during optimization".to_string(),
612                            parameters: HashMap::new(),
613                        }
614                    ],
615                    key_concepts: vec![
616                        "VQE finds ground states variationally".to_string(),
617                        "Ansatz choice affects performance".to_string(),
618                        "Classical optimizer minimizes expectation value".to_string(),
619                    ],
620                },
621            ],
622            exercises: vec!["vqe_lih".to_string()],
623        });
624
625        self.tutorials
626            .insert(TutorialCategory::Variational, tutorials);
627    }
628
629    /// Register optimization tutorials
630    fn register_optimization_tutorials(&mut self) {
631        let mut tutorials = Vec::new();
632
633        // Quantum Approximate Optimization Algorithm (QAOA)
634        tutorials.push(Tutorial {
635            id: "qaoa_tutorial".to_string(),
636            title: "Quantum Approximate Optimization Algorithm (QAOA)".to_string(),
637            description: "Learn QAOA for solving combinatorial optimization problems.".to_string(),
638            category: TutorialCategory::Optimization,
639            difficulty: DifficultyLevel::Advanced,
640            prerequisites: vec![
641                "vqe_tutorial".to_string(),
642                "Combinatorial optimization".to_string(),
643            ],
644            learning_objectives: vec![
645                "Understand QAOA algorithm structure".to_string(),
646                "Implement QAOA for MaxCut problem".to_string(),
647                "Learn about QAOA parameter optimization".to_string(),
648                "Apply QAOA to real optimization problems".to_string(),
649            ],
650            duration_minutes: 100,
651            sections: vec![TutorialSection {
652                title: "QAOA for MaxCut".to_string(),
653                content: "QAOA can solve graph partitioning problems like MaxCut approximately."
654                    .to_string(),
655                code_examples: vec![CodeExample {
656                    title: "MaxCut with QAOA".to_string(),
657                    description: "Solve MaxCut problem using QAOA".to_string(),
658                    code: r#"
659use quantrs2_ml::prelude::*;
660
661// Define a simple graph (adjacency matrix)
662let graph = Array2::from_shape_vec(
663    (4, 4),
664    vec![
665        0.0, 1.0, 1.0, 0.0,
666        1.0, 0.0, 1.0, 1.0,
667        1.0, 1.0, 0.0, 1.0,
668        0.0, 1.0, 1.0, 0.0,
669    ]
670)?;
671
672// Create QAOA instance
673let mut qaoa = QuantumMLQUBO::new(4, 2)?; // 4 qubits, 2 layers
674
675// Convert MaxCut to QUBO formulation
676let qubo_matrix = qaoa.maxcut_to_qubo(&graph)?;
677
678// Solve with quantum annealing
679let annealing_params = AnnealingParams {
680    num_reads: 1000,
681    annealing_time: 20.0,
682    temperature: 0.1,
683};
684
685let result = qaoa.solve_qubo(&qubo_matrix, annealing_params)?;
686println!("Best cut value: {}", result.energy);
687println!("Optimal partition: {:?}", result.solution);
688"#
689                    .to_string(),
690                    expected_output: Some(
691                        "Best cut value: 4\nOptimal partition: [0, 1, 0, 1]".to_string(),
692                    ),
693                    explanation:
694                        "This solves a graph partitioning problem using quantum optimization."
695                            .to_string(),
696                }],
697                interactive_elements: vec![],
698                key_concepts: vec![
699                    "QAOA approximates combinatorial optimization".to_string(),
700                    "Problem encoding into quantum Hamiltonian".to_string(),
701                    "Alternating mixer and problem Hamiltonians".to_string(),
702                ],
703            }],
704            exercises: vec!["qaoa_tsp".to_string()],
705        });
706
707        self.tutorials
708            .insert(TutorialCategory::Optimization, tutorials);
709    }
710
711    /// Register hybrid tutorials
712    fn register_hybrid_tutorials(&mut self) {
713        let mut tutorials = Vec::new();
714
715        // Hybrid Quantum-Classical ML
716        tutorials.push(Tutorial {
717            id: "hybrid_ml".to_string(),
718            title: "Hybrid Quantum-Classical Machine Learning".to_string(),
719            description: "Learn to combine quantum and classical ML techniques effectively.".to_string(),
720            category: TutorialCategory::Hybrid,
721            difficulty: DifficultyLevel::Intermediate,
722            prerequisites: vec!["qnn_intro".to_string(), "Classical ML experience".to_string()],
723            learning_objectives: vec![
724                "Design hybrid ML pipelines".to_string(),
725                "Combine quantum feature extraction with classical models".to_string(),
726                "Implement ensemble methods".to_string(),
727                "Optimize hybrid workflows".to_string(),
728            ],
729            duration_minutes: 80,
730            sections: vec![
731                TutorialSection {
732                    title: "Hybrid Pipeline Design".to_string(),
733                    content: "Hybrid approaches can leverage the best of both quantum and classical worlds.".to_string(),
734                    code_examples: vec![
735                        CodeExample {
736                            title: "Quantum Feature Extraction + Classical ML".to_string(),
737                            description: "Use quantum circuits for feature extraction and classical models for decision making".to_string(),
738                            code: r#"
739use quantrs2_ml::prelude::*;
740
741// Create hybrid pipeline manager
742let manager = HybridPipelineManager::new();
743
744// Configure hybrid pipeline
745let config = PipelineConfig::default();
746
747// Create quantum feature extractor + classical classifier pipeline
748let mut pipeline = manager.create_pipeline("hybrid_classification", config)?;
749
750// Sample data
751let X = Array2::random((1000, 10), Uniform::new(-1.0, 1.0)?);
752let y = Array1::from_vec((0..1000).map(|i| if i < 500 { 0.0 } else { 1.0 }).collect());
753
754// Train hybrid pipeline
755pipeline.fit(&X.into_dyn(), &y.into_dyn().insert_axis(Axis(1)))?;
756
757// Make predictions
758let test_X = Array2::random((100, 10), Uniform::new(-1.0, 1.0)?);
759let predictions = pipeline.predict(&test_X.into_dyn())?;
760"#.to_string(),
761                            expected_output: Some("Hybrid pipeline trained and predictions made".to_string()),
762                            explanation: "This demonstrates a hybrid approach combining quantum feature learning with classical decision making.".to_string(),
763                        }
764                    ],
765                    interactive_elements: vec![
766                        InteractiveElement {
767                            element_type: InteractiveType::Experiment,
768                            title: "Hybrid vs Pure Quantum Comparison".to_string(),
769                            instructions: "Compare performance of hybrid vs pure quantum approaches".to_string(),
770                            parameters: HashMap::new(),
771                        }
772                    ],
773                    key_concepts: vec![
774                        "Hybrid methods combine strengths of both paradigms".to_string(),
775                        "Quantum preprocessing can enhance classical ML".to_string(),
776                        "Careful design is crucial for hybrid success".to_string(),
777                    ],
778                },
779            ],
780            exercises: vec!["hybrid_credit_scoring".to_string()],
781        });
782
783        self.tutorials.insert(TutorialCategory::Hybrid, tutorials);
784    }
785
786    /// Register application tutorials
787    fn register_application_tutorials(&mut self) {
788        let mut tutorials = Vec::new();
789
790        // Finance Applications
791        tutorials.push(Tutorial {
792            id: "finance_qml".to_string(),
793            title: "Quantum ML for Finance".to_string(),
794            description: "Apply quantum machine learning to financial problems like portfolio optimization and risk assessment.".to_string(),
795            category: TutorialCategory::Applications,
796            difficulty: DifficultyLevel::Intermediate,
797            prerequisites: vec!["hybrid_ml".to_string(), "Finance domain knowledge".to_string()],
798            learning_objectives: vec![
799                "Apply QML to portfolio optimization".to_string(),
800                "Implement quantum risk models".to_string(),
801                "Use domain templates for finance".to_string(),
802                "Evaluate quantum advantage in finance".to_string(),
803            ],
804            duration_minutes: 95,
805            sections: vec![
806                TutorialSection {
807                    title: "Quantum Portfolio Optimization".to_string(),
808                    content: "Use quantum optimization for portfolio selection under constraints.".to_string(),
809                    code_examples: vec![
810                        CodeExample {
811                            title: "Portfolio Optimization with Domain Templates".to_string(),
812                            description: "Use finance domain templates for portfolio optimization".to_string(),
813                            code: r#"
814use quantrs2_ml::prelude::*;
815
816// Load domain template manager
817let template_manager = DomainTemplateManager::new();
818
819// Configure portfolio optimization template
820let config = TemplateConfig {
821    num_qubits: 10,
822    input_dim: 20, // 20 assets
823    output_dim: 20, // Portfolio weights
824    parameters: HashMap::new(),
825};
826
827// Create portfolio optimization model
828let mut portfolio_model = template_manager.create_model_from_template(
829    "Portfolio Optimization",
830    config
831)?;
832
833// Sample return data (20 assets, 252 trading days)
834let returns = Array2::random((252, 20), Normal::new(0.001, 0.02)?);
835
836// Risk-return optimization
837let expected_returns = returns.mean_axis(Axis(0))
838    .ok_or_else(|| MLError::InvalidConfiguration("Failed to compute mean returns".to_string()))?;
839portfolio_model.train(&returns.into_dyn(), &expected_returns.into_dyn().insert_axis(Axis(1)))?;
840
841// Get optimal portfolio weights
842let optimal_weights = portfolio_model.predict(&expected_returns.into_dyn())?;
843"#.to_string(),
844                            expected_output: Some("Optimal portfolio weights computed".to_string()),
845                            explanation: "This uses quantum optimization to find optimal portfolio allocations.".to_string(),
846                        }
847                    ],
848                    interactive_elements: vec![],
849                    key_concepts: vec![
850                        "Quantum optimization for constrained problems".to_string(),
851                        "Risk-return trade-offs in portfolio theory".to_string(),
852                        "Domain templates simplify implementation".to_string(),
853                    ],
854                },
855            ],
856            exercises: vec!["portfolio_backtest".to_string()],
857        });
858
859        self.tutorials
860            .insert(TutorialCategory::Applications, tutorials);
861    }
862
863    /// Register advanced tutorials
864    fn register_advanced_tutorials(&mut self) {
865        let mut tutorials = Vec::new();
866
867        // Quantum Generative Models
868        tutorials.push(Tutorial {
869            id: "quantum_gans".to_string(),
870            title: "Quantum Generative Adversarial Networks".to_string(),
871            description: "Implement quantum GANs for generating quantum and classical data.".to_string(),
872            category: TutorialCategory::Advanced,
873            difficulty: DifficultyLevel::Expert,
874            prerequisites: vec!["qnn_intro".to_string(), "GAN knowledge".to_string()],
875            learning_objectives: vec![
876                "Understand quantum GAN architecture".to_string(),
877                "Implement quantum generator and discriminator".to_string(),
878                "Train quantum GANs on real data".to_string(),
879                "Evaluate generated samples quality".to_string(),
880            ],
881            duration_minutes: 150,
882            sections: vec![
883                TutorialSection {
884                    title: "Quantum GAN Architecture".to_string(),
885                    content: "Quantum GANs use quantum circuits as generators and/or discriminators.".to_string(),
886                    code_examples: vec![
887                        CodeExample {
888                            title: "Simple Quantum GAN".to_string(),
889                            description: "Implement a basic quantum GAN".to_string(),
890                            code: r#"
891use quantrs2_ml::prelude::*;
892
893// Configure quantum GAN
894let gan_config = GANConfig {
895    latent_dim: 4,
896    data_dim: 8,
897    generator_layers: 3,
898    discriminator_layers: 2,
899    learning_rate: 0.01,
900    batch_size: 32,
901    num_epochs: 100,
902};
903
904// Create enhanced quantum GAN
905let mut qgan = EnhancedQuantumGAN::new(gan_config)?;
906
907// Generate training data (simplified)
908let real_data = Array2::random((1000, 8), Normal::new(0.0, 1.0)?);
909
910// Train the quantum GAN
911qgan.train(&real_data)?;
912
913// Generate new samples
914let generated_samples = qgan.generate(100)?;
915"#.to_string(),
916                            expected_output: Some("Quantum GAN trained, samples generated".to_string()),
917                            explanation: "This implements a quantum GAN that can learn to generate data similar to the training set.".to_string(),
918                        }
919                    ],
920                    interactive_elements: vec![
921                        InteractiveElement {
922                            element_type: InteractiveType::Visualization,
923                            title: "GAN Training Dynamics".to_string(),
924                            instructions: "Visualize generator and discriminator loss during training".to_string(),
925                            parameters: HashMap::new(),
926                        }
927                    ],
928                    key_concepts: vec![
929                        "Adversarial training in quantum setting".to_string(),
930                        "Quantum advantage in generative modeling".to_string(),
931                        "Challenges in quantum GAN training".to_string(),
932                    ],
933                },
934            ],
935            exercises: vec!["qgan_mnist".to_string()],
936        });
937
938        self.tutorials.insert(TutorialCategory::Advanced, tutorials);
939    }
940
941    /// Register exercises
942    fn register_exercises(&mut self) {
943        // Basic quantum computing exercises
944        self.exercises.insert(
945            "qc_basic_gates".to_string(),
946            Exercise {
947                id: "qc_basic_gates".to_string(),
948                title: "Basic Quantum Gates".to_string(),
949                description:
950                    "Practice applying basic quantum gates and understanding their effects"
951                        .to_string(),
952                exercise_type: ExerciseType::CircuitDesign,
953                instructions: vec![
954                    "Create a 2-qubit circuit".to_string(),
955                    "Apply H gate to first qubit".to_string(),
956                    "Apply CNOT gate with first qubit as control".to_string(),
957                    "Measure both qubits".to_string(),
958                ],
959                starter_code: Some(
960                    r#"
961use quantrs2_circuit::prelude::*;
962
963fn create_bell_state() -> Result<QuantumCircuit> {
964    let mut circuit = QuantumCircuit::new(2);
965
966    // Step 1: Apply Hadamard to qubit 0 to create superposition |+⟩
967    circuit.h(0);
968    // Step 2: Apply CNOT with qubit 0 as control and qubit 1 as target
969    //         to entangle them, creating the Bell state (|00⟩ + |11⟩)/√2
970    circuit.cnot(0, 1);
971    // Step 3: Measure both qubits
972    circuit.measure_all();
973
974    Ok(circuit)
975}
976"#
977                    .to_string(),
978                ),
979                solution_code: r#"
980use quantrs2_circuit::prelude::*;
981
982fn create_bell_state() -> Result<QuantumCircuit> {
983    let mut circuit = QuantumCircuit::new(2);
984
985    circuit.h(0);
986    circuit.cnot(0, 1);
987    circuit.measure_all();
988
989    Ok(circuit)
990}
991"#
992                .to_string(),
993                test_cases: vec![
994                    TestCase {
995                        description: "Circuit should have 2 qubits".to_string(),
996                        input: "circuit.num_qubits()".to_string(),
997                        expected_output: "2".to_string(),
998                        points: 10,
999                    },
1000                    TestCase {
1001                        description: "Circuit should create Bell state".to_string(),
1002                        input: "measure_bell_state_fidelity()".to_string(),
1003                        expected_output: "> 0.95".to_string(),
1004                        points: 20,
1005                    },
1006                ],
1007                hints: vec![
1008                    "Remember that H gate creates superposition".to_string(),
1009                    "CNOT gate creates entanglement between qubits".to_string(),
1010                ],
1011            },
1012        );
1013
1014        // QNN classification exercise
1015        self.exercises.insert(
1016            "qnn_classification".to_string(),
1017            Exercise {
1018                id: "qnn_classification".to_string(),
1019                title: "QNN Binary Classification".to_string(),
1020                description: "Implement a quantum neural network for binary classification"
1021                    .to_string(),
1022                exercise_type: ExerciseType::AlgorithmImplementation,
1023                instructions: vec![
1024                    "Create a QNN with 4 qubits".to_string(),
1025                    "Add embedding and entangling layers".to_string(),
1026                    "Train on provided dataset".to_string(),
1027                    "Achieve >85% accuracy".to_string(),
1028                ],
1029                starter_code: Some(
1030                    r#"
1031use quantrs2_ml::prelude::*;
1032
1033/// QNN binary classifier implementing angle encoding + variational layers.
1034///
1035/// Architecture:
1036///   1. Embedding layer  – RY/RZ angle encoding of input features
1037///   2. Entangling layer – CNOT chain for quantum correlations
1038///   3. Variational layer – trainable RY/RZ parameters (gradient via parameter-shift)
1039///   4. Measurement       – Z-expectation on qubit 0 → threshold at 0 → class label
1040fn train_qnn_classifier(X: &ArrayD<f64>, y: &ArrayD<f64>) -> Result<Box<dyn QuantumModel>> {
1041    // Build a 4-qubit QNN with embedding, entangling, and parameterised layers
1042    let qnn_builder = QNNBuilder::new(4)
1043        .add_layer(QNNLayer::Embedding {
1044            rotation_gates: vec!["RY".to_string(), "RZ".to_string()],
1045        })
1046        .add_layer(QNNLayer::Entangling {
1047            entangling_gate: "CNOT".to_string(),
1048        })
1049        .add_layer(QNNLayer::Parameterized {
1050            gates: vec!["RY".to_string(), "RZ".to_string()],
1051            num_parameters: 8,
1052        });
1053
1054    let mut qnn = qnn_builder.build()?;
1055
1056    // Training loop using parameter-shift gradient descent
1057    // Parameters are updated by the QNN's internal optimizer
1058    qnn.train(X, y)?;
1059
1060    Ok(Box::new(qnn))
1061}
1062"#
1063                    .to_string(),
1064                ),
1065                solution_code: r#"
1066use quantrs2_ml::prelude::*;
1067
1068fn train_qnn_classifier(X: &ArrayD<f64>, y: &ArrayD<f64>) -> Result<Box<dyn QuantumModel>> {
1069    let mut qnn_builder = QNNBuilder::new(4)
1070        .add_layer(QNNLayer::Embedding { rotation_gates: vec!["RY", "RZ"] })
1071        .add_layer(QNNLayer::Entangling { entangling_gate: "CNOT" })
1072        .add_layer(QNNLayer::Parameterized {
1073            gates: vec!["RY", "RZ"],
1074            num_parameters: 8
1075        });
1076
1077    let mut qnn = qnn_builder.build()?;
1078    qnn.train(X, y)?;
1079
1080    Ok(Box::new(qnn))
1081}
1082"#
1083                .to_string(),
1084                test_cases: vec![
1085                    TestCase {
1086                        description: "Model should train without errors".to_string(),
1087                        input: "train_qnn_classifier(&X, &y)".to_string(),
1088                        expected_output: "Ok(model)".to_string(),
1089                        points: 15,
1090                    },
1091                    TestCase {
1092                        description: "Model should achieve >85% accuracy".to_string(),
1093                        input: "evaluate_accuracy(&model, &X_test, &y_test)".to_string(),
1094                        expected_output: "> 0.85".to_string(),
1095                        points: 25,
1096                    },
1097                ],
1098                hints: vec![
1099                    "Use appropriate data encoding for your problem".to_string(),
1100                    "Try different ansatz architectures".to_string(),
1101                    "Monitor training convergence".to_string(),
1102                ],
1103            },
1104        );
1105    }
1106
1107    /// Get tutorials for a category
1108    pub fn get_category_tutorials(&self, category: &TutorialCategory) -> Option<&Vec<Tutorial>> {
1109        self.tutorials.get(category)
1110    }
1111
1112    /// Get all available categories
1113    pub fn get_available_categories(&self) -> Vec<TutorialCategory> {
1114        self.tutorials.keys().cloned().collect()
1115    }
1116
1117    /// Search tutorials by difficulty
1118    pub fn search_by_difficulty(&self, difficulty: &DifficultyLevel) -> Vec<&Tutorial> {
1119        self.tutorials
1120            .values()
1121            .flatten()
1122            .filter(|tutorial| {
1123                std::mem::discriminant(&tutorial.difficulty) == std::mem::discriminant(difficulty)
1124            })
1125            .collect()
1126    }
1127
1128    /// Get tutorial by ID
1129    pub fn get_tutorial(&self, tutorial_id: &str) -> Option<&Tutorial> {
1130        self.tutorials
1131            .values()
1132            .flatten()
1133            .find(|tutorial| tutorial.id == tutorial_id)
1134    }
1135
1136    /// Get exercise by ID
1137    pub fn get_exercise(&self, exercise_id: &str) -> Option<&Exercise> {
1138        self.exercises.get(exercise_id)
1139    }
1140
1141    /// Start tutorial for user
1142    pub fn start_tutorial(&mut self, user_id: String, tutorial_id: String) -> Result<()> {
1143        if !self
1144            .tutorials
1145            .values()
1146            .flatten()
1147            .any(|t| t.id == tutorial_id)
1148        {
1149            return Err(MLError::InvalidConfiguration(format!(
1150                "Tutorial not found: {}",
1151                tutorial_id
1152            )));
1153        }
1154
1155        let mut progress =
1156            self.progress
1157                .entry(user_id.clone())
1158                .or_insert_with(|| TutorialProgress {
1159                    user_id: user_id.clone(),
1160                    completed_tutorials: Vec::new(),
1161                    completed_exercises: Vec::new(),
1162                    current_tutorial: None,
1163                    scores: HashMap::new(),
1164                    time_spent: HashMap::new(),
1165                });
1166
1167        progress.current_tutorial = Some(tutorial_id);
1168        Ok(())
1169    }
1170
1171    /// Complete tutorial for user
1172    pub fn complete_tutorial(
1173        &mut self,
1174        user_id: &str,
1175        tutorial_id: String,
1176        score: f64,
1177        time_minutes: usize,
1178    ) -> Result<()> {
1179        let progress = self
1180            .progress
1181            .get_mut(user_id)
1182            .ok_or_else(|| MLError::InvalidConfiguration("User not found".to_string()))?;
1183
1184        progress.completed_tutorials.push(tutorial_id.clone());
1185        progress.scores.insert(tutorial_id.clone(), score);
1186        progress.time_spent.insert(tutorial_id, time_minutes);
1187        progress.current_tutorial = None;
1188
1189        Ok(())
1190    }
1191
1192    /// Get learning path recommendations
1193    pub fn recommend_learning_path(&self, user_background: &UserBackground) -> Vec<String> {
1194        let mut path = Vec::new();
1195
1196        match user_background.experience_level {
1197            ExperienceLevel::Beginner => {
1198                path.extend(vec![
1199                    "qc_intro".to_string(),
1200                    "qc_circuits".to_string(),
1201                    "qnn_intro".to_string(),
1202                    "qsvm_tutorial".to_string(),
1203                ]);
1204            }
1205            ExperienceLevel::Intermediate => {
1206                path.extend(vec![
1207                    "qnn_intro".to_string(),
1208                    "qsvm_tutorial".to_string(),
1209                    "vqe_tutorial".to_string(),
1210                    "hybrid_ml".to_string(),
1211                ]);
1212            }
1213            ExperienceLevel::Advanced => {
1214                path.extend(vec![
1215                    "vqe_tutorial".to_string(),
1216                    "qaoa_tutorial".to_string(),
1217                    "hybrid_ml".to_string(),
1218                    "quantum_gans".to_string(),
1219                ]);
1220            }
1221        }
1222
1223        // Add domain-specific tutorials
1224        if let Some(domain) = &user_background.target_domain {
1225            match domain.as_str() {
1226                "finance" => path.push("finance_qml".to_string()),
1227                _ => {} // Add other domains as needed
1228            }
1229        }
1230
1231        path
1232    }
1233
1234    /// Run interactive tutorial session
1235    pub fn run_interactive_session(&self, tutorial_id: &str) -> Result<TutorialSession> {
1236        let tutorial = self.get_tutorial(tutorial_id).ok_or_else(|| {
1237            MLError::InvalidConfiguration(format!("Tutorial not found: {}", tutorial_id))
1238        })?;
1239
1240        Ok(TutorialSession {
1241            tutorial_id: tutorial_id.to_string(),
1242            current_section: 0,
1243            completed_sections: Vec::new(),
1244            session_start_time: std::time::SystemTime::now(),
1245            interactive_state: HashMap::new(),
1246        })
1247    }
1248}
1249
1250/// User background for personalized recommendations
1251#[derive(Debug, Clone)]
1252pub struct UserBackground {
1253    /// Experience level with quantum computing
1254    pub experience_level: ExperienceLevel,
1255    /// Classical ML experience
1256    pub classical_ml_experience: bool,
1257    /// Programming languages known
1258    pub programming_languages: Vec<String>,
1259    /// Target application domain
1260    pub target_domain: Option<String>,
1261    /// Learning goals
1262    pub learning_goals: Vec<String>,
1263}
1264
1265/// Experience levels
1266#[derive(Debug, Clone)]
1267pub enum ExperienceLevel {
1268    Beginner,
1269    Intermediate,
1270    Advanced,
1271}
1272
1273/// Interactive tutorial session
1274#[derive(Debug, Clone)]
1275pub struct TutorialSession {
1276    /// Tutorial ID
1277    pub tutorial_id: String,
1278    /// Current section index
1279    pub current_section: usize,
1280    /// Completed sections
1281    pub completed_sections: Vec<usize>,
1282    /// Session start time
1283    pub session_start_time: std::time::SystemTime,
1284    /// Interactive state
1285    pub interactive_state: HashMap<String, String>,
1286}
1287
1288impl TutorialSession {
1289    /// Get current section
1290    pub fn current_section(&self) -> usize {
1291        self.current_section
1292    }
1293
1294    /// Mark section as complete
1295    pub fn complete_section(&mut self) {
1296        if !self.completed_sections.contains(&self.current_section) {
1297            self.completed_sections.push(self.current_section);
1298        }
1299        self.current_section += 1;
1300    }
1301
1302    /// Check if tutorial is complete
1303    pub fn is_complete(&self, total_sections: usize) -> bool {
1304        self.completed_sections.len() >= total_sections
1305    }
1306
1307    /// Get total number of sections for this tutorial
1308    pub fn total_sections(&self) -> usize {
1309        // This would typically be retrieved from the tutorial manager
1310        // For now, return a default value
1311        10
1312    }
1313
1314    /// Get estimated duration for this tutorial in minutes
1315    pub fn estimated_duration(&self) -> usize {
1316        // This would typically be calculated based on tutorial content
1317        // For now, return a default value
1318        30
1319    }
1320}
1321
1322/// Utility functions for tutorials
1323pub mod utils {
1324    use super::*;
1325
1326    /// Create beginner learning path
1327    pub fn create_beginner_path() -> Vec<String> {
1328        vec![
1329            "qc_intro".to_string(),
1330            "qc_circuits".to_string(),
1331            "qnn_intro".to_string(),
1332            "qsvm_tutorial".to_string(),
1333            "hybrid_ml".to_string(),
1334        ]
1335    }
1336
1337    /// Create advanced learning path
1338    pub fn create_advanced_path() -> Vec<String> {
1339        vec![
1340            "vqe_tutorial".to_string(),
1341            "qaoa_tutorial".to_string(),
1342            "quantum_gans".to_string(),
1343            "finance_qml".to_string(),
1344        ]
1345    }
1346
1347    /// Generate tutorial progress report
1348    pub fn generate_progress_report(progress: &TutorialProgress) -> String {
1349        let mut report = String::new();
1350        report.push_str(&format!(
1351            "Tutorial Progress Report for User: {}\n",
1352            progress.user_id
1353        ));
1354        report.push_str("=".repeat(50).as_str());
1355        report.push_str("\n\n");
1356
1357        report.push_str(&format!(
1358            "Completed Tutorials: {}\n",
1359            progress.completed_tutorials.len()
1360        ));
1361        report.push_str(&format!(
1362            "Completed Exercises: {}\n",
1363            progress.completed_exercises.len()
1364        ));
1365
1366        if let Some(current) = &progress.current_tutorial {
1367            report.push_str(&format!("Current Tutorial: {}\n", current));
1368        }
1369
1370        report.push_str("\nScores:\n");
1371        for (tutorial, score) in &progress.scores {
1372            report.push_str(&format!("  {}: {:.1}%\n", tutorial, score * 100.0));
1373        }
1374
1375        let total_time: usize = progress.time_spent.values().sum();
1376        report.push_str(&format!("\nTotal Learning Time: {} minutes\n", total_time));
1377
1378        report
1379    }
1380
1381    /// Validate exercise solution
1382    pub fn validate_exercise_solution(exercise: &Exercise, user_code: &str) -> ExerciseResult {
1383        // Simplified validation - in practice would compile and test code
1384        let mut passed_tests = 0;
1385        let total_tests = exercise.test_cases.len();
1386
1387        // Basic validation checks
1388        if user_code.contains("TODO") {
1389            return ExerciseResult {
1390                passed: false,
1391                score: 0.0,
1392                passed_tests,
1393                total_tests,
1394                feedback: "Remove TODO comments and implement the solution".to_string(),
1395                hints_used: 0,
1396            };
1397        }
1398
1399        // Mock test execution
1400        passed_tests = if user_code.len() > 100 {
1401            total_tests
1402        } else {
1403            total_tests / 2
1404        };
1405
1406        let score = passed_tests as f64 / total_tests as f64;
1407        let passed = score >= 0.7;
1408
1409        ExerciseResult {
1410            passed,
1411            score,
1412            passed_tests,
1413            total_tests,
1414            feedback: if passed {
1415                "Great job! All tests passed.".to_string()
1416            } else {
1417                "Some tests failed. Check the hints and try again.".to_string()
1418            },
1419            hints_used: 0,
1420        }
1421    }
1422}
1423
1424/// Exercise result
1425#[derive(Debug, Clone)]
1426pub struct ExerciseResult {
1427    /// Whether exercise passed
1428    pub passed: bool,
1429    /// Score (0.0 to 1.0)
1430    pub score: f64,
1431    /// Number of tests passed
1432    pub passed_tests: usize,
1433    /// Total number of tests
1434    pub total_tests: usize,
1435    /// Feedback message
1436    pub feedback: String,
1437    /// Number of hints used
1438    pub hints_used: usize,
1439}
1440
1441#[cfg(test)]
1442mod tests {
1443    use super::*;
1444
1445    #[test]
1446    fn test_tutorial_manager_creation() {
1447        let manager = TutorialManager::new();
1448        assert!(!manager.get_available_categories().is_empty());
1449    }
1450
1451    #[test]
1452    fn test_get_tutorial() {
1453        let manager = TutorialManager::new();
1454        let tutorial = manager.get_tutorial("qc_intro");
1455        assert!(tutorial.is_some());
1456        assert_eq!(
1457            tutorial.expect("Tutorial should exist").title,
1458            "Introduction to Quantum Computing"
1459        );
1460    }
1461
1462    #[test]
1463    fn test_difficulty_search() {
1464        let manager = TutorialManager::new();
1465        let beginner_tutorials = manager.search_by_difficulty(&DifficultyLevel::Beginner);
1466        assert!(!beginner_tutorials.is_empty());
1467
1468        for tutorial in beginner_tutorials {
1469            assert!(matches!(tutorial.difficulty, DifficultyLevel::Beginner));
1470        }
1471    }
1472
1473    #[test]
1474    fn test_learning_path_recommendation() {
1475        let manager = TutorialManager::new();
1476        let background = UserBackground {
1477            experience_level: ExperienceLevel::Beginner,
1478            classical_ml_experience: true,
1479            programming_languages: vec!["Python".to_string(), "Rust".to_string()],
1480            target_domain: Some("finance".to_string()),
1481            learning_goals: vec!["Learn quantum ML basics".to_string()],
1482        };
1483
1484        let path = manager.recommend_learning_path(&background);
1485        assert!(!path.is_empty());
1486        assert!(path.contains(&"qc_intro".to_string()));
1487    }
1488
1489    #[test]
1490    fn test_tutorial_progress() {
1491        let mut manager = TutorialManager::new();
1492        let user_id = "test_user".to_string();
1493        let tutorial_id = "qc_intro".to_string();
1494
1495        // Start tutorial
1496        manager
1497            .start_tutorial(user_id.clone(), tutorial_id.clone())
1498            .expect("Should start tutorial successfully");
1499
1500        // Complete tutorial
1501        manager
1502            .complete_tutorial(&user_id, tutorial_id.clone(), 0.95, 45)
1503            .expect("Should complete tutorial successfully");
1504
1505        let progress = manager
1506            .progress
1507            .get(&user_id)
1508            .expect("User progress should exist");
1509        assert!(progress.completed_tutorials.contains(&tutorial_id));
1510        assert_eq!(progress.scores.get(&tutorial_id), Some(&0.95));
1511    }
1512
1513    #[test]
1514    fn test_exercise_validation() {
1515        let manager = TutorialManager::new();
1516        let exercise = manager
1517            .get_exercise("qc_basic_gates")
1518            .expect("Exercise should exist");
1519
1520        let good_solution = r#"
1521        use quantrs2_circuit::prelude::*;
1522
1523        fn create_bell_state() -> Result<QuantumCircuit> {
1524            let mut circuit = QuantumCircuit::new(2);
1525            circuit.h(0);
1526            circuit.cnot(0, 1);
1527            circuit.measure_all();
1528            Ok(circuit)
1529        }
1530        "#;
1531
1532        let result = utils::validate_exercise_solution(exercise, good_solution);
1533        assert!(result.passed);
1534        assert!(result.score > 0.7);
1535    }
1536
1537    #[test]
1538    fn test_interactive_session() {
1539        let manager = TutorialManager::new();
1540        let session = manager
1541            .run_interactive_session("qc_intro")
1542            .expect("Should create interactive session");
1543
1544        assert_eq!(session.tutorial_id, "qc_intro");
1545        assert_eq!(session.current_section, 0);
1546        assert!(session.completed_sections.is_empty());
1547    }
1548}