Tempo de leitura: 45 minutos.
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.
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)
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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:
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.
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]].
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.
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.
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.
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.