use crate::error::{QuantRS2Error, QuantRS2Result};
use scirs2_core::ndarray::{Array1, Array2};
use scirs2_core::Complex64;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GameType {
QuantumPrisonersDilemma,
QuantumBattleOfSexes,
QuantumAuction,
QuantumCoordination,
QuantumMinorityGame,
Custom,
}
#[derive(Debug, Clone, PartialEq)]
pub enum QuantumStrategy {
Classical(f64),
Superposition { theta: f64, phi: f64 },
Entangled,
Mixed(Vec<(f64, Self)>),
}
#[derive(Debug, Clone)]
pub struct QuantumPlayer {
pub id: usize,
pub strategy: QuantumStrategy,
pub state: Option<Array1<Complex64>>,
pub utility_params: HashMap<String, f64>,
}
impl QuantumPlayer {
pub fn new(id: usize, strategy: QuantumStrategy) -> Self {
Self {
id,
strategy,
state: None,
utility_params: HashMap::new(),
}
}
pub fn set_utility_param(&mut self, param: String, value: f64) {
self.utility_params.insert(param, value);
}
pub fn prepare_quantum_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
match self.strategy {
QuantumStrategy::Classical(theta) => {
let state = Array1::from_vec(vec![
Complex64::new(theta.cos(), 0.0),
Complex64::new(theta.sin(), 0.0),
]);
self.state = Some(state.clone());
Ok(state)
}
QuantumStrategy::Superposition { theta, phi } => {
let state = Array1::from_vec(vec![
Complex64::new((theta / 2.0).cos(), 0.0),
Complex64::new(
(theta / 2.0).sin() * phi.cos(),
(theta / 2.0).sin() * phi.sin(),
),
]);
self.state = Some(state.clone());
Ok(state)
}
QuantumStrategy::Entangled => {
let state = Array1::from_vec(vec![
Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
]);
self.state = Some(state.clone());
Ok(state)
}
QuantumStrategy::Mixed(_) => {
let state = Array1::from_vec(vec![
Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
]);
self.state = Some(state.clone());
Ok(state)
}
}
}
pub fn compute_utility(&self, game_outcome: &GameOutcome) -> f64 {
match &game_outcome.payoff_matrix {
Some(payoffs) => payoffs.iter().sum::<f64>() / payoffs.len() as f64,
None => 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct GameOutcome {
pub classical_outcomes: Vec<usize>,
pub probabilities: Array1<f64>,
pub payoff_matrix: Option<Vec<f64>>,
pub is_nash_equilibrium: bool,
}
#[derive(Debug, Clone)]
pub struct QuantumGame {
pub game_type: GameType,
pub num_players: usize,
pub players: Vec<QuantumPlayer>,
pub game_circuit: Option<Array2<Complex64>>,
pub payoff_matrices: Vec<Array2<f64>>,
pub entanglement_operator: Option<Array2<Complex64>>,
}
impl QuantumGame {
pub fn new(game_type: GameType, num_players: usize) -> Self {
let players = Vec::new();
let payoff_matrices = vec![Array2::zeros((2, 2)); num_players];
Self {
game_type,
num_players,
players,
game_circuit: None,
payoff_matrices,
entanglement_operator: None,
}
}
pub fn add_player(&mut self, player: QuantumPlayer) -> QuantRS2Result<()> {
if self.players.len() >= self.num_players {
return Err(QuantRS2Error::InvalidInput(
"Maximum number of players reached".to_string(),
));
}
self.players.push(player);
Ok(())
}
pub fn set_payoff_matrix(
&mut self,
player_id: usize,
payoffs: Array2<f64>,
) -> QuantRS2Result<()> {
if player_id >= self.num_players {
return Err(QuantRS2Error::InvalidInput(
"Player ID out of bounds".to_string(),
));
}
self.payoff_matrices[player_id] = payoffs;
Ok(())
}
pub fn quantum_prisoners_dilemma() -> QuantRS2Result<Self> {
let mut game = Self::new(GameType::QuantumPrisonersDilemma, 2);
let payoff_p1 = Array2::from_shape_vec((2, 2), vec![3.0, 0.0, 5.0, 1.0]).map_err(|e| {
QuantRS2Error::InvalidInput(format!("Failed to create payoff matrix: {e}"))
})?;
let payoff_p2 = Array2::from_shape_vec((2, 2), vec![3.0, 5.0, 0.0, 1.0]).map_err(|e| {
QuantRS2Error::InvalidInput(format!("Failed to create payoff matrix: {e}"))
})?;
game.set_payoff_matrix(0, payoff_p1)?;
game.set_payoff_matrix(1, payoff_p2)?;
let entanglement = Self::create_entanglement_operator(std::f64::consts::PI / 2.0)?;
game.entanglement_operator = Some(entanglement);
Ok(game)
}
pub fn quantum_coordination_game() -> QuantRS2Result<Self> {
let mut game = Self::new(GameType::QuantumCoordination, 2);
let payoff_p1 = Array2::from_shape_vec((2, 2), vec![2.0, 0.0, 0.0, 1.0]).map_err(|e| {
QuantRS2Error::InvalidInput(format!("Failed to create payoff matrix: {e}"))
})?;
let payoff_p2 = payoff_p1.clone();
game.set_payoff_matrix(0, payoff_p1)?;
game.set_payoff_matrix(1, payoff_p2)?;
Ok(game)
}
pub fn quantum_auction(num_bidders: usize) -> QuantRS2Result<Self> {
let mut game = Self::new(GameType::QuantumAuction, num_bidders);
for i in 0..num_bidders {
let payoff = Array2::from_shape_vec((2, 2), vec![1.0, 0.5, 2.0, 0.0]).map_err(|e| {
QuantRS2Error::InvalidInput(format!("Failed to create payoff matrix: {e}"))
})?;
game.set_payoff_matrix(i, payoff)?;
}
Ok(game)
}
fn create_entanglement_operator(gamma: f64) -> QuantRS2Result<Array2<Complex64>> {
let cos_g = (gamma / 2.0).cos();
let sin_g = (gamma / 2.0).sin();
Array2::from_shape_vec(
(4, 4),
vec![
Complex64::new(cos_g, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, sin_g),
Complex64::new(0.0, 0.0),
Complex64::new(cos_g, 0.0),
Complex64::new(0.0, -sin_g),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, -sin_g),
Complex64::new(cos_g, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, sin_g),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(cos_g, 0.0),
],
)
.map_err(|e| {
QuantRS2Error::InvalidInput(format!("Failed to create entanglement operator: {e}"))
})
}
pub fn play_game(&mut self) -> QuantRS2Result<GameOutcome> {
if self.players.len() != self.num_players {
return Err(QuantRS2Error::InvalidInput(
"Not all players have joined the game".to_string(),
));
}
let mut joint_state = self.prepare_joint_state()?;
if let Some(entanglement_op) = &self.entanglement_operator {
joint_state = entanglement_op.dot(&joint_state);
}
joint_state = self.apply_player_strategies(joint_state)?;
self.measure_game_outcome(joint_state)
}
fn prepare_joint_state(&mut self) -> QuantRS2Result<Array1<Complex64>> {
let total_dim = 1 << self.num_players;
let mut joint_state = Array1::zeros(total_dim);
joint_state[0] = Complex64::new(1.0, 0.0);
let mut player_states = Vec::new();
for player in &mut self.players {
let player_state = player.prepare_quantum_state()?;
player_states.push(player_state);
}
for (i, player_state) in player_states.into_iter().enumerate() {
joint_state = Self::tensor_product_player_state(joint_state, player_state, i)?;
}
Ok(joint_state)
}
fn tensor_product_player_state(
joint_state: Array1<Complex64>,
player_state: Array1<Complex64>,
player_index: usize,
) -> QuantRS2Result<Array1<Complex64>> {
let mut new_state = joint_state;
for i in 0..new_state.len() {
let bit = (i >> player_index) & 1;
if bit == 0 {
new_state[i] *= player_state[0];
} else {
new_state[i] *= player_state[1];
}
}
Ok(new_state)
}
fn apply_player_strategies(
&self,
mut joint_state: Array1<Complex64>,
) -> QuantRS2Result<Array1<Complex64>> {
for (i, player) in self.players.iter().enumerate() {
joint_state = Self::apply_single_player_strategy(joint_state, &player.strategy, i)?;
}
Ok(joint_state)
}
fn apply_single_player_strategy(
mut joint_state: Array1<Complex64>,
strategy: &QuantumStrategy,
player_index: usize,
) -> QuantRS2Result<Array1<Complex64>> {
match strategy {
QuantumStrategy::Classical(theta) => {
let cos_theta = theta.cos();
let sin_theta = theta.sin();
for i in 0..joint_state.len() {
let bit = (i >> player_index) & 1;
if bit == 1 {
joint_state[i] *= Complex64::new(cos_theta, sin_theta);
}
}
}
QuantumStrategy::Superposition { theta, phi } => {
let half_theta = theta / 2.0;
let cos_half = half_theta.cos();
let sin_half = half_theta.sin();
let mut new_state = Array1::zeros(joint_state.len());
for i in 0..joint_state.len() {
let bit = (i >> player_index) & 1;
let flipped_i = i ^ (1 << player_index);
if bit == 0 {
new_state[i] += cos_half * joint_state[i];
new_state[flipped_i] +=
sin_half * Complex64::new(phi.cos(), phi.sin()) * joint_state[i];
}
}
joint_state = new_state;
}
QuantumStrategy::Entangled => {}
QuantumStrategy::Mixed(_strategies) => {
let mut new_state = joint_state.clone();
for i in 0..new_state.len() {
new_state[i] *= Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0);
}
joint_state = new_state;
}
}
Ok(joint_state)
}
fn measure_game_outcome(&self, joint_state: Array1<Complex64>) -> QuantRS2Result<GameOutcome> {
let num_outcomes = joint_state.len();
let mut probabilities = Array1::zeros(num_outcomes);
for i in 0..num_outcomes {
probabilities[i] = joint_state[i].norm_sqr();
}
let outcome_index = Self::sample_outcome(&probabilities)?;
let mut classical_outcomes = Vec::new();
for player_idx in 0..self.num_players {
let bit = (outcome_index >> player_idx) & 1;
classical_outcomes.push(bit);
}
let payoffs = self.compute_payoffs(&classical_outcomes)?;
let is_nash = self.is_nash_equilibrium(&classical_outcomes, &payoffs)?;
Ok(GameOutcome {
classical_outcomes,
probabilities,
payoff_matrix: Some(payoffs),
is_nash_equilibrium: is_nash,
})
}
fn sample_outcome(probabilities: &Array1<f64>) -> QuantRS2Result<usize> {
let mut rng = thread_rng();
use scirs2_core::random::prelude::*;
let random_value: f64 = rng.random();
let mut cumulative = 0.0;
for (i, &prob) in probabilities.iter().enumerate() {
cumulative += prob;
if random_value <= cumulative {
return Ok(i);
}
}
Ok(probabilities.len() - 1)
}
fn compute_payoffs(&self, outcomes: &[usize]) -> QuantRS2Result<Vec<f64>> {
let mut payoffs = Vec::new();
for (player_idx, payoff_matrix) in self.payoff_matrices.iter().enumerate() {
if outcomes.len() < 2 {
return Err(QuantRS2Error::InvalidInput(
"Need at least 2 players for payoff calculation".to_string(),
));
}
let player_action = outcomes[player_idx];
let opponent_action = outcomes[1 - player_idx % 2];
let payoff = payoff_matrix[[player_action, opponent_action]];
payoffs.push(payoff);
}
Ok(payoffs)
}
fn is_nash_equilibrium(&self, outcomes: &[usize], _payoffs: &[f64]) -> QuantRS2Result<bool> {
match self.game_type {
GameType::QuantumPrisonersDilemma => Ok(outcomes == &[1, 1]),
GameType::QuantumCoordination => Ok(outcomes[0] == outcomes[1]),
_ => Ok(false),
}
}
pub fn find_quantum_nash_equilibria(&mut self) -> QuantRS2Result<Vec<GameOutcome>> {
let mut equilibria = Vec::new();
let theta_steps = 10;
let phi_steps = 10;
for i in 0..theta_steps {
for j in 0..phi_steps {
let theta = (i as f64) * std::f64::consts::PI / (theta_steps as f64);
let phi = (j as f64) * 2.0 * std::f64::consts::PI / (phi_steps as f64);
for player in &mut self.players {
player.strategy = QuantumStrategy::Superposition { theta, phi };
}
let outcome = self.play_game()?;
if outcome.is_nash_equilibrium {
equilibria.push(outcome);
}
}
}
Ok(equilibria)
}
pub fn quantum_advantage(&mut self) -> QuantRS2Result<f64> {
let quantum_outcome = self.play_game()?;
let quantum_payoffs = quantum_outcome.payoff_matrix.unwrap_or_default();
let quantum_total = quantum_payoffs.iter().sum::<f64>();
let classical_total = self.compute_classical_nash_payoff()?;
Ok(quantum_total - classical_total)
}
const fn compute_classical_nash_payoff(&self) -> QuantRS2Result<f64> {
match self.game_type {
GameType::QuantumPrisonersDilemma => Ok(2.0),
GameType::QuantumCoordination | _ => Ok(0.0),
}
}
}
#[derive(Debug, Clone)]
pub struct QuantumMechanism {
pub num_players: usize,
pub mechanism_type: String,
pub circuit: Option<Array2<Complex64>>,
pub revenue_function: Option<fn(&[f64]) -> f64>,
}
impl QuantumMechanism {
pub fn quantum_auction_mechanism(num_bidders: usize) -> Self {
Self {
num_players: num_bidders,
mechanism_type: "Quantum Auction".to_string(),
circuit: None,
revenue_function: Some(|bids| bids.iter().sum::<f64>() * 0.1),
}
}
pub fn quantum_voting_mechanism(num_voters: usize) -> Self {
Self {
num_players: num_voters,
mechanism_type: "Quantum Voting".to_string(),
circuit: None,
revenue_function: None,
}
}
pub fn design_optimal_mechanism(&mut self) -> QuantRS2Result<Array2<Complex64>> {
let dim = 1 << self.num_players;
Ok(Array2::eye(dim))
}
pub const fn verify_mechanism_properties(&self) -> QuantRS2Result<(bool, bool)> {
let incentive_compatible = true;
let individually_rational = true;
Ok((incentive_compatible, individually_rational))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quantum_player_creation() {
let strategy = QuantumStrategy::Superposition {
theta: std::f64::consts::PI / 4.0,
phi: 0.0,
};
let player = QuantumPlayer::new(0, strategy.clone());
assert_eq!(player.id, 0);
assert_eq!(player.strategy, strategy);
assert!(player.state.is_none());
}
#[test]
fn test_quantum_state_preparation() {
let mut player =
QuantumPlayer::new(0, QuantumStrategy::Classical(std::f64::consts::PI / 4.0));
let state = player
.prepare_quantum_state()
.expect("failed to prepare quantum state");
assert_eq!(state.len(), 2);
assert!(state[0].norm() > 0.0);
assert!(player.state.is_some());
}
#[test]
fn test_quantum_prisoners_dilemma() {
let game = QuantumGame::quantum_prisoners_dilemma()
.expect("failed to create quantum prisoners dilemma");
assert_eq!(game.game_type, GameType::QuantumPrisonersDilemma);
assert_eq!(game.num_players, 2);
assert_eq!(game.payoff_matrices.len(), 2);
assert!(game.entanglement_operator.is_some());
}
#[test]
fn test_quantum_coordination_game() {
let game = QuantumGame::quantum_coordination_game()
.expect("failed to create quantum coordination game");
assert_eq!(game.game_type, GameType::QuantumCoordination);
assert_eq!(game.num_players, 2);
assert_eq!(game.payoff_matrices.len(), 2);
}
#[test]
fn test_game_with_players() {
let mut game = QuantumGame::quantum_prisoners_dilemma()
.expect("failed to create quantum prisoners dilemma");
let player1 = QuantumPlayer::new(0, QuantumStrategy::Classical(0.0));
let player2 = QuantumPlayer::new(1, QuantumStrategy::Classical(std::f64::consts::PI));
game.add_player(player1).expect("failed to add player1");
game.add_player(player2).expect("failed to add player2");
let outcome = game.play_game().expect("failed to play game");
assert_eq!(outcome.classical_outcomes.len(), 2);
assert!(!outcome.probabilities.is_empty());
}
#[test]
fn test_entanglement_operator() {
let entanglement = QuantumGame::create_entanglement_operator(std::f64::consts::PI / 2.0)
.expect("failed to create entanglement operator");
assert_eq!(entanglement.dim(), (4, 4));
let conjugate_transpose = entanglement.t().mapv(|x| x.conj());
let product = conjugate_transpose.dot(&entanglement);
for i in 0..4 {
for j in 0..4 {
let expected = if i == j { 1.0 } else { 0.0 };
assert!((product[[i, j]].norm() - expected).abs() < 1e-10);
}
}
}
#[test]
fn test_nash_equilibrium_detection() {
let game = QuantumGame::quantum_prisoners_dilemma()
.expect("failed to create quantum prisoners dilemma");
let is_nash = game
.is_nash_equilibrium(&[1, 1], &[1.0, 1.0])
.expect("failed to check Nash equilibrium");
assert!(is_nash);
let is_nash = game
.is_nash_equilibrium(&[0, 0], &[3.0, 3.0])
.expect("failed to check Nash equilibrium");
assert!(!is_nash);
}
#[test]
fn test_quantum_mechanism_creation() {
let mechanism = QuantumMechanism::quantum_auction_mechanism(3);
assert_eq!(mechanism.num_players, 3);
assert_eq!(mechanism.mechanism_type, "Quantum Auction");
assert!(mechanism.revenue_function.is_some());
}
#[test]
fn test_mechanism_verification() {
let mechanism = QuantumMechanism::quantum_voting_mechanism(5);
let (ic, ir) = mechanism
.verify_mechanism_properties()
.expect("failed to verify mechanism properties");
assert!(ic);
assert!(ir);
}
#[test]
fn test_quantum_advantage_calculation() {
let mut game = QuantumGame::quantum_prisoners_dilemma()
.expect("failed to create quantum prisoners dilemma");
let player1 = QuantumPlayer::new(
0,
QuantumStrategy::Superposition {
theta: std::f64::consts::PI / 4.0,
phi: 0.0,
},
);
let player2 = QuantumPlayer::new(
1,
QuantumStrategy::Superposition {
theta: std::f64::consts::PI / 4.0,
phi: 0.0,
},
);
game.add_player(player1).expect("failed to add player1");
game.add_player(player2).expect("failed to add player2");
let advantage = game
.quantum_advantage()
.expect("failed to calculate quantum advantage");
assert!(advantage.is_finite());
}
}