1use crate::error::{QuantRS2Error, QuantRS2Result};
9use scirs2_core::ndarray::{Array1, Array2};
10use scirs2_core::Complex64;
11use std::collections::HashMap;
12
13#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum GameType {
16 QuantumPrisonersDilemma,
18 QuantumBattleOfSexes,
20 QuantumAuction,
22 QuantumCoordination,
24 QuantumMinorityGame,
26 Custom,
28}
29
30#[derive(Debug, Clone, PartialEq)]
32pub enum QuantumStrategy {
33 Classical(f64), Superposition { theta: f64, phi: f64 }, Entangled,
39 Mixed(Vec<(f64, QuantumStrategy)>), }
42
43#[derive(Debug, Clone)]
45pub struct QuantumPlayer {
46 pub id: usize,
48 pub strategy: QuantumStrategy,
50 pub state: Option<Array1<Complex64>>,
52 pub utility_params: HashMap<String, f64>,
54}
55
56impl QuantumPlayer {
57 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 pub fn set_utility_param(&mut self, param: String, value: f64) {
69 self.utility_params.insert(param, value);
70 }
71
72 pub fn prepare_quantum_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
74 match self.strategy {
75 QuantumStrategy::Classical(theta) => {
76 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 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 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 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 pub fn compute_utility(&self, game_outcome: &GameOutcome) -> f64 {
120 match &game_outcome.payoff_matrix {
121 Some(payoffs) => {
122 payoffs.iter().sum::<f64>() / payoffs.len() as f64
124 }
125 None => 0.0,
126 }
127 }
128}
129
130#[derive(Debug, Clone)]
132pub struct GameOutcome {
133 pub classical_outcomes: Vec<usize>,
135 pub probabilities: Array1<f64>,
137 pub payoff_matrix: Option<Vec<f64>>,
139 pub is_nash_equilibrium: bool,
141}
142
143#[derive(Debug, Clone)]
145pub struct QuantumGame {
146 pub game_type: GameType,
148 pub num_players: usize,
150 pub players: Vec<QuantumPlayer>,
152 pub game_circuit: Option<Array2<Complex64>>,
154 pub payoff_matrices: Vec<Array2<f64>>,
156 pub entanglement_operator: Option<Array2<Complex64>>,
158}
159
160impl QuantumGame {
161 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 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 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 pub fn quantum_prisoners_dilemma() -> QuantRS2Result<Self> {
206 let mut game = Self::new(GameType::QuantumPrisonersDilemma, 2);
207
208 let payoff_p1 = Array2::from_shape_vec(
211 (2, 2),
212 vec![3.0, 0.0, 5.0, 1.0], )
214 .unwrap();
215
216 let payoff_p2 = Array2::from_shape_vec(
217 (2, 2),
218 vec![3.0, 5.0, 0.0, 1.0], )
220 .unwrap();
221
222 game.set_payoff_matrix(0, payoff_p1)?;
223 game.set_payoff_matrix(1, payoff_p2)?;
224
225 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 pub fn quantum_coordination_game() -> QuantRS2Result<Self> {
234 let mut game = Self::new(GameType::QuantumCoordination, 2);
235
236 let payoff_p1 = Array2::from_shape_vec(
238 (2, 2),
239 vec![2.0, 0.0, 0.0, 1.0], )
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 pub fn quantum_auction(num_bidders: usize) -> QuantRS2Result<Self> {
253 let mut game = Self::new(GameType::QuantumAuction, num_bidders);
254
255 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], )
261 .unwrap();
262
263 game.set_payoff_matrix(i, payoff)?;
264 }
265
266 Ok(game)
267 }
268
269 fn create_entanglement_operator(gamma: f64) -> Array2<Complex64> {
271 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 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 let mut joint_state = self.prepare_joint_state()?;
310
311 if let Some(entanglement_op) = &self.entanglement_operator {
313 joint_state = entanglement_op.dot(&joint_state);
314 }
315
316 joint_state = self.apply_player_strategies(joint_state)?;
318
319 self.measure_game_outcome(joint_state)
321 }
322
323 fn prepare_joint_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
325 let total_dim = 1 << self.num_players; let mut joint_state = Array1::zeros(total_dim);
327
328 joint_state[0] = Complex64::new(1.0, 0.0);
330
331 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 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 let mut new_state = joint_state.clone();
354
355 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 fn apply_player_strategies(
370 &self,
371 mut joint_state: Array1<Complex64>,
372 ) -> QuantRS2Result<Array1<Complex64>> {
373 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 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 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 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 }
426 QuantumStrategy::Mixed(_strategies) => {
427 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 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 for i in 0..num_outcomes {
447 probabilities[i] = joint_state[i].norm_sqr();
448 }
449
450 let outcome_index = self.sample_outcome(&probabilities)?;
452
453 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 let payoffs = self.compute_payoffs(&classical_outcomes)?;
462
463 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 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 Ok(probabilities.len() - 1)
491 }
492
493 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 let player_action = outcomes[player_idx];
506 let opponent_action = outcomes[1 - player_idx % 2]; let payoff = payoff_matrix[[player_action, opponent_action]];
509 payoffs.push(payoff);
510 }
511
512 Ok(payoffs)
513 }
514
515 fn is_nash_equilibrium(&self, outcomes: &[usize], _payoffs: &[f64]) -> QuantRS2Result<bool> {
517 match self.game_type {
523 GameType::QuantumPrisonersDilemma => {
524 Ok(outcomes == &[1, 1]) }
526 GameType::QuantumCoordination => {
527 Ok(outcomes[0] == outcomes[1]) }
529 _ => Ok(false),
530 }
531 }
532
533 pub fn find_quantum_nash_equilibria(&mut self) -> QuantRS2Result<Vec<GameOutcome>> {
535 let mut equilibria = Vec::new();
536
537 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 for player in &mut self.players {
548 player.strategy = QuantumStrategy::Superposition { theta, phi };
549 }
550
551 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 pub fn quantum_advantage(&mut self) -> QuantRS2Result<f64> {
564 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 let classical_total = self.compute_classical_nash_payoff()?;
571
572 Ok(quantum_total - classical_total)
573 }
574
575 fn compute_classical_nash_payoff(&self) -> QuantRS2Result<f64> {
577 match self.game_type {
580 GameType::QuantumPrisonersDilemma => Ok(2.0), GameType::QuantumCoordination => Ok(0.0), _ => Ok(0.0),
583 }
584 }
585}
586
587#[derive(Debug, Clone)]
589pub struct QuantumMechanism {
590 pub num_players: usize,
592 pub mechanism_type: String,
594 pub circuit: Option<Array2<Complex64>>,
596 pub revenue_function: Option<fn(&[f64]) -> f64>,
598}
599
600impl QuantumMechanism {
601 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), }
609 }
610
611 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, }
619 }
620
621 pub fn design_optimal_mechanism(&mut self) -> QuantRS2Result<Array2<Complex64>> {
623 let dim = 1 << self.num_players;
626 Ok(Array2::eye(dim))
627 }
628
629 pub fn verify_mechanism_properties(&self) -> QuantRS2Result<(bool, bool)> {
631 let incentive_compatible = true; let individually_rational = true; 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 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 let is_nash = game.is_nash_equilibrium(&[1, 1], &[1.0, 1.0]).unwrap();
727 assert!(is_nash);
728
729 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); assert!(ir); }
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 assert!(advantage.is_finite());
778 }
779}