quantrs2_core/
quantum_game_theory.rs

1//! Quantum Game Theory
2//!
3//! This module implements quantum game theory algorithms and protocols,
4//! extending classical game theory to the quantum realm. It includes
5//! quantum Nash equilibria, quantum strategies, and quantum mechanisms
6//! for multi-player games.
7
8use crate::error::{QuantRS2Error, QuantRS2Result};
9use scirs2_core::ndarray::{Array1, Array2};
10use scirs2_core::Complex64;
11use std::collections::HashMap;
12
13/// Types of quantum games
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum GameType {
16    /// Prisoner's Dilemma with quantum strategies
17    QuantumPrisonersDilemma,
18    /// Battle of the Sexes with quantum entanglement
19    QuantumBattleOfSexes,
20    /// Quantum Auction mechanism
21    QuantumAuction,
22    /// Quantum Coordination Game
23    QuantumCoordination,
24    /// Quantum Minority Game
25    QuantumMinorityGame,
26    /// Custom quantum game
27    Custom,
28}
29
30/// Player strategies in quantum games
31#[derive(Debug, Clone, PartialEq)]
32pub enum QuantumStrategy {
33    /// Classical deterministic strategy (pure classical)
34    Classical(f64), // angle parameter for rotation
35    /// Quantum superposition strategy
36    Superposition { theta: f64, phi: f64 }, // Bloch sphere angles
37    /// Entangled strategy (requires coordination with other player)
38    Entangled,
39    /// Mixed quantum strategy
40    Mixed(Vec<(f64, QuantumStrategy)>), // probabilities and strategies
41}
42
43/// Quantum player in a game
44#[derive(Debug, Clone)]
45pub struct QuantumPlayer {
46    /// Player ID
47    pub id: usize,
48    /// Player's quantum strategy
49    pub strategy: QuantumStrategy,
50    /// Player's quantum state (for entangled strategies)
51    pub state: Option<Array1<Complex64>>,
52    /// Player's utility function parameters
53    pub utility_params: HashMap<String, f64>,
54}
55
56impl QuantumPlayer {
57    /// Create a new quantum player
58    pub fn new(id: usize, strategy: QuantumStrategy) -> Self {
59        Self {
60            id,
61            strategy,
62            state: None,
63            utility_params: HashMap::new(),
64        }
65    }
66
67    /// Set utility function parameter
68    pub fn set_utility_param(&mut self, param: String, value: f64) {
69        self.utility_params.insert(param, value);
70    }
71
72    /// Prepare quantum state based on strategy
73    pub fn prepare_quantum_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
74        match self.strategy {
75            QuantumStrategy::Classical(theta) => {
76                // Classical strategy as a quantum state |0⟩ or |1⟩ with rotation
77                let state = Array1::from_vec(vec![
78                    Complex64::new(theta.cos(), 0.0),
79                    Complex64::new(theta.sin(), 0.0),
80                ]);
81                self.state = Some(state.clone());
82                Ok(state)
83            }
84            QuantumStrategy::Superposition { theta, phi } => {
85                // General qubit state on Bloch sphere
86                let state = Array1::from_vec(vec![
87                    Complex64::new((theta / 2.0).cos(), 0.0),
88                    Complex64::new(
89                        (theta / 2.0).sin() * phi.cos(),
90                        (theta / 2.0).sin() * phi.sin(),
91                    ),
92                ]);
93                self.state = Some(state.clone());
94                Ok(state)
95            }
96            QuantumStrategy::Entangled => {
97                // Entangled state preparation requires coordination
98                // Return Bell state component for now
99                let state = Array1::from_vec(vec![
100                    Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
101                    Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
102                ]);
103                self.state = Some(state.clone());
104                Ok(state)
105            }
106            QuantumStrategy::Mixed(_) => {
107                // Mixed strategy - for now use superposition
108                let state = Array1::from_vec(vec![
109                    Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
110                    Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
111                ]);
112                self.state = Some(state.clone());
113                Ok(state)
114            }
115        }
116    }
117
118    /// Compute expected utility given game outcomes
119    pub fn compute_utility(&self, game_outcome: &GameOutcome) -> f64 {
120        match &game_outcome.payoff_matrix {
121            Some(payoffs) => {
122                // Linear utility based on expected payoffs
123                payoffs.iter().sum::<f64>() / payoffs.len() as f64
124            }
125            None => 0.0,
126        }
127    }
128}
129
130/// Game outcome after quantum measurement
131#[derive(Debug, Clone)]
132pub struct GameOutcome {
133    /// Classical outcome for each player
134    pub classical_outcomes: Vec<usize>,
135    /// Quantum measurement probabilities
136    pub probabilities: Array1<f64>,
137    /// Payoff matrix for the outcomes
138    pub payoff_matrix: Option<Vec<f64>>,
139    /// Nash equilibrium indicator
140    pub is_nash_equilibrium: bool,
141}
142
143/// Quantum game engine
144#[derive(Debug, Clone)]
145pub struct QuantumGame {
146    /// Type of game
147    pub game_type: GameType,
148    /// Number of players
149    pub num_players: usize,
150    /// Players in the game
151    pub players: Vec<QuantumPlayer>,
152    /// Quantum circuit for the game
153    pub game_circuit: Option<Array2<Complex64>>,
154    /// Payoff matrices (one for each player)
155    pub payoff_matrices: Vec<Array2<f64>>,
156    /// Entanglement operator (if applicable)
157    pub entanglement_operator: Option<Array2<Complex64>>,
158}
159
160impl QuantumGame {
161    /// Create a new quantum game
162    pub fn new(game_type: GameType, num_players: usize) -> Self {
163        let players = Vec::new();
164        let payoff_matrices = vec![Array2::zeros((2, 2)); num_players];
165
166        Self {
167            game_type,
168            num_players,
169            players,
170            game_circuit: None,
171            payoff_matrices,
172            entanglement_operator: None,
173        }
174    }
175
176    /// Add a player to the game
177    pub fn add_player(&mut self, player: QuantumPlayer) -> QuantRS2Result<()> {
178        if self.players.len() >= self.num_players {
179            return Err(QuantRS2Error::InvalidInput(
180                "Maximum number of players reached".to_string(),
181            ));
182        }
183
184        self.players.push(player);
185        Ok(())
186    }
187
188    /// Set payoff matrix for a specific player
189    pub fn set_payoff_matrix(
190        &mut self,
191        player_id: usize,
192        payoffs: Array2<f64>,
193    ) -> QuantRS2Result<()> {
194        if player_id >= self.num_players {
195            return Err(QuantRS2Error::InvalidInput(
196                "Player ID out of bounds".to_string(),
197            ));
198        }
199
200        self.payoff_matrices[player_id] = payoffs;
201        Ok(())
202    }
203
204    /// Create quantum prisoner's dilemma
205    pub fn quantum_prisoners_dilemma() -> QuantRS2Result<Self> {
206        let mut game = Self::new(GameType::QuantumPrisonersDilemma, 2);
207
208        // Classical prisoner's dilemma payoff matrices
209        // (Cooperate, Defect) strategies
210        let payoff_p1 = Array2::from_shape_vec(
211            (2, 2),
212            vec![3.0, 0.0, 5.0, 1.0], // (CC, CD, DC, DD)
213        )
214        .unwrap();
215
216        let payoff_p2 = Array2::from_shape_vec(
217            (2, 2),
218            vec![3.0, 5.0, 0.0, 1.0], // (CC, DC, CD, DD)
219        )
220        .unwrap();
221
222        game.set_payoff_matrix(0, payoff_p1)?;
223        game.set_payoff_matrix(1, payoff_p2)?;
224
225        // Add entanglement operator (optional)
226        let entanglement = Self::create_entanglement_operator(std::f64::consts::PI / 2.0);
227        game.entanglement_operator = Some(entanglement);
228
229        Ok(game)
230    }
231
232    /// Create quantum coordination game
233    pub fn quantum_coordination_game() -> QuantRS2Result<Self> {
234        let mut game = Self::new(GameType::QuantumCoordination, 2);
235
236        // Coordination game: both players want to choose the same action
237        let payoff_p1 = Array2::from_shape_vec(
238            (2, 2),
239            vec![2.0, 0.0, 0.0, 1.0], // Prefer (0,0) or (1,1)
240        )
241        .unwrap();
242
243        let payoff_p2 = payoff_p1.clone();
244
245        game.set_payoff_matrix(0, payoff_p1)?;
246        game.set_payoff_matrix(1, payoff_p2)?;
247
248        Ok(game)
249    }
250
251    /// Create quantum auction mechanism
252    pub fn quantum_auction(num_bidders: usize) -> QuantRS2Result<Self> {
253        let mut game = Self::new(GameType::QuantumAuction, num_bidders);
254
255        // Each bidder has a 2x2 payoff matrix (bid high/low vs others)
256        for i in 0..num_bidders {
257            let payoff = Array2::from_shape_vec(
258                (2, 2),
259                vec![1.0, 0.5, 2.0, 0.0], // Utility from winning/losing auction
260            )
261            .unwrap();
262
263            game.set_payoff_matrix(i, payoff)?;
264        }
265
266        Ok(game)
267    }
268
269    /// Create entanglement operator
270    fn create_entanglement_operator(gamma: f64) -> Array2<Complex64> {
271        // J(γ) = exp(iγ(σ_x ⊗ σ_x + σ_y ⊗ σ_y)/2)
272        // Simplified version: controlled-rotation
273        let cos_g = (gamma / 2.0).cos();
274        let sin_g = (gamma / 2.0).sin();
275
276        Array2::from_shape_vec(
277            (4, 4),
278            vec![
279                Complex64::new(cos_g, 0.0),
280                Complex64::new(0.0, 0.0),
281                Complex64::new(0.0, 0.0),
282                Complex64::new(0.0, sin_g),
283                Complex64::new(0.0, 0.0),
284                Complex64::new(cos_g, 0.0),
285                Complex64::new(0.0, -sin_g),
286                Complex64::new(0.0, 0.0),
287                Complex64::new(0.0, 0.0),
288                Complex64::new(0.0, -sin_g),
289                Complex64::new(cos_g, 0.0),
290                Complex64::new(0.0, 0.0),
291                Complex64::new(0.0, sin_g),
292                Complex64::new(0.0, 0.0),
293                Complex64::new(0.0, 0.0),
294                Complex64::new(cos_g, 0.0),
295            ],
296        )
297        .unwrap()
298    }
299
300    /// Play the quantum game and return outcome
301    pub fn play_game(&mut self) -> QuantRS2Result<GameOutcome> {
302        if self.players.len() != self.num_players {
303            return Err(QuantRS2Error::InvalidInput(
304                "Not all players have joined the game".to_string(),
305            ));
306        }
307
308        // Prepare player quantum states
309        let mut joint_state = self.prepare_joint_state()?;
310
311        // Apply entanglement operator if present
312        if let Some(entanglement_op) = &self.entanglement_operator {
313            joint_state = entanglement_op.dot(&joint_state);
314        }
315
316        // Apply player strategies
317        joint_state = self.apply_player_strategies(joint_state)?;
318
319        // Measure the final state
320        self.measure_game_outcome(joint_state)
321    }
322
323    /// Prepare joint quantum state of all players
324    fn prepare_joint_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
325        let total_dim = 1 << self.num_players; // 2^n dimensional Hilbert space
326        let mut joint_state = Array1::zeros(total_dim);
327
328        // Start with |00...0⟩ state
329        joint_state[0] = Complex64::new(1.0, 0.0);
330
331        // Apply each player's initial strategy
332        let mut player_states = Vec::new();
333        for player in self.players.iter_mut() {
334            let player_state = player.prepare_quantum_state()?;
335            player_states.push(player_state);
336        }
337
338        for (i, player_state) in player_states.into_iter().enumerate() {
339            joint_state = self.tensor_product_player_state(joint_state, player_state, i)?;
340        }
341
342        Ok(joint_state)
343    }
344
345    /// Tensor product of joint state with single player state
346    fn tensor_product_player_state(
347        &self,
348        joint_state: Array1<Complex64>,
349        player_state: Array1<Complex64>,
350        player_index: usize,
351    ) -> QuantRS2Result<Array1<Complex64>> {
352        // Simplified implementation - in practice this is more complex
353        let mut new_state = joint_state.clone();
354
355        // Apply player's state preparation as a rotation on their qubit
356        for i in 0..new_state.len() {
357            let bit = (i >> player_index) & 1;
358            if bit == 0 {
359                new_state[i] *= player_state[0];
360            } else {
361                new_state[i] *= player_state[1];
362            }
363        }
364
365        Ok(new_state)
366    }
367
368    /// Apply all player strategies to the joint state
369    fn apply_player_strategies(
370        &self,
371        mut joint_state: Array1<Complex64>,
372    ) -> QuantRS2Result<Array1<Complex64>> {
373        // For each player, apply their quantum strategy operator
374        for (i, player) in self.players.iter().enumerate() {
375            joint_state = self.apply_single_player_strategy(joint_state, &player.strategy, i)?;
376        }
377
378        Ok(joint_state)
379    }
380
381    /// Apply a single player's strategy to the joint state
382    fn apply_single_player_strategy(
383        &self,
384        mut joint_state: Array1<Complex64>,
385        strategy: &QuantumStrategy,
386        player_index: usize,
387    ) -> QuantRS2Result<Array1<Complex64>> {
388        match strategy {
389            QuantumStrategy::Classical(theta) => {
390                // Apply rotation around Z-axis
391                let cos_theta = theta.cos();
392                let sin_theta = theta.sin();
393
394                for i in 0..joint_state.len() {
395                    let bit = (i >> player_index) & 1;
396                    if bit == 1 {
397                        joint_state[i] *= Complex64::new(cos_theta, sin_theta);
398                    }
399                }
400            }
401            QuantumStrategy::Superposition { theta, phi } => {
402                // Apply general single-qubit rotation
403                let half_theta = theta / 2.0;
404                let cos_half = half_theta.cos();
405                let sin_half = half_theta.sin();
406
407                let mut new_state = Array1::zeros(joint_state.len());
408
409                for i in 0..joint_state.len() {
410                    let bit = (i >> player_index) & 1;
411                    let flipped_i = i ^ (1 << player_index);
412
413                    if bit == 0 {
414                        new_state[i] += cos_half * joint_state[i];
415                        new_state[flipped_i] +=
416                            sin_half * Complex64::new(phi.cos(), phi.sin()) * joint_state[i];
417                    }
418                }
419
420                joint_state = new_state;
421            }
422            QuantumStrategy::Entangled => {
423                // Entangled strategies are handled by the entanglement operator
424                // No additional operation needed here
425            }
426            QuantumStrategy::Mixed(_strategies) => {
427                // Mixed strategies require probabilistic sampling
428                // For now, treat as superposition
429                let mut new_state = joint_state.clone();
430                for i in 0..new_state.len() {
431                    new_state[i] *= Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0);
432                }
433                joint_state = new_state;
434            }
435        }
436
437        Ok(joint_state)
438    }
439
440    /// Measure the final game state and determine outcome
441    fn measure_game_outcome(&self, joint_state: Array1<Complex64>) -> QuantRS2Result<GameOutcome> {
442        let num_outcomes = joint_state.len();
443        let mut probabilities = Array1::zeros(num_outcomes);
444
445        // Compute measurement probabilities
446        for i in 0..num_outcomes {
447            probabilities[i] = joint_state[i].norm_sqr();
448        }
449
450        // Sample a classical outcome based on probabilities
451        let outcome_index = self.sample_outcome(&probabilities)?;
452
453        // Extract individual player outcomes
454        let mut classical_outcomes = Vec::new();
455        for player_idx in 0..self.num_players {
456            let bit = (outcome_index >> player_idx) & 1;
457            classical_outcomes.push(bit);
458        }
459
460        // Compute payoffs for this outcome
461        let payoffs = self.compute_payoffs(&classical_outcomes)?;
462
463        // Check if this is a Nash equilibrium
464        let is_nash = self.is_nash_equilibrium(&classical_outcomes, &payoffs)?;
465
466        Ok(GameOutcome {
467            classical_outcomes,
468            probabilities,
469            payoff_matrix: Some(payoffs),
470            is_nash_equilibrium: is_nash,
471        })
472    }
473
474    /// Sample an outcome based on probability distribution
475    fn sample_outcome(&self, probabilities: &Array1<f64>) -> QuantRS2Result<usize> {
476        let mut rng = thread_rng();
477        use scirs2_core::random::prelude::*;
478
479        let random_value: f64 = rng.random();
480        let mut cumulative = 0.0;
481
482        for (i, &prob) in probabilities.iter().enumerate() {
483            cumulative += prob;
484            if random_value <= cumulative {
485                return Ok(i);
486            }
487        }
488
489        // Fallback to last outcome
490        Ok(probabilities.len() - 1)
491    }
492
493    /// Compute payoffs for all players given classical outcomes
494    fn compute_payoffs(&self, outcomes: &[usize]) -> QuantRS2Result<Vec<f64>> {
495        let mut payoffs = Vec::new();
496
497        for (player_idx, payoff_matrix) in self.payoff_matrices.iter().enumerate() {
498            if outcomes.len() < 2 {
499                return Err(QuantRS2Error::InvalidInput(
500                    "Need at least 2 players for payoff calculation".to_string(),
501                ));
502            }
503
504            // For 2-player games, use both players' actions
505            let player_action = outcomes[player_idx];
506            let opponent_action = outcomes[1 - player_idx % 2]; // Simple opponent selection
507
508            let payoff = payoff_matrix[[player_action, opponent_action]];
509            payoffs.push(payoff);
510        }
511
512        Ok(payoffs)
513    }
514
515    /// Check if current outcome is a Nash equilibrium
516    fn is_nash_equilibrium(&self, outcomes: &[usize], _payoffs: &[f64]) -> QuantRS2Result<bool> {
517        // Simplified Nash equilibrium check
518        // In a real implementation, this would check if any player can improve
519        // their payoff by unilaterally changing their strategy
520
521        // For now, assume prisoner's dilemma: (Defect, Defect) is Nash equilibrium
522        match self.game_type {
523            GameType::QuantumPrisonersDilemma => {
524                Ok(outcomes == &[1, 1]) // Both defect
525            }
526            GameType::QuantumCoordination => {
527                Ok(outcomes[0] == outcomes[1]) // Coordination successful
528            }
529            _ => Ok(false),
530        }
531    }
532
533    /// Find quantum Nash equilibria using iterative algorithm
534    pub fn find_quantum_nash_equilibria(&mut self) -> QuantRS2Result<Vec<GameOutcome>> {
535        let mut equilibria = Vec::new();
536
537        // Grid search over strategy space
538        let theta_steps = 10;
539        let phi_steps = 10;
540
541        for i in 0..theta_steps {
542            for j in 0..phi_steps {
543                let theta = (i as f64) * std::f64::consts::PI / (theta_steps as f64);
544                let phi = (j as f64) * 2.0 * std::f64::consts::PI / (phi_steps as f64);
545
546                // Set strategies for all players
547                for player in &mut self.players {
548                    player.strategy = QuantumStrategy::Superposition { theta, phi };
549                }
550
551                // Play game and check if outcome is equilibrium
552                let outcome = self.play_game()?;
553                if outcome.is_nash_equilibrium {
554                    equilibria.push(outcome);
555                }
556            }
557        }
558
559        Ok(equilibria)
560    }
561
562    /// Compute quantum advantage over classical game
563    pub fn quantum_advantage(&mut self) -> QuantRS2Result<f64> {
564        // Play quantum version
565        let quantum_outcome = self.play_game()?;
566        let quantum_payoffs = quantum_outcome.payoff_matrix.unwrap_or_default();
567        let quantum_total = quantum_payoffs.iter().sum::<f64>();
568
569        // Compare with classical Nash equilibrium
570        let classical_total = self.compute_classical_nash_payoff()?;
571
572        Ok(quantum_total - classical_total)
573    }
574
575    /// Compute payoff at classical Nash equilibrium
576    fn compute_classical_nash_payoff(&self) -> QuantRS2Result<f64> {
577        // For prisoner's dilemma: classical Nash is (Defect, Defect) = (1, 1)
578        // Both players get payoff of 1
579        match self.game_type {
580            GameType::QuantumPrisonersDilemma => Ok(2.0), // 1 + 1
581            GameType::QuantumCoordination => Ok(0.0),     // Miscoordination
582            _ => Ok(0.0),
583        }
584    }
585}
586
587/// Quantum mechanism design for multi-player games
588#[derive(Debug, Clone)]
589pub struct QuantumMechanism {
590    /// Number of players
591    pub num_players: usize,
592    /// Mechanism type
593    pub mechanism_type: String,
594    /// Quantum circuit implementing the mechanism
595    pub circuit: Option<Array2<Complex64>>,
596    /// Revenue function for the mechanism designer
597    pub revenue_function: Option<fn(&[f64]) -> f64>,
598}
599
600impl QuantumMechanism {
601    /// Create quantum auction mechanism
602    pub fn quantum_auction_mechanism(num_bidders: usize) -> Self {
603        Self {
604            num_players: num_bidders,
605            mechanism_type: "Quantum Auction".to_string(),
606            circuit: None,
607            revenue_function: Some(|bids| bids.iter().sum::<f64>() * 0.1), // 10% commission
608        }
609    }
610
611    /// Create quantum voting mechanism
612    pub fn quantum_voting_mechanism(num_voters: usize) -> Self {
613        Self {
614            num_players: num_voters,
615            mechanism_type: "Quantum Voting".to_string(),
616            circuit: None,
617            revenue_function: None, // No revenue in voting
618        }
619    }
620
621    /// Design optimal quantum mechanism
622    pub fn design_optimal_mechanism(&mut self) -> QuantRS2Result<Array2<Complex64>> {
623        // This would implement the quantum mechanism design algorithm
624        // For now, return identity transformation
625        let dim = 1 << self.num_players;
626        Ok(Array2::eye(dim))
627    }
628
629    /// Verify mechanism properties (incentive compatibility, individual rationality)
630    pub fn verify_mechanism_properties(&self) -> QuantRS2Result<(bool, bool)> {
631        // Simplified verification
632        // In practice, this would check incentive compatibility and individual rationality
633
634        let incentive_compatible = true; // Assume true for now
635        let individually_rational = true; // Assume true for now
636
637        Ok((incentive_compatible, individually_rational))
638    }
639}
640
641#[cfg(test)]
642mod tests {
643    use super::*;
644
645    #[test]
646    fn test_quantum_player_creation() {
647        let strategy = QuantumStrategy::Superposition {
648            theta: std::f64::consts::PI / 4.0,
649            phi: 0.0,
650        };
651        let player = QuantumPlayer::new(0, strategy.clone());
652
653        assert_eq!(player.id, 0);
654        assert_eq!(player.strategy, strategy);
655        assert!(player.state.is_none());
656    }
657
658    #[test]
659    fn test_quantum_state_preparation() {
660        let mut player =
661            QuantumPlayer::new(0, QuantumStrategy::Classical(std::f64::consts::PI / 4.0));
662        let state = player.prepare_quantum_state().unwrap();
663
664        assert_eq!(state.len(), 2);
665        assert!(state[0].norm() > 0.0);
666        assert!(player.state.is_some());
667    }
668
669    #[test]
670    fn test_quantum_prisoners_dilemma() {
671        let game = QuantumGame::quantum_prisoners_dilemma().unwrap();
672
673        assert_eq!(game.game_type, GameType::QuantumPrisonersDilemma);
674        assert_eq!(game.num_players, 2);
675        assert_eq!(game.payoff_matrices.len(), 2);
676        assert!(game.entanglement_operator.is_some());
677    }
678
679    #[test]
680    fn test_quantum_coordination_game() {
681        let game = QuantumGame::quantum_coordination_game().unwrap();
682
683        assert_eq!(game.game_type, GameType::QuantumCoordination);
684        assert_eq!(game.num_players, 2);
685        assert_eq!(game.payoff_matrices.len(), 2);
686    }
687
688    #[test]
689    fn test_game_with_players() {
690        let mut game = QuantumGame::quantum_prisoners_dilemma().unwrap();
691
692        let player1 = QuantumPlayer::new(0, QuantumStrategy::Classical(0.0));
693        let player2 = QuantumPlayer::new(1, QuantumStrategy::Classical(std::f64::consts::PI));
694
695        game.add_player(player1).unwrap();
696        game.add_player(player2).unwrap();
697
698        let outcome = game.play_game().unwrap();
699        assert_eq!(outcome.classical_outcomes.len(), 2);
700        assert!(!outcome.probabilities.is_empty());
701    }
702
703    #[test]
704    fn test_entanglement_operator() {
705        let entanglement = QuantumGame::create_entanglement_operator(std::f64::consts::PI / 2.0);
706
707        assert_eq!(entanglement.dim(), (4, 4));
708
709        // Check unitarity (U†U = I)
710        let conjugate_transpose = entanglement.t().mapv(|x| x.conj());
711        let product = conjugate_transpose.dot(&entanglement);
712
713        for i in 0..4 {
714            for j in 0..4 {
715                let expected = if i == j { 1.0 } else { 0.0 };
716                assert!((product[[i, j]].norm() - expected).abs() < 1e-10);
717            }
718        }
719    }
720
721    #[test]
722    fn test_nash_equilibrium_detection() {
723        let game = QuantumGame::quantum_prisoners_dilemma().unwrap();
724
725        // (Defect, Defect) should be Nash equilibrium in prisoner's dilemma
726        let is_nash = game.is_nash_equilibrium(&[1, 1], &[1.0, 1.0]).unwrap();
727        assert!(is_nash);
728
729        // (Cooperate, Cooperate) should not be Nash equilibrium
730        let is_nash = game.is_nash_equilibrium(&[0, 0], &[3.0, 3.0]).unwrap();
731        assert!(!is_nash);
732    }
733
734    #[test]
735    fn test_quantum_mechanism_creation() {
736        let mechanism = QuantumMechanism::quantum_auction_mechanism(3);
737
738        assert_eq!(mechanism.num_players, 3);
739        assert_eq!(mechanism.mechanism_type, "Quantum Auction");
740        assert!(mechanism.revenue_function.is_some());
741    }
742
743    #[test]
744    fn test_mechanism_verification() {
745        let mechanism = QuantumMechanism::quantum_voting_mechanism(5);
746        let (ic, ir) = mechanism.verify_mechanism_properties().unwrap();
747
748        assert!(ic); // Incentive compatible
749        assert!(ir); // Individually rational
750    }
751
752    #[test]
753    fn test_quantum_advantage_calculation() {
754        let mut game = QuantumGame::quantum_prisoners_dilemma().unwrap();
755
756        let player1 = QuantumPlayer::new(
757            0,
758            QuantumStrategy::Superposition {
759                theta: std::f64::consts::PI / 4.0,
760                phi: 0.0,
761            },
762        );
763        let player2 = QuantumPlayer::new(
764            1,
765            QuantumStrategy::Superposition {
766                theta: std::f64::consts::PI / 4.0,
767                phi: 0.0,
768            },
769        );
770
771        game.add_player(player1).unwrap();
772        game.add_player(player2).unwrap();
773
774        let advantage = game.quantum_advantage().unwrap();
775        // Quantum strategies can potentially achieve better outcomes than classical Nash
776        // The exact value depends on the strategy profile
777        assert!(advantage.is_finite());
778    }
779}