AUTOR:
André Melo
DATA DE PUBLICAÇÃO:
16 de Setembro de 2023

Tempo de leitura: 45 minutos.

1. Introdução

A teoria dos jogos é um ramo da matemática que explora as interações estratégicas em que as decisões de um indivíduo são influenciadas pelo conflito e cooperação de outros participantes. Em relação ao campo das ciências econômicas, essa teoria desempenha um papel fundamental ao analisar como as pessoas realizam escolhas estratégicas diante de objetivos concorrentes em um contexto de escassez.

Uma aplicação interessante da teoria dos jogos na área da economia é a sua combinação com simulações de aprendizado. Por exemplo, em um cenário em que diferentes empresas competem para estabelecer preços em um mercado, é possível utilizar a teoria dos jogos em conjunto com modelos de aprendizado. Nesses modelos, as empresas podem aprender ao longo do tempo a tomar decisões estratégicas mais eficientes e adaptar suas estratégias com base nas escolhas e resultados passados. Dessa forma, as empresas podem ajustar gradualmente suas ações para obter melhores resultados e alcançar equilíbrios de longo prazo em um ambiente competitivo.

Este tutorial tem como objetivo ensinar como aplicar a teoria dos jogos no ambiente R, utilizando o pacote Rgamer, desenvolvido por Yusei Yanai, Ph.D. em Ciência Política, e Yoshio Kamijo, Especialista em Economia Experimental, Teoria dos Jogos, Teoria Comportamental dos Jogos e Design do Futuro. Desse modo, através da integração de funções de modelos de aprendizado, exploraremos a teoria dos jogos e sua aplicação prática. O pacote oferece representações visuais de jogos para dois ou mais jogadores e possibilita encontrar equilíbrios de Nash, proporcionando uma compreensão mais profunda dos conceitos fundamentais no contexto das Ciências Econômicas. Com o Rgamer, tem-se disponível uma ferramenta poderosa para a análise e simulação de interações estratégicas, tornando o estudo do assunto ainda mais acessível e abrangente.

1.1 Pacotes

Para realização dos passos seguintes, será necessário a instalação e ativação do pacote:

# install.packages("devtools")
# devtools::install_github("yukiyanai/rgamer")
library(rgamer)
library(utf8)

2. Jogos Simultâneos

Os jogos simultâneos representam uma categoria fundamental na teoria dos jogos, na qual todos os jogadores tomam suas decisões ao mesmo tempo, sem qualquer conhecimento prévio das escolhas dos outros jogadores. No ambiente de programação R, o pacote Rgamer oferece uma ampla gama de recursos que facilitam a modelagem de jogos simultâneos, o cálculo de equilíbrios de Nash, a representação gráfica e a análise de estratégias dominantes.

2.1 Estratégias Puras

O dilema dos prisioneiros é um clássico exemplo de jogo de estratégia pura em teoria dos jogos que envolve dois jogadores que enfrentam uma escolha difícil entre cooperar ou trair o outro jogador. Através da função normal_form() teremos dois exemplos desse tipo forma normal de jogo em dois métodos.

Neste primeiro método, é necessário definir os pagamentos para cada célula da matriz do jogo utilizando o argumento cells, que é configurado como uma lista, no caso list(). Também é necessário especificar os jogadores, que, neste exemplo, são "Bonnie" e "Clyde", utilizando o argumento players, em que as estratégias, "Confessar" e "Não Confessar", respectivamente, são definidas nos argumentos s1 e s2 para eles.

O argumento lógico byrow pode ser configurado como TRUE ou FALSE. Quando definido como TRUE, os valores na lista dentro das células são especificados por linha, seguindo a ordem das estratégias “Confessar” e “Não Confessar”, respectivamente, para cada jogador. Se configurado como FALSE, os valores serão organizados por coluna.

jogo1 <- normal_form(
          players = c("Bonnie", "Clyde"),
          s1 = c("Confessar", "Não Confessar"), 
          s2 = c("Confessar", "Não Confessar"), 
          cells = list(c(-8, -8), 
                       c(0, -15),
                       c(-15, 0), 
                       c(-1, -1)),
          byrow = TRUE)

Para encontrar a solução do primeiro método é necessário a função solve_nfg() e o argumento show_table = TRUE para obter a tabela e o equilíbrio de Nash.

s_jogo1 <- solve_nfg(jogo1, show_table = TRUE)
Pure-strategy NE: [Confessar, Confessar]
Clyde
strategy Confessar Não Confessar
Bonnie Confessar -8^, -8^ 0^, -15
Não Confessar -15, 0^ -1, -1

Considerando o fator “traição”, escolher confessar é sempre a melhor opção para Bonnie, independentemente da escolha de Clyde. A estratégia de não confessar pode levar a resultados piores se o outro jogador escolher confessar. Portanto, confessar é a estratégia dominante para ambos, incentivando a cooperação mútua.

2.2 Estratégias Dominantes

As estratégias estritamente dominantes referem-se a uma situação em que um jogador tem uma estratégia que é sempre melhor do que qualquer outra estratégia que ele possa escolher, independentemente das escolhas dos outros jogadores.

No exemplo a seguir, os jogadores "Pedro" e "Ana" são especificados no argumento players. Neste jogo, ao contrário dos dois exemplos anteriores, cada jogador possui 3 estratégias disponíveis: "Bar", "Museu" e "Café". Dessa forma, será necessário aumentar o número de elementos nas matrizes payoffs1 e payoffs2, agora contendo um total de 9 elementos.

jogo3 <- normal_form(
          players = c("Pedro", "Ana"),
          s1 = c("Bar", "Museu", "Café"), 
          s2 = c("Bar", "Museu", "Café"), 
          payoffs1 = c(6, 2, 1, 
                       6, 5, 1, 
                       4, 2, 3), 
          payoffs2 = c(4, 1, 1, 
                       3, 5, 3, 
                       2, 2, 6))

O argumento lógico mark_br desempenha a função de destacar as melhores respostas (best responses) na tabela de solução. Quando é definido como FALSE, as melhores respostas não são destacadas na tabela. O valor padrão para mark_br é TRUE, o que significa que, caso esse argumento na função não seja incluído na função, a tabela exibirá automaticamente o equilíbrio de Nash.

Nesse caso, o equilíbrio de Nash em conjunto com a mensagem não serão exibidas, já que ao configurar quietly como TRUE, está sendo implicitamente ocultado a mensagem de melhores respostas. Essa configuração flexível permite controlar tanto a exibição da mensagem quanto o destaque do Equilíbrio de Nash, de acordo com as preferências.

s_jogo3 <- solve_nfg(jogo3, 
                     show_table = TRUE, 
                     mark_br = FALSE, 
                     quietly = TRUE)
Ana
strategy Bar Museu Café
Pedro Bar 6, 4 6, 3 4, 2
Museu 2, 1 5, 5 2, 2
Café 1, 1 1, 3 3, 6

Na função dom() com type = "dominant", são identificadas as estratégias estritamente dominantes para cada jogador no jogo. Por meio dessa configuração é possível identificar as estratégias que são sempre a melhor escolha, independentemente das ações tomadas pelos outros jogadores.

Diferentemente do parâmetro quietly encontrado em funções como solve_nfg() e outras do pacote Rgamer, é essencial demonstrar que ao configurar esse parâmetro como FALSE na função dom(), ela passa a exibir uma mensagem que identifica quais estratégias são estritamente dominantes.

dominant_j3 <- dom(jogo3, 
                   type = "dominant", 
                   quietly = FALSE)
Pedro's dominant strategy: Bar
Pedro's weakly dominant strategy: Bar
Ana's dominant strategy: NA
Ana's weakly dominant strategy: NA

No primeiro conjunto de resultados, ao analisar as estratégias estritamente dominantes, identificamos que a estratégia “Bar” é a melhor resposta para Pedro. Nesse contexto, essa estratégia é a escolha que Pedro deve realizar independentemente das escolhas de Ana.

Contudo, é importante ressaltar que a existência de estratégias estritamente dominantes em jogos não é uma característica universal, variando conforme as regras e as interações específicas dentro de cada jogo. Desse modo, quando tais estratégias estão presentes, elas desempenham um papel crucial na análise e na formulação de decisões estratégicas.

2.3 Estratégias Dominadas

A dominância fraca é um dos critérios usados para identificar estratégias não razoáveis ou não ótimas em um jogo. Ela indica a existência de outra estratégia que é, no mínimo, tão boa quanto a estratégia dominada fracamente, mas que pode oferecer um melhor resultado em algumas situações específicas.

No mesmo exemplo, faremos uma alteração no parâmetro type, em que anteriormente estava definido como "dominant", mas agora será configurado como "dominated". O objetivo dessa modificação é identificar estratégias que são dominadas e fracamente dominadas tanto para Pedro quanto para Ana.

dominated_j3 <- dom(jogo3, 
                    type = "dominated", 
                    quietly = FALSE)
Pedro's dominated strategy: Museu, Café
Pedro's weakly dominated strategy: Museu, Café
Ana's dominated strategy: NA
Ana's weakly dominated strategy: NA

Através da análise do segundo conjunto, podemos evidenciar que para o jogador Pedro, as estratégias “Museu” e “Café” são dominadas por outra estratégia, pois sempre há uma escolha alternativa, no caso “Bar”, que leva a um resultado melhor, independentemente da escolha do outro jogador.

Na perspectiva de Ana, em ambos os conjuntos de resultados, não foram encontradas estratégias dominadas nem dominantes, o que indica que suas escolhas são consideradas melhores respostas dadas as escolhas de Pedro.

br_j3 <- solve_nfg(jogo3)
Pure-strategy NE: [Bar, Bar]
Ana
strategy Bar Museu Café
Pedro Bar 6^, 4^ 6^, 3 4^, 2
Museu 2, 1 5, 5^ 2, 2
Café 1, 1 1, 3 3, 6^

Agora, ao verificar as melhores estratégias para o jogador 1 e 2, a mensagem e o destaque do Equilíbrio de Nash podem ser exibidos. Dentro da estrutura da função solve_nfg(), ao remover o parâmetro show_table, a tabela será exibida por padrão, assim como ocorre com outros parâmetros como quietly e mark_br.

2.4 Estratégias Mistas

Imagine um cenário onde o Governo e uma pessoa pobre estão interagindo. O Governo tem duas estratégias possíveis: “Ajuda” e “Não Ajuda”, enquanto a pessoa pobre tem duas estratégias: “Trabalha” e “Vadia”.

jogo4 <- normal_form(
          players = c("Governo", "Pobre"),
          s1 = c("Ajuda", "Não Ajuda"), 
          s2 = c("Trabalha", "Vadia"), 
          payoffs1 = c(3, -1, -1, 0), 
          payoffs2 = c(2, 1, 3, 0))

Nesse jogo, o Governo e o pobre podem optar por estratégias puras, ou seja, escolher uma ação específica com certeza, ou podem utilizar estratégias mistas, ou seja, fazer escolhas ponderadas com base em probabilidades. Através do parâmetro mixed = TRUE, podemos encontrar a solução para esse tipo de jogo para as estratégias mistas.

s_jogo4 <- solve_nfg(jogo4, 
                     mixed = TRUE, 
                     show_table = FALSE)
Pure strategy NE does not exist.
Mixed-strategy NE: [(1/2, 1/2), (1/5, 4/5)]
The obtained mixed-strategy NE might be only a part of the solutions.
Please examine br_plot (best response plot) carefully.

Com a função br_plot (best response plot) ou gráfico de melhores respostas é possível se chegar a maximização do payoff esperado.

s_jogo4$br_plot

A função de payoff em estratégias mistas é usada para representar o resultado esperado que um jogador obtém ao escolher uma determinada ação com probabilidade ou com incerteza. No exemplo a seguir estão as funções de payoff para as estratégias dos jogadores A e B.

  • Jogador: \(\{A, B\}\)

  • Estratégia: \(\{x \in [0, 1], y \in [0, 1] \}\)

  • Payoff: \(\{f_x(x, y) = -3x^2 + (1 - y) \times 2x, f_y(x, y) = -2y^2 + (1 - x) \times 3y\}\)

Desse modo, é possível definir um jogo fornecendo as funções de payoff como vetores de caracteres usando a função normal_form(). Nos parâmetros par1_lim e par2_lim estão configurados os valores entre 0 e 1, o que significa que as estratégias ou escolhas dos jogadores “A” e “B” estão limitadas a esse intervalo. Esses argumentos definem os limites para os eixos, no caso, "x" e "y" contidas em pars.

jogo5 <- normal_form(
          players = c("A", "B"),
          payoffs1 = "-4*x^2 + (1-y) * 2*x",
          payoffs2 = "-2*y^2 + (1-x) * 3*y",
          par1_lim = c(0, 1),
          par2_lim = c(0, 1),
          pars = c("x", "y"))

Com a construção da estrutura do jogo na forma normal, temos a solução dele a apartir da função solve_nfg().

s_jogo5 <- solve_nfg(jogo5)
approximated NE: (0.1, 0.7)
The obtained NE might be only a part of the solutions.
Please examine br_plot (best response plot) carefully.

Nesse método alternativo, é possível definir os resultados de um jogo na forma normal, utilizando function da linguagem R.

  • Jogador: \(\{A, B\}\)

  • Estratégia: \(\{x \in [0, 1], y \in [0, 1] \}\)

  • Payoff: \(\{f_x(x, y) = -nx^a + (b - y) \times px, f_y(x, y) = -my^s + (t - x) \times qy\}\)

# Função do jogador 1
f_x <- function(x, y, a, b, n, p) {
          -n*x^a + (b - y) * p*x
        }

# Função do jogador 2
f_y <- function(x, y, s, t, m, q) {
          -m*y^s + (t - x) * q*y
        }

Após a definição das funções para os jogadores 1 e 2, podemos incorporá-las dentro da normal_form() nos parâmetros payoffs1 e payoffs2.

jogo6 <- normal_form(
          players = c("A", "B"),
          payoffs1 = f_x,
          payoffs2 = f_y,
          par1_lim = c(0, 1),
          par2_lim = c(0, 1),
          pars = c("x", "y"))

Para obter uma solução aproximada numericamente usando o solve_nfg(), é necessário definir os valores dos parâmetros da função que devem ser tratados como constantes, utilizando os argumentos cons1 e cons2, ambos aceitando uma lista de nomes. Além disso, é possível evitar que o gráfico das melhores respostas seja exibido, definindo plot = FALSE.

spf_jogo6 <- solve_nfg(
              game = jogo6,
              cons1 = list(
                a = 2, b = 1, n = 4, p = 2
                ),
              cons2 = list(
                s = 2, t = 1, m = 2, q = 3
                ),
              plot = FALSE)
## approximated NE: (0.1, 0.7)
## The obtained NE might be only a part of the solutions.
## Please examine br_plot (best response plot) carefully.

É possível ajustar a precisão da aproximação através do parâmetro precision (por padrão, precision = 1). Ao aumentar o valor, o cálculo das soluções será feito com maior detalhamento, resultando em uma aproximação mais precisa dos resultados. No entanto, é importante notar que quanto maior o valor desse parâmetro, mais tempo o processo de cálculo pode levar, especialmente para jogos mais complexos com muitas estratégias e jogadores. Portanto, é recomendado ajustar o valor da precisão de acordo com a complexidade do jogo e a necessidade de precisão dos resultados.

s_jogo6 <- solve_nfg(
            game = jogo6,
            cons1 = list(
              a = 2, b = 1, n = 4, p = 2
              ),
            cons2 = list(
              s = 2, t = 1, m = 2, q = 3
              ),
            precision = 3)
approximated NE: (0.077, 0.692)
The obtained NE might be only a part of the solutions.
Please examine br_plot (best response plot) carefully.

Para extrair o gráfico das melhores respostas com o ponto de Equilíbrio de Nash (NE) marcado, é possível utilizar a função br_plot_NE. Esse gráfico mostra como as estratégias dos jogadores podem mudar e se adaptar para alcançar o NE.

s_jogo6$br_plot_NE

Com estratégias mistas, os jogadores podem tomar decisões aleatórias com diferentes probabilidades para cada ação. Isso torna o resultado do jogo mais incerto, pois o desfecho dependerá das escolhas aleatórias feitas por cada jogador.

3. Jogos Sequenciais

Jogos sequenciais são modelos que representam a tomada de decisão em sequência, levando em conta as escolhas dos jogadores e as informações disponíveis. A análise desses jogos envolve a busca por estratégias ótimas e a previsão dos desdobramentos com base nessas estratégias. Na aplicação de jogos sequenciais no R, há funções que auxiliam na construção gráfica da forma extensiva e sequencial do jogo.

Na representação extensiva, podemos utilizar o exemplo mencionado anteriormente da guerra de preços entre dois postos de gasolina. Nessa estrutura de jogo, ao contrário da forma normal, os jogadores tomam decisões em uma ordem específica. Começando com o posto “OilFlex”, que é o jogador inicial e tem um nó na árvore de decisão, e “EconoGas”, que é repetido duas vezes porque possui dois nós, um para cada situação em que pode reagir às ações tomadas pelo outro posto de gasolina. Essa diferenciação ocorre porque o jogador inicial, neste caso, começa a árvore de decisão, enquanto o segundo jogador reage a essa ação inicial. O mesmo princípio se aplica às estratégias no argumento actions, que consiste nas estratégias "Manter"” e "Reduzir" para o jogador 1 e 2.

Ao definir rep(NA, 4) dentro do argumento players, estamos indicando que os nós terminais se repetirão quatro vezes, refletindo as possíveis combinações de ações ao longo da árvore de decisão. A estrutura de payoffs é feita em uma lista com o nome dos jogadores, seguida pela especificação de seus ganhos para cada combinação de ações. Essa estrutura, diferentemente da forma normal, é necessária porque a representação extensiva é mais detalhada e explícita, mostrando a árvore de decisão completa do jogo, passo a passo, com informações sobre as ações tomadas em cada nó da árvore. Dessa forma, os payoffs são especificados separadamente para cada jogador em cada nó, permitindo uma representação detalhada das recompensas em cada cenário do jogo.

jogo7 <- extensive_form(
          players = list("OilFlex",
                         c("EconoGas", "EconoGas"),
                         rep(NA, 4)),
          actions = list(c("Manter", "Reduzir"),
                         c("Manter", "Reduzir"), c("Manter", "Reduzir")),
          payoffs = list(OilFlex = c(50, 30, 60, 40),
                         EconoGas = c(50, 60, 30, 40)),
          show_node_id = FALSE)

Quando show_node_id é definido como FALSE (sendo TRUE o valor padrão), a árvore de decisões é exibida de maneira simplificada, sem a numeração de cada nó na árvore.

Nesse outro método, iniciamos a estruturação do exemplo utilizando a função seq_form(), o que nos permite especificar as estratégias dos jogadores e os payoffs associados a cada combinação de estratégias.

sq_jogo8 <- seq_form(
              players = c("OilFlex", "EconoGas"),
              s1 = c("Manter", "Reduzir"), 
              s2 = c("Manter", "Reduzir"), 
              payoffs1 = c(50, 60, 30, 40),
              payoffs2 = c(50, 30, 60, 40))

A partir disso, usamos a função seq_extensive() para transformar um jogo na forma sequencial, definido com seq_form(), em um jogo na forma extensiva.

jogo8 <- seq_extensive(sq_jogo8, 
                       direction = "right", 
                       color_palette = "Dark2")

Ao especificarmos o parâmetro direction como "right", a árvore extensiva é direcionada para a direita, e as cores são aplicadas de acordo com a paleta de cores especificada em color_palette.

Além disso, é possível utilizar funções que permitem não somente a indução manual dos caminhos, a restrição das opções dos jogadores, mas também outras funcionalidades que incluem a possibilidade da contagem de subjogos em cada ramo da forma extensiva e a transferência dos dados para matrizes. O que contribui para uma análise mais completa e coerente das possibilidades do jogo.

Com a construção da estrutura da forma extensiva, podemos utilizar a função draw_path para induzir os caminhos específicos em um jogo representado em forma de árvore, definido pela função extensive_form().

draw_path(jogo7, actions = list("Manter", "Manter"))
The game reaches at n4. 
Payoffs:
 OilFlex EconoGas 
      50       50 
The game reaches at n4. 
Payoffs:

No R, é possível restringir as ações dos jogadores através da eliminação de certas sequências de jogadas. Essa restrição pode ser feita utilizando o parâmetro actions da função restrict_action(), que recebe uma lista de vetores. Ao utilizar essa função, é possível controlar quais jogadas são permitidas em cada estágio do jogo sequencial.

restrict_action(jogo7, action = list("n1" = "Reduzir", 
                                     "n2" = "Reduzir"))

Ao observar o parâmetro action, percebemos que ele contém a identificação dos nós do jogo, neste caso, "n1" e "n2", juntamente com as ações correspondentes, que são "Reduzir" e "Reduzir".

A função subgames() é usada para encontrar e identificar os subjogos dentro de um jogo em forma extensiva. Um subjogo é uma parte do jogo que pode ser analisada e tratada separadamente.

subgames(jogo7, quietly = FALSE)
The game has 3 subgames.

Ao utilizar o parâmetro quietly = FALSE, a mensagem de contagem de subjogos será exibida juntamente com os gráficos.

A função to_matrix é usada para transformar um jogo em forma extensiva, com dois jogadores, em um jogo em forma normal. Isso permite representar o jogo em uma matriz de ganhos, onde as estratégias ou perfis de ações são especificados.

jogo7mx <- to_matrix(jogo7)

Para visualizar o data frame que contém as matrizes dos jogadores 1 e 2, basta utilizar o objeto criado anteriormente, nomeado como jogo7mx, e acrescentar $df. Nesse data frame, as colunas payoff1 e s1 representam, respectivamente, os ganhos e as estratégias do posto OilFlex, enquanto as colunas payoff2 e s2 representam os ganhos e estratégias da EconoGas.

jogo7mx$df
  row column        s1                 s2 payoff1 payoff2
1   1      1  (Manter)   (Manter, Manter)      50      50
2   1      2  (Manter)  (Manter, Reduzir)      50      50
3   1      3  (Manter)  (Reduzir, Manter)      30      60
4   1      4  (Manter) (Reduzir, Reduzir)      30      60
5   2      1 (Reduzir)   (Manter, Manter)      60      30
6   2      2 (Reduzir)  (Manter, Reduzir)      40      40
7   2      3 (Reduzir)  (Reduzir, Manter)      60      30
8   2      4 (Reduzir) (Reduzir, Reduzir)      40      40

Na visualização dos payoffs de cada jogador, é necessário utilizar a função matrix() em jogo7mx$mat$matrix1. Desse modo, é possível identificar as jogadas e os ganhos do jogador 1.

# Payoff do posto "OilFlex"
matrix(jogo7mx$mat$matrix1, 
       nrow = 2, 
       dimnames = list(c('M', 'R'), 
                       c('MM', 'MR', 'RM', 'RR')))
  MM MR RM RR
M 50 50 30 30
R 60 40 60 40

Ao utilizar o argumento dimnames para especificar os nomes das colunas e linhas de uma matriz. Dessa forma, é implementada por meio de uma lista, permitindo uma representação mais intuítiva das ações dos jogadores (Manter e Reduzir) e dos payoffs correspondentes ao jogador 1 e 2.

# Payoff do posto "EconoGas"
matrix(jogo7mx$mat$matrix2, 
       nrow = 2, 
       dimnames = list(c('M', 'R'), 
                       c('MM', 'MR', 'RM', 'RR')))
  MM MR RM RR
M 50 50 60 60
R 30 40 30 40

Quando utilizamos o argumento nrow = 2, estamos essencialmente informando que a matriz terá duas linhas, cada uma representando as ações “Reduzir” ('R') e “Manter” ('M'). Vale notar que, ao especificar o número de linhas, o ambiente R define automaticamente o número de colunas com base nessa especificação.

3.1 Eq. de Nash Perfeito em Subjogos

O Equilíbrio de Nash Perfeito em Subjogos (ENPS) é um conceito utilizado na teoria dos jogos para analisar estratégias em jogos sequenciais. Ele consiste em um conjunto de estratégias, uma para cada jogador, que representa um equilíbrio de Nash em cada subjogo do jogo original.

O solve_efg permite encontrar soluções para jogos em forma extensiva. Ele recebe como entrada um jogo em forma extensiva definido previamente e retorna uma lista de soluções encontradas, baseadas no conceito de solução escolhido pelo usuário.

Existem duas opções para o conceito de solução: "backward" (Indução Retroativa) e "spe" (Equilíbrio Perfeito em Subjogos), ambos obtêm o mesmo resultado.

solve_efg(jogo7, concept = "backward", quietly = FALSE)
backward induction: [(Reduzir), (Reduzir, Reduzir)]

Ou pode-se chegar ao gráfico de melhores respostas pelo comando show_path().

show_path(jogo7)

Também é possível obter a tabela a partir da matriz usando a função solve_nfg() e determinar os equilíbrios de Nash e Equilíbrio de Nash Perfeito em Subjogos a partir das informações mencionadas no tópico anterior.

# Matriz do jogo 7
jogo7mxtab <- solve_nfg(jogo7mx)
Pure-strategy NE: [(Reduzir), (Reduzir, Reduzir)]
EconoGas
strategy (Manter, Manter) (Manter, Reduzir) (Reduzir, Manter) (Reduzir, Reduzir)
OilFlex (Manter) 50, 50 50^, 50 30, 60^ 30, 60^
(Reduzir) 60^, 30 40, 40^ 60^, 30 40^, 40^

Assim, o ENPS ocorre quando o posto EconoGas adota as estratégias de “Reduzir, Reduzir”, em resposta à redução de preços realizada pelo posto OilFlex.

O solve_seq aceita um jogo em forma sequencial como entrada e retorna os equilíbrios de Nash encontrados, se houver. Além disso, ele também pode exibir uma tabela com as jogadas e estratégias ótimas para cada jogador, facilitando a análise e compreensão dos resultados.

No exemplo anterior, utilizamos a função seq_form() para estruturar um jogo na forma sequencial, a partir de uma forma normal. Em seguida, aplicamos o solve_seq() para transformar o jogo da forma extensiva novamente para a forma normal.

solve_seq(
  sq_jogo8,
  show_table = TRUE,
  mark_br = FALSE,
  precision = 1L,
  quietly = FALSE
  )
SPE outcome: (Reduzir, Reduzir)
EconoGas
strategy Manter Reduzir
OilFlex Manter 50, 50 60, 30
Reduzir 30, 60 40, 40

Já o argumento precision afeta a formatação dos valores exibidos na tabela de solução, determinando o número de casas decimais a serem apresentadas. Por exemplo, ao definir precision = 1L, os valores serão arredondados para uma casa decimal, já que o uso de 1L assegura que a precisão seja interpretada como um número inteiro.

Encontrar o ENPS envolve analisar cada subjogo, identificar os equilíbrios de Nash em cada um e verificar se esses equilíbrios são compatíveis entre si ao longo de todo o jogo. Caso exista um conjunto de estratégias que satisfaça essas condições, temos um Equilíbrio de Nash Perfeito em Subjogos.

4. Jogos Repetidos

Em jogos repetidos é possível definir os jogadores envolvidos e as ações disponíveis para cada um em cada rodada, de forma que os payoffs podem ser atribuídos a diferentes combinações de ações ao longo do tempo. Esse enfoque permite uma exploração mais profunda das complexas dinâmicas estratégicas que emergem quando os jogadores interagem repetidamente. À medida que eles se envolvem em múltiplas rodadas é ajustado suas estratégias com base nas escolhas anteriores dos adversários, construindo gradualmente um aprendizado estratégico.

4.1 Jogos Repetidos Finitos

Considerando um exemplo de jogo repetido finito entre dois países, "P1" e "P2", que estão em um cenário de possíveis conflitos e cooperação, representados pelas ações de “Guerra” ("G") e “Paz” ("P"). Nesse contexto, os jogadores estão envolvidos em quatro períodos de decisão. Eles estão avaliando se devem optar por “Guerra” ou “Paz” em cada período.

Comparando com a estrutura de Jogos Sequenciais, onde o argumento players continha rep() apenas no final e era definido por NA juntamente com o número de nós terminais. Em Jogos Repetidos, podemos utilizar a função rep() de forma mais detalhada.

Nesse caso, começamos com as jogadas de P2, pois as ações de P2 se repetirão sequencialmente após a ação do jogador inicial. Portanto, usamos "P2", 2 e assim por diante. Em sequência, teremos "P1", 4, o que significa que cada nó da jogada anterior de P2 se ramificará em dois nós, representando os 4 nós de P1. Na configuração rep(NA, 16), o valor NA indica que não há mais jogadas de nenhum jogador, apenas os nós terminais, que serão 16.

Nessa situação, especificamos duas estratégias para ambos os jogadores. Consequentemente, o número de repetições dos nós será sempre o dobro do anterior, como ilustrado abaixo.

jogo9 <- extensive_form(
            players = list("P1",         # n1
                           rep("P2", 2), # n2 e n3
                           rep("P1", 4), # n4 - n7
                           rep("P2", 8), # n8 - n15
                           rep(NA, 16)), # Nós terminais
            actions = list(
              c("G", "P"), c("G", "P"), c("G", "P"), # n1 - n3
              c("G", "P"), c("G", "P"), c("G", "P"), # n4 - n6
              c("G", "P"), c("G", "P"), c("G", "P"), # n7 - n9
              c("G", "P"), c("G", "P"), c("G", "P"), # n10 - n12
              c("G", "P"), c("G", "P"), c("G", "P")  # n13 - n15
            ),
            payoffs = list(
              P1 = c(6, 5, 6, 4, 5, 3, 6, 2, 8, 4, 7, 6, 7, 3, 6, 4),
              P2 = c(8, 5, 6, 4, 7, 5, 6, 8, 6, 2, 3, 3, 6, 3, 4, 7)
            ),
            direction = "down",
            show_node_id = FALSE
          )

O exemplo acima possui uma estrutura de árvore com 15 nós, numerados de n1 a n15. Em cada nó, os jogadores têm a opção de escolher entre duas ações. Por exemplo, os três primeiros nós (n1 a n3) representam as escolhas de ação dos jogadores no primeiro período.

Ao resolver o jogo acima por indução retroativa é possível visualizar as estratégias escolhidas pelos dois jogadores.

s_jogo9 <- solve_efg(jogo9, concept = "backward", quietly = FALSE)
backward induction: [(P, G, G, G, G), (G, G, G, G, G, P, G, G, G, P)], [(P, G, G, G, G), (G, P, G, G, G, P, G, G, G, P)], [(P, P, G, G, G), (P, G, G, G, G, P, G, G, G, P)], [(P, P, G, G, G), (P, P, G, G, G, P, G, G, G, P)], [(P, G, G, G, G), (G, G, G, G, G, P, G, P, G, P)], [(P, G, G, G, G), (G, P, G, G, G, P, G, P, G, P)], [(P, P, G, G, G), (P, G, G, G, G, P, G, P, G, P)], [(P, P, G, G, G), (P, P, G, G, G, P, G, P, G, P)]

Em jogos repetidos, as árvores de decisão geralmente se tornam mais complexas, devido à repetição das jogadas pelos jogadores. Como observado anteriormente, foram identificadas oito soluções por meio da análise de indução retroativa.

s_jogo9$sols
[[1]]
[1] "[(P, G, G, G, G), (G, G, G, G, G, P, G, G, G, P)]"

[[2]]
[1] "[(P, G, G, G, G), (G, P, G, G, G, P, G, G, G, P)]"

[[3]]
[1] "[(P, P, G, G, G), (P, G, G, G, G, P, G, G, G, P)]"

[[4]]
[1] "[(P, P, G, G, G), (P, P, G, G, G, P, G, G, G, P)]"

[[5]]
[1] "[(P, G, G, G, G), (G, G, G, G, G, P, G, P, G, P)]"

[[6]]
[1] "[(P, G, G, G, G), (G, P, G, G, G, P, G, P, G, P)]"

[[7]]
[1] "[(P, P, G, G, G), (P, G, G, G, G, P, G, P, G, P)]"

[[8]]
[1] "[(P, P, G, G, G), (P, P, G, G, G, P, G, P, G, P)]"

Utilizando o nome do objeto criado, s_jogo9, em conjunto com o atributo $n_sols, é possível obter o número total de soluções, que neste contexto específico é representado como [1] 8. Em uma análise mais aprofundada de uma das soluções, podemos escolher a primeira solução por meio da combinação entre s_jogo9 e $trees[[1]], que corresponde à representação visual da solução $sols[[1]], ou seja, a primeira solução em formato de árvore.

s_jogo9$trees[[1]]

Para cada solução em formato de combinação ($sols) é possível se chegar a uma representação gráfica em árvore de decisão ($trees).

Os conjuntos de informações podem ser especificados no argumento info_sets, agrupando, dessa forma, os nós nos quais um jogador não consegue distinguir as ações tomadas por seu oponente. Por exemplo, os nós n2 e n3 formam um conjunto de informações para o jogador P1, indicando que ele não sabe qual ação o jogador P2 escolheu nos nós n2 e n3.

jogo9info <- extensive_form(
            players = list("P1",         # n1
                           rep("P2", 2), # n2 e n3
                           rep("P1", 4), # n4 - n7
                           rep("P2", 8), # n8 - n15
                           rep(NA, 16)), # Nós terminais
            actions = list(
              c("G", "P"), c("G", "P"), c("G", "P"), # n1 - n3
              c("G", "P"), c("G", "P"), c("G", "P"), # n4 - n6
              c("G", "P"), c("G", "P"), c("G", "P"), # n7 - n9
              c("G", "P"), c("G", "P"), c("G", "P"), # n10 - n12
              c("G", "P"), c("G", "P"), c("G", "P")  # n13 - n15
            ),
            payoffs = list(
              P1 = c(6, 5, 6, 4, 5, 3, 6, 2, 8, 4, 7, 6, 7, 3, 6, 4),
              P2 = c(8, 5, 6, 4, 7, 5, 6, 8, 6, 2, 3, 3, 6, 3, 4, 7)
            ),
            direction = "down",
            info_sets = list(c(2,3), c(8, 9), c(10, 11),
                             c(12, 13), c(14, 15)),
            show_node_id = FALSE
          )

Devido à falta de conhecimento por parte do jogador P1 em relação às estratégias escolhidas pelo jogador P2, encontrar uma solução para esse jogo torna-se um desafio. Especialmente em cenários onde os jogadores estão alheios às estratégias dos demais participantes, como é o caso apresentado abaixo ao tentar aplicar o conceito de indução retroativa para elucidar as escolhas estratégicas de P1 e P2.

solve_efg(jogo9info, concept = "backward", quietly = FALSE)

Error in backward_induction()

  Error in backward_induction(game, restriction = tree_overlay): This is not a perfect-information game.

Nesse caso, há um erro ao empregar a função backward_induction() ou solve_efg(), pois o jogo em questão não se encaixa na categoria de informação perfeita (Perfect-Information). Em restriction = tree_overlay ocorre a restrição de sobreposição na estrutura da árvore, especificamente pelo uso do parâmetro info_sets.

Em jogos de informação perfeita, os jogadores têm conhecimento completo sobre as ações e movimentos realizados por outros jogadores em cada ponto da árvore de decisão, como exemplo o jogo 7, 8 e 9. Se o jogo contém informações imperfeitas ou incertezas sobre as ações de outros jogadores, a indução reversa ou indução retroativa não pode ser aplicada diretamente, já que ela pressupõe informação perfeita.

Ao expandir o exemplo, agora com a introdução de um terceiro país "P3", novas dimensões estratégicas emergem. Nessa situação ele possui as opções de “Ajudar” ("A") e “Desestabilizar” ("D"). Se P3 escolher “Ajudar”, seu objetivo é promover uma abordagem cooperativa entre P1 e P2, encorajando tratados de paz e parcerias, podendo ser alcançado através de diplomacia, oferecendo incentivos econômicos ou compartilhando informações sensíveis.

Por outro lado, se P3 optar por “Desestabilizar”, suas ações terão como alvo a erosão da confiança entre P1 e P2, ou seja, ele poderia propagar rumores, incentivar disputas territoriais ou minar acordos já existentes. Ao fazer isso, será criado um ambiente de incerteza e rivalidade, aumentando assim as chances de conflito entre os outros dois países.

jogo10 <- extensive_form(
            players = list("P1",          # n1
                           rep("P2", 2),  # n2 e n3
                           rep("P1", 4),  # n4 - n7
                           rep("P2", 8),  # n8 - n15
                           rep("P3", 16), # n16 - n31
                           rep(NA, 32)),  # Nós terminais
            actions = list(
              c("G", "P"), c("G", "P"), c("G", "P"), # n1 - n3
              c("G", "P"), c("G", "P"), c("G", "P"), # n4 - n6
              c("G", "P"), c("G", "P"), c("G", "P"), # n7 - n9
              c("G", "P"), c("G", "P"), c("G", "P"), # n10 - n12
              c("G", "P"), c("G", "P"), c("G", "P"), # n13 - n15
              # Ações do terceiro país (P3)
              c("A", "D"), c("A", "D"), c("A", "D"), # n16 - n18
              c("A", "D"), c("A", "D"), c("A", "D"), # n19 - n21
              c("A", "D"), c("A", "D"), c("A", "D"), # n22 - n24
              c("A", "D"), c("A", "D"), c("A", "D"), # n25 - n27
              c("A", "D"), c("A", "D"), c("A", "D"), # n28 - n30
              c("A", "D")                            # n31
            ),
            payoffs = list(
              P1 = c(6, 5, 6, 4, 5, 3, 6, 2, 
                     8, 4, 7, 6, 7, 3, 6, 4, 
                     8, 9, 1, 2, 3, 4, 5, 6, 
                     7, 8, 9, 1, 2, 3, 4, 5),
              P2 = c(8, 5, 6, 4, 7, 5, 6, 8, 
                     6, 2, 3, 3, 6, 3, 4, 7,
                     8, 9, 1, 2, 3, 4, 5, 6, 
                     7, 8, 9, 1, 2, 3, 4, 5),
              P3 = sample(1:9, 32, 
                          replace = TRUE)
            ),
            direction = "right",
            show_node_id = FALSE
          )

Nesta situação, ocorre a expansão do exemplo ao adicionar mais 15 nodos, a fim de incluir o terceiro país no jogo. Além disso, a amostragem dos payoffs é estendida para 32 elementos. Uma abordagem alternativa é a definição dos payoffs de forma aleatória para P3, como realizado através da função sample(), a qual gera uma seleção aleatória de valores a partir de um vetor.

Ao empregar 1:9, 32 como argumento dessa função, é criado um vetor com valores variando de 1 a 9, ou seja, os possíveis ganhos do jogador P3 estão dentro desse intervalo. Esses valores são então repetidos 32 vezes, correspondendo ao número de elementos amostrados. A utilização de replace = TRUE permite que elementos sejam selecionados mais de uma vez na amostra, possibilitando a repetição de valores nos payoffs do país P3. Caso fosse definido replace = FALSE, cada valor apareceria apenas uma vez.

Em resumo, essa abordagem amplia a complexidade do exemplo ao adicionar um terceiro país e introduzir aleatoriedade nos payoffs desse jogador por meio da função sample().

s_jogo10 <- solve_efg(jogo9, concept = "backward", quietly = FALSE)
backward induction: [(P, G , G , G , G ), (G, G, G  , G  , G  ,   P, G  , G  , G  ,   P)], [(P, G , G , G , G ), (G, P, G  , G  , G  ,   P, G  , G  , G  ,   P)], [(P,  P, G , G , G ), (P, G, G  , G  , G  ,   P, G  , G  , G  ,   P)], [(P,  P, G , G , G ), (P, P, G  , G  , G  ,   P, G  , G  , G  ,   P)], [(P, G , G , G , G ), (G, G, G  , G  , G  ,   P, G  ,   P, G  ,   P)], [(P, G , G , G , G ), (G, P, G  , G  , G  ,   P, G  ,   P, G  ,   P)], [(P,  P, G , G , G ), (P, G, G  , G  , G  ,   P, G  ,   P, G  ,   P)], [(P,  P, G , G , G ), (P, P, G  , G  , G  ,   P, G  ,   P, G  ,   P)]

A presença de P3 adiciona uma nova camada de complexidade. Sua escolha de “Ajudar” em vez de “Desestabilizar” parece ter desempenhado um papel crucial em incentivar a paz entre P1 e P2 nas primeiras rodadas. No entanto, à medida que P1 opta por “Guerra” e P2 responde da mesma forma, o equilíbrio entre os três países se torna mais delicado.

Em síntese, a introdução de P3 com suas estratégias de “Ajudar” e “Desestabilizar” transformou a dinâmica geopolítica. As decisões agora são influenciadas pelas ações de três jogadores, levando a resultados variados e demonstrando como diferentes abordagens podem levar a cenários diversos de cooperação e conflito

Quando se trata de um jogo com três jogadores, como no caso do jogo 9, a função to_matrix() não pode ser empregada, conforme demonstrado na tentativa a seguir ao utilizá-la.

to_matrix(jogo10)

Error in to_matrix()

  Error in to_matrix(jogo10): This function only works with a two-person game.

Esse erro ocorre pois a função to_matrix() do pacote Rgamer é projetada para trabalhar com jogos de dois jogadores. A mensagem de erro que está sendo mostrada, “This function only works with a two-person game”, significa que essa função não é capaz de lidar com jogos envolvendo três jogadores ou mais, pois limita-se a jogos de dois jogadores porque ela transforma a estrutura de um jogo em uma matriz, que é mais adequada para jogos de dois jogadores.

Quando há três jogadores, como no exemplo apresentado, a representação em forma extensiva da árvore de decisão se torna mais clara e menos complexa do que a representação em forma normal por matriz, porém a complexidade aumenta ao considerar as possíveis soluções de indução retroativa, em que cada jogador analisa as escolhas dos outros para determinar suas próprias ações.

Com três ou mais jogadores, a quantidade de combinações possíveis de soluções de indução retroativa cresce exponencialmente. Desse modo, surge mais cenários estratégicos a considerar, tornando impraticável a representação por matriz.

5. Outros Exemplos

Neste jogo, duas empresas, a “Empresa A” e a “Empresa B”, participam de uma disputa para ganhar um contrato. Cada uma delas deve escolher um lance entre 1 e 10 milhões de reais.

  • Se a “Empresa A” fizer o lance mais alto, ela ganha o contrato e recebe uma recompensa de 10 milhões. Enquanto isso, a “Empresa B” não ganha o contrato e ela acaba tendo prejuízo de 1 milhão.

  • Por outro lado, se a “Empresa A” fizer o lance mais alto, ela ganha o contrato e recebe a recompensa de 10 milhões. Enquanto isso, a “Empresa B” não ganha o contrato e perde 1 milhão.

  • Se ambas as empresas fizerem exatamente o mesmo lance, elas não conseguem diferenciar suas ofertas, e o contrato é anulado. Nesse caso, nenhuma das empresas recebe a recompensa.

Com base no exemplo mencionado anteriormente, utilizaremos novamente a palavra-chave function do R para representar a função de payoff. Isso se deve ao maior espaço estratégico presente no jogo, o qual possibilita mais combinações de lances e, por consequência, mais resultados em comparação com o jogo do dilema dos prisioneiros.

# Payoff do jogador 1
func_payoff1 <- function(a, b) {
                  if (a < b) {
                    profit <- -1
                    } else if (a == b) {
                    profit <- 0
                    } else {
                    profit <- 10
                    }
                  profit
                  }

# Payoff do jogador 2
func_payoff2 <- function(a, b){
                  if (a > b) {
                    profit <- -1
                    } else if (a == b) {
                    profit <- 0
                    } else {
                    profit <- 10
                    }
                  profit
                  }

Após a definição das funções de payoff, podemos passar o exemplo acima para a função normal_form(), utilizando as condições de func_payoff1 e func_payoff2.

jogo11 <- normal_form(
            players = c("Empresa A", 
                        "Empresa B"),
            payoffs1 = func_payoff1,
            payoffs2 = func_payoff2,
            pars = c("a", "b"),
            s1 = c(seq(1, 10,1)),
            s2 = c(seq(1, 10,1)),
            discretize = TRUE)

A opção discretize = TRUE é usada quando o conjunto contínuo de estratégias é muito grande, tornando a avaliação completa computacionalmente custosa. Nesse caso, o jogo é avaliado apenas em um conjunto específico de pontos discretos, em vez de considerar todas as combinações possíveis de estratégias contínuas. O padrão é discretize = FALSE, que significa que o jogo é avaliado considerando todas as possíveis combinações contínuas de estratégias.

Nesse contexto, na função solve_nfg(), o parâmetro mark_br será definido como FALSE, uma vez que não haverá marcação das melhores respostas para cada estratégia do oponente, devido à consideração restrita a pontos discretos ao invés de todas as combinações contínuas de estratégias.

s_jogo11 <- solve_nfg(jogo11, mark_br = FALSE)
Pure-strategy NE: [10, 10]
Empresa B
strategy 1 2 3 4 5 6 7 8 9 10
Empresa A 1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10
2 10, -1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10
3 10, -1 10, -1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10
4 10, -1 10, -1 10, -1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10
5 10, -1 10, -1 10, -1 10, -1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10 -1, 10
6 10, -1 10, -1 10, -1 10, -1 10, -1 0, 0 -1, 10 -1, 10 -1, 10 -1, 10
7 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 0, 0 -1, 10 -1, 10 -1, 10
8 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 0, 0 -1, 10 -1, 10
9 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 0, 0 -1, 10
10 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 10, -1 0, 0

A Batalha dos Sexos é um exemplo clássico na teoria dos jogos que ilustra a situação em que dois jogadores têm preferências diferentes, mas desejam coordenar suas ações. Neste exemplo, consideramos um casal composto por um homem e uma mulher que precisam decidir entre duas atividades: assistir a um jogo de futebol ou assistir a um balé.

Suponha que o marido prefira assistir a um jogo de futebol, enquanto a esposa prefira assistir a um balé. No entanto, ambos preferem estar juntos do que fazer atividades separadas. Portanto, eles precisam chegar a um acordo sobre qual evento assistir juntos.

  jogo12 <- normal_form(
              players = c("Marido", "Esposa"),
              s1 = c("Futebol(p)", "Balé(1-p)"), 
              s2 = c("Futebol(q)", "Balé(1-q)"), 
              payoffs1 = c(10, 1, 2, 5), 
              payoffs2 = c(6, 2, 3, 10))

# Transformando o jogo 12 em tabela
table_jogo12 <- solve_nfg(jogo12,
                     show_table = TRUE, 
                     mark_br = FALSE)
Pure-strategy NE: [Futebol(p), Futebol(q)], [Balé(1-p), Balé(1-q)]
Esposa
strategy Futebol(q) Balé(1-q)
Marido Futebol(p) 10, 6 2, 3
Balé(1-p) 1, 2 5, 10

A utilidade esperada dos dois é calculada com base na fórmula que leva em conta as probabilidades \(p\) e \(q\) presentes na tabela acima. Simplificamos e combinamos os termos para obter o resultado da utilidade esperada.

\(E(U_{M}) = 10pq + 2p(1 - q) + 1(1 - p)q + 5(1 - p)(1 - q)\)

\(E(U_{M}) = 10pq + 2p - 2pq + q - pq + 5 - 5p - 5q + 5pq\)

\(E(U_{M}) = 12pq - 4q - 3p + 5\)

\({\large{\frac{\partial U_{M}}{\partial p}}} = 12pq - 4q - 3p + 5\)

Para encontrar o valor de \(q\) que maximiza a utilidade esperada do marido, igualamos a derivada parcial em relação a \(q\) a zero:

\(12q - 3 = 0\)

\(q = \frac{1}{4}\)

Com base na resposta anterior, pode-se usar a mesma lógica para calcular a utilidade esperada da esposa.

\(E(U_{E}) = 6pq + 3p(1-q) + 2(1-p)q + 10(1-p)(1-q)\)

\(E(U_{E}) = 6pq + 3p - 3pq + 2q - 2pq + 10 - 10p - 10q + 10pq\)

\(E(U_{E}) = 11pq - 7p - 8q + 10\)

\({\large{\frac{\partial U_{E}}{\partial q}}} = 11pq - 7p - 8q + 10\)

Para encontrar o valor de \(p\) que maximiza a utilidade esperada, igualamos a derivada parcial em relação a \(p\) a zero:

\(11p - 8 = 0\)

\(p = \frac{8}{11}\)

O resultado da utilidade esperada do casal pode ser visualizado de forma gráfica utilizando a função br_plot.

table_jogo12$br_plot

6. Modelo de Aprendizagem

O modelo de aprendizagem aplicado à teoria dos jogos refere-se a um conjunto de regras e estratégias que os jogadores usam para aprender e adaptar seu comportamento ao longo do tempo em um jogo. Esses modelos podem ajudar a explicar como os jogadores tomam decisões e como essas decisões evoluem à medida que eles ganham experiência e aprendem com as interações passadas.

6.1 Experienced-Weighted Attraction (EWA)

O modelo de aprendizagem EWA (Experienced-Weighted Attraction) ou Atração Ponderada Experiente é uma abordagem em modelagem de aprendizado que busca demonstrar como os jogadores realizam escolhas estratégicas com base em suas experiências passadas e nas atrações associadas a diferentes estratégias. Neste modelo, os jogadores atribuem valores de atração a cada uma das estratégias disponíveis com base nas recompensas (payoffs) que receberam no passado ao escolher essas estratégias. Esses valores de atração refletem a percepção sobre a utilidade de cada estratégia e são atualizados ao longo do tempo com base nas recompensas obtidas.

Em um dos recursos presentes no pacote Rgamer está a função sim_learning() que realiza a simulação usando o modelo EWA e fornece resultados como estratégias escolhidas pelos jogadores, valores de atração, probabilidades de escolha de estratégias e gráficos de resultados.

Utilizando o mesmo exemplo dos dois postos de gasolina, o qual é estruturado por normal_form() para criar o jogo que será utilizado na simulação executada pela função sim_learning().

jogo12 <- sim_learning(
            game = jogo2,
            n_samples = 10,
            n_periods = 20,
            type = "EWA",
            lambda = 1,
            delta = 0.5,
            rho = 0.5,
            phi = 0.5
            )

Em 10 amostras (repetições) definido por n_samples, em que cada amostra contém 20 períodos (rodadas) configurado por n_periods, é necessário observar que quanto maior o número de amostras e períodos, maior será a precisão da simulação do modelo de aprendizagem. No entanto, isso também exigirá mais tempo e recursos de desempenho da máquina.

Abaixo estão as definições e configuração dos parâmetros lambda, delta, rho e phi:

  • lambda ( \(\lambda\) ): Esse parâmetro controla a rapidez com que os jogadores ajustam suas probabilidades de escolha com base nas experiências passadas. Quando o valor é igual a 1, significa que o jogadores aumentam ao máximo suas taxas de aprendizado.

  • delta ( \(\Delta\) ): Possui influência na sensibilidade dos jogadores às mudanças nas recompensas. Ao configurar esse parâmetro com o valor 0.5, irá gerar um equilíbrio entre reagir a mudanças e manter estabilidade nas escolhas.

  • rho ( \(\rho\) ): Ao adicionar esse parâmetro, é possível modificar a sensibilidade dos jogadores às diferenças nas atrações entre estratégias. Um valor de 0.5 indica que as preferências serão moderadamente relativas entre estratégias.

  • phi ( \(\phi\) ): Esse parâmetro representa a sensibilidade dos jogadores às mudanças nas atrações entre estratégias ao longo das amostras. Um valor de 0.5 significa que as mudanças nas preferências serão graduais.

Em muitos casos, é necessário ajustar esses valores, que variam de 0 a 1, durante a modelagem e testar diferentes combinações para ver como afetam o comportamento do modelo e se ajustam aos dados reais do problema em estudo. É importante notar que cada combinação diferente pode ativar um caso específico do modelo EWA, abordado mais a frente.

6.1.1 Probabilidade de Escolha

Este modelo não se limita apenas em fornecer representações gráficas, mas também oferece informações sobre as escolhas probabilísticas das estratégias feitas pelos jogadores ao longo dos períodos. Essas informações podem ser acessadas por meio dos comandos $choice_prob$P1 para o jogador 1 e $choice_prob$P2 para o jogador 2, ou também $choice_prob na visualização geral das probabilidades de escolha dos dois jogadores.

Para acessar as escolhas em probabilidade feitas pelo jogador 1 e 2, neste caso, basta utilizar o objeto criado, jogo12, em conjunto com esses comandos, como demonstrado abaixo.

# Probabilidade das escolhas do posto "OilFlex"
round(jogo12$choice_prob$P1[[10]], digits = 2)

# Probabilidade das escolhas do posto "EconoGas"
round(jogo12$choice_prob$P2[[10]], digits = 2)
     
jogo12$choice_prob$P1[[10]]  
   Manter Preço Reduzir Preço period
1           0.5           0.5      1
2           1.0           0.0      2
3           1.0           0.0      3
4           1.0           0.0      4
5           1.0           0.0      5
6           1.0           0.0      6
7           1.0           0.0      7
8           1.0           0.0      8
9           1.0           0.0      9
10          1.0           0.0     10
11          1.0           0.0     11
12          1.0           0.0     12
13          1.0           0.0     13
14          1.0           0.0     14
15          1.0           0.0     15
16          1.0           0.0     16
17          1.0           0.0     17
18          1.0           0.0     18
19          1.0           0.0     19
20          1.0           0.0     20
     
jogo12$choice_prob$P2[[10]]
   Manter Preço Reduzir Preço period
1           0.5           0.5      1
2           0.0           1.0      2
3           0.0           1.0      3
4           0.0           1.0      4
5           0.0           1.0      5
6           0.0           1.0      6
7           0.0           1.0      7
8           0.0           1.0      8
9           0.0           1.0      9
10          0.0           1.0     10
11          0.0           1.0     11
12          0.0           1.0     12
13          0.0           1.0     13
14          0.0           1.0     14
15          0.0           1.0     15
16          0.0           1.0     16
17          0.0           1.0     17
18          0.0           1.0     18
19          0.0           1.0     19
20          0.0           1.0     20

Para garantir a clareza dos resultados, neste cenário, realizamos a formatação dos números por meio do arredondamento utilizando a função round(), com precisão de duas casas decimais (digits = 2). A análise foi focada nos períodos (n_periods) da décima amostra (n_samples), que pode ser acessada através da posição [[10]].

Ao analisar o resultado, podemos inferir o seguinte:

  • No primeiro período, tanto “OilFlex” quanto “EconoGas” começam com uma probabilidade equilibrada de 50% para escolher qualquer uma das estratégias disponíveis, ou seja, “Manter Preço” ou “Reduzir Preço”. Esse cenário é comum em jogos onde os jogadores têm informações limitadas sobre as estratégias de seus oponentes. Nesse contexto, eles adotam uma abordagem inicial de “esperar para ver” e fazem suas escolhas de maneira aleatória, com base em suas percepções iniciais, sem conhecimento das escolhas do oponente. Essa abordagem equilibrada reflete a incerteza inicial sobre qual estratégia é a mais vantajosa.

A partir do segundo período, se observa uma mudança significativa no comportamento dos jogadores:

  • O jogador 1 (“OilFlex”) começa a escolher “Manter Preço” com uma probabilidade de 100%, indicando que ele adotou essa estratégia determinística a partir do segundo período. Essa escolha sugere uma tomada de decisão baseada em um padrão de aprendizado em atração ponderada experiente ou em uma estratégia que ele percebe como mais vantajosa a longo prazo.

  • O jogador 2 (“EconoGas”), por outro lado, começa a escolher “Reduzir Preço” com probabilidade de 100% a partir do segundo período. Da mesma forma que o jogador 1, o jogador 2 tomou uma decisão consistente de reduzir o preço, independentemente da escolha do oponente.

As escolhas dos jogadores são totalmente aleatórias? A resposta é não. Nesse exemplo, as probabilidades de escolha, representadas pelo termo “$choice_prob”, determinam as chances de um jogador selecionar uma estratégia específica em um determinado período. Essas probabilidades não são totalmente aleatórias, elas são diretamente influenciadas pelos valores de atração associados a cada estratégia. É importante notar que o modo de configuração dos parâmetros \(\lambda\), \(\Delta\), \(\rho\) e \(\phi\) também podem desempenhar um papel significativo na forma como o modelo lida com os valores de atrações em cenários específicos.

6.1.2 Valor de Atração (Attraction)

O valor de atração é uma medida que representa o grau de preferência ou atratividade de uma estratégia para um jogador em uma determinada amostra do jogo. Essencialmente, ele indica o quão valiosa uma estratégia é para o jogador em comparação com outras alternativas disponíveis.

Quando o valor de atração é elevado para uma determinada estratégia, isso implica que o jogador percebe essa estratégia como altamente vantajosa ou preferível naquela amostra em particular. Como resultado, a probabilidade dos jogadores escolherem essa estratégia será significativamente alta, aproximando-se de 1, enquanto a probabilidade de optar por outras estratégias será baixa, refletindo um valor de atração menor que influencia a diminuição das escolhas probabilísticas para valores próximos de 0.

É possível personalizar o quão atrativas (ou favoráveis) as estratégias são consideradas pelos jogadores no início da simulação. Essa modificação pode ser feito usando os parâmetros A1_init para o jogador 1 e A2_init para o jogador 2, fornecendo os valores correspondentes para cada parâmetro. Essa personalização afetará a forma como cada jogador começa a jogar no início de cada simulação. Também é relevante mencionar que a influência das experiências passadas na aprendizagem dos jogadores pode ser ajustada por meio do parâmetro N_init, que define o peso atribuído às escolhas passadas dos jogadores.

Na prática, ao utilizar o objeto de jogo da simulação, $jogo12, em conjunto com os comandos de valor de atração $attraction$A1 para o jogador 1 ou $attraction$A2 para o jogador 2 (ou simplesmente $attraction para uma visão geral), torna-se possível identificar preferências em relação às vantagens.

# Valor de atração para o posto "OilFlex" 
jogo12$attraction$A1[[10]]

# Valor de atração para o posto "EconoGas"
jogo12$attraction$A2[[10]]
     
jogo12$attraction$A1[[10]]
   Manter Preço Reduzir Preço period
1            30            20      1
2            30            20      2
3            30            20      3
4            30            20      4
5            30            20      5
6            30            20      6
7            30            20      7
8            30            20      8
9            30            20      9
10           30            20     10
11           30            20     11
12           30            20     12
13           30            20     13
14           30            20     14
15           30            20     15
16           30            20     16
17           30            20     17
18           30            20     18
19           30            20     19
20           30            20     20
     
jogo12$attraction$A2[[10]]
   Manter Preço Reduzir Preço period
1            25            60      1
2            25            60      2
3            25            60      3
4            25            60      4
5            25            60      5
6            25            60      6
7            25            60      7
8            25            60      8
9            25            60      9
10           25            60     10
11           25            60     11
12           25            60     12
13           25            60     13
14           25            60     14
15           25            60     15
16           25            60     16
17           25            60     17
18           25            60     18
19           25            60     19
20           25            60     20

Ao analisar o primeiro período, podemos inferir que:

  • O jogador “OilFlex” demonstra uma atratividade quase igual tanto pela estratégia “Manter Preço” (30) quanto pela “Reduzir Preço” (20). Essa paridade resulta em probabilidades de escolha equilibradas (0.5 para cada estratégia). Portanto, o jogador parece estar indeciso e faz suas escolhas de forma aleatória.

  • O jogador “EconoGas” encontra-se em uma situação semelhante ao “OilFlex”. Suas atrações pela estratégia “Manter Preço” (25) e “Reduzir Preço” (60) também levam a probabilidades equilibradas (0.5 para cada estratégia), indicando que o jogador também está indeciso e faz escolhas aleatórias.

Nesse período, uma situação interessante e curiosa destaca-se, pois as probabilidades de escolha para ambos os jogadores foram de 0.5, o que equivale a 50%. Essas probabilidades ocorreram independentemente dos valores de atração atribuídos a cada estratégia. Por exemplo, o posto EconoGas pode ter uma preferência maior (valor de atração de 60) por reduzir o preço, mas ainda assim, no primeiro período, há uma probabilidade de 50% de escolher entre manter ou reduzir o preço. Para visualização das escolhas que cada jogador realizou na décima amostra é necessário combinar o objeto de jogo com $data_list[[10]].

6.1.3 Estocasticidade e Valor de Atração Médio

A aparente contradição na análise do primeiro período pode ser atribuída a dois fatores. O primeiro é a Aleatoriedade ou Estocasticidade, um componente inerente à teoria probabilística. Mesmo quando o valor de atração indica uma preferência mais forte por “Reduzir Preço”, pode haver um elemento estocástico nas decisões do jogador 2. Esse fator demonstra que as escolhas do jogador 2 não são feitas puramente com base em preferências, mas também envolvem um elemento aleatório, principalmente no primeiro período, quando ambos os jogadores estão jogando pela primeira vez em uma amostra.

O segundo fator é o Valor de Atração Médio. Com o tempo, é possível observar que o valor médio de atração seja igual para ambas as estratégias, apesar das flutuações de curto prazo. Por exemplo, pode ser que o jogador 2 tenha escolhido “Reduzir Preço” com mais frequência em amostras passadas, mas em média, as escolhas se equilibram ao longo do tempo, como demonstrado nos períodos subsequentes. Esse valor médio de atração tem um impacto significativo nas probabilidades de escolha, especialmente quando se utiliza uma função de escolha estocástica que leva em consideração as diferenças nas atrações médias das estratégias.

Assim, o valor médio de atração desempenha um papel na influência das probabilidades de escolha ao longo das amostras. No entanto, a estocasticidade introduz uma variabilidade nas decisões, mesmo quando existe uma preferência clara por uma estratégia naquele intervalo de tempo. Por exemplo, em uma simulação com 10 amostras, os jogadores podem alternar entre as estratégias de “Manter Preço” e “Reduzir Preço”, sendo essa alternância influenciada pelo valor médio de atratividade e pela aleatoriedade na exploração de novas estratégias.

A combinação desses fatores pode resultar em probabilidades de escolha que não correspondem diretamente aos valores de atração em um período específico. Essa complexidade reflete a natureza realista das decisões humanas em situações de jogo, onde as preferências individuais, juntamente com elementos estocásticos, contribuem para as escolhas finais dos jogadores.

6.2 Tipos de Modelo

Além dos parâmetros mencionados anteriormente, o tipo de modelo de aprendizagem também é um elemento importante a ser considerado. Dependendo dos valores dos argumentos fornecidos, o modelo pode ser configurado como um modelo de aprendizagem por reforço ou um modelo de aprendizagem por crenças. Essas configurações especiais são casos específicos do modelo EWA.

Na representação gráfica, a opção de ajustar a escala do eixo Y nos gráficos de probabilidade de escolha ao longo do tempo é feita por meio do argumento plot_range_y. Existem três valores disponíveis para este argumento: "fixed", "full", e "free".

No caso do primeiro valor, "fixed", a faixa do eixo Y permanece constante e igual para todos os gráficos gerados. A escala vertical dos gráficos permanece inalterada, independentemente das variações nas probabilidades de escolha observadas. Essa abordagem pode ser útil para identificar tendências, diferenças ou padrões entre os gráficos de forma mais consistente.

No segundo cenário, "full", a faixa do eixo Y é definida com base nas probabilidades de escolha reais observadas durante a simulação. A escala vertical dos gráficos é automaticamente ajustada para incluir todas as probabilidades observadas, garantindo que os gráficos mostrem todas as variações nas escolhas ao longo do tempo.

Já no terceiro caso, "free", a faixa do eixo Y é flexível e depende dos resultados específicos de cada simulação. A escala vertical dos gráficos pode variar de uma execução para outra, dependendo das probabilidades de escolha observadas em cada simulação. Essa opção é útil quando se deseja realizar uma análise detalhada das mudanças nas probabilidades ao longo das amostras e quando é importante obter uma visão precisa das flutuações nas escolhas dos jogadores.

A escolha entre esses valores depende dos objetivos da análise. Por exemplo, se precisa fazer comparações consistentes entre gráficos de diferentes simulações, optar por "fixed" pode ser mais apropriado. Por outro lado, "full" ou "free" são escolhas preferíveis quando se tem a escala ajustada automaticamente com base nos resultados da simulação.

O modelo por reforço, popularmente conhecido como Reinforcement Learning, é uma abordagem amplamente utilizada em Machine Learning e teoria dos jogos. Ele é empregado em cenários nos quais um agente ou jogador precisa tomar decisões sequenciais com o objetivo de maximizar recompensas ao longo do tempo.

Neste modelo, os jogadores aprendem quais estratégias são mais vantajosas com base nas recompensas que recebem. É importante notar que no exemplo abaixo, o parâmetro rho está definido como 0, o que implica que o modelo não leva em consideração a atração ponderada experiente (EWA) nas escolhas dos jogadores. Portanto, no contexto desse caso específica, as escolhas dos jogadores são influenciadas principalmente pelas recompensas passadas. Dessa forma, quando uma estratégia leva a recompensas positivas, a probabilidade do jogador escolher essa estratégia aumenta ao longo do tempo, refletindo o seu aprendizado e adaptação.

Quando type = "reinforcement", utilizamos o modelo de aprendizado por reforço. Os jogadores escolhem a melhor resposta às ações do oponente na rodada anterior, buscando maximizar suas recompensas. Ao considerar o plot_range_y como "free", é possível ter uma visão mais detalhada das mudanças nas probabilidades.

sim_learning(
  game = jogo2,
  n_samples = 10,
  n_periods = 20,
  type = "reinforcement",
  lambda = 1,
  delta = 0.5,
  rho = 0,
  plot_range_y = "free"
  )

Ao utilizar o valor "free", é importante notar que os gráficos podem apresentar escalas diferentes em diversas simulações, o que pode dificultar a comparação visual entre diferentes conjuntos de dados. Contudo, essa configuração é ideal para uma análise minuciosa das variações nas probabilidades ao longo do tempo em um modelo de reforço.

O modelo por crenças é uma abordagem que se concentra na consideração das crenças dos jogadores sobre as estratégias e informações de seus oponentes ao tomar decisões em um jogo. Essa abordagem leva em conta não apenas as próprias informações do jogador, mas também o que o jogador acredita que seus oponentes sabem ou podem fazer.

Nesse modelo, os jogadores formam e atualizam suas crenças sobre as estratégias de seus oponentes com base nas informações disponíveis, podendo ser usado como parte dessas crenças o valor de atração médio. Por exemplo, se um jogador observar que, ao longo de várias rodadas, seu oponente tem consistentemente escolhido uma determinada estratégia, isso afetará suas crenças sobre a probabilidade de o oponente escolher essa estratégia no futuro.

No exemplo abaixo, quando temos phi igual a 1, os jogadores são racionais, pois realizam uma avaliação precisa e completa das ações passadas de seus oponentes. Eles atualizam suas crenças de forma ótima, pois levam em consideração todas as informações disponíveis, similar a Inferência Bayesiana.

Ao definir o type como "belief" e ajustar os valores de delta, rho, para 0.5 e phi para 1 é possível simular o comportamento de aprendizado baseado em crenças no sim_learning(). Também podemos definir o argumento plot_range_y como "fixed" para ter uma escala vertical fixa nos gráficos.

sim_learning(
  game = jogo2,
  n_samples = 10,
  n_periods = 20,
  type = "belief",
  lambda = 1,
  delta = 0.5,
  rho = 0.5,
  phi = 1,
  plot_range_y = "fixed"
  )

É importante mencionar que ao utilizar o valor "fixed", pode haver a possibilidade de corte das informações visuais se as probabilidades ou crenças observadas ultrapassarem os limites da faixa fixa. O mesmo ocorre com o "full", pois as probabilidades observadas podem variar amplamente em uma simulação específica, tornando difícil a visualização dos detalhes das mudanças nas probabilidades.

6.3 Simulação de Jogadas

A função sim_game() é usada para simular jogadas em um jogo na forma normal, permitindo a simulação de diferentes estratégias e comportamentos esperados com base em regras específicas.

Na opção "br" do argumento type, cada jogador escolhe a melhor resposta à escolha do oponente no período anterior. O valor do argumento eta (\(\eta\)) é definido como 0.5 para equilibrar a decisão atual em relação à decisão tomada na partida anterior.

sim_game(
  game = jogo2,
  n_samples = 10,
  n_periods = 20,
  type = "br",
  eta = 0.5,
  lambda = 1 
  )

Em outra opção como "imitation" em que os jogadores imitam a escolha do outro no período anterior, copiando a estratégia escolhida pelo oponente no período anterior.

sim_game(
  game = jogo2,
  n_samples = 1,
  n_periods = 10,
  type = "imitation",
  eta = 0.7,
  lambda = 0.8
  )

Nesse caso, o parâmetro eta é definido como 0.7 para controlar a aleatoriedade no comportamento dos jogadores, enquanto o lambda é definido como 0.8.

Adicionalmente, o parâmetro type presente na função sim_game() disponibiliza outras opções para simulação, incluindo:

  • "sbr" (Soft Best Response): Nessa abordagem, os jogadores optam por uma resposta suavizada às jogadas do oponente em períodos anteriores. Isso implica que eles não mudam suas estratégias abruptamente, mas, ao invés disso, ajustam-nas gradualmente com base nas escolhas prévias do oponente.

  • "abr" (Alternating Best Response): Os jogadores tomam decisões alternadas, escolhendo a melhor resposta possível para a ação do oponente. Isso significa que em cada turno, um jogador seleciona a sua melhor opção de acordo com a jogada feita pelo oponente no turno anterior, e no próximo turno, o outro jogador faz o mesmo, baseando-se na escolha do primeiro jogador no turno anterior.

Essas diferentes estratégias de simulação permitem o estudo de como as escolhas dos jogadores evoluem ao longo do tempo e como essas estratégias afetam o resultado do jogo. Cada opção de type fornece uma abordagem diferente para modelar o comportamento dos jogadores e pode levar a resultados distintos na simulação do jogo.

7. Referências

HAZRA, Tanmoy; ANJARIA, Kushal. Applications of game theory in deep learning: a survey. Multimedia Tools and Applications, v. 81, n. 6, p. 8963-8994, 2022. DOI: https://doi.org/10.1007/s11042-022-12153-2.

MANKIW, N. Gregory et al. Introdução à economia. 2005.

YANAI, Yusei; KAMIJO, Yoshio. Game Theory With R. Shin-Ogawacho, Shinjuku-ku, Tóquio, JP: Asakura Publishing Co,. Ltd., 2023. 244 p. ISBN 978-4-254-27024-2 C3050.