Public
Edited
Dec 27, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
energydb
SELECT * FROM "results" where GameType=7 and (Game=2020 or Game=2021)
Insert cell
energydb = DuckDBClient.of({
actions: FileAttachment("db Electric market 2018-2020 - db@1.csv"),
results: FileAttachment("db Electric market 2018-2020 - Results.csv")
})
Insert cell
Insert cell
energydb
select * from actions where gametype=1 or gametype=3 order by year,gametype,period, player
Insert cell
Insert cell
energydb
SELECT * FROM "actions" where gametype=7 order by year,gametype,period,player
Insert cell
Insert cell
Insert cell
// множество всех возможных наборов рангов рефлексии
set_of_ranks = d3.cross( d3.range(3) ,[0,1,2] ,[0,1,2] )
Insert cell
// данные по оценке моделей
graph_data = _.map(_.toPairs(set_of_refl_models), d=> [d[0].split('-').join(',') ,d[1][1][0],d[1][1][1],d[1][1][2] ,d[1][0][0],d[1][0][1],d[1][0][2]] )
Insert cell
// данные поведения всех вариантов рангов для 3 игроков моделей рефлексии для игр типа 7
acts_data = _.map(_.toPairs(set_of_refl_models), d=> [d[0] ,d[1][3][0],d[1][3][1] ] )
Insert cell
// синоним
refl_models_all_variants = acts_data
Insert cell
Insert cell
function add_rank1_actions(to_array ,br_of_player) {
for (let a of br_of_player) {
to_array.push(a)
}
}
Insert cell
<!-- function calc_reflexive_model(ranks ,history_steps ,generators_characters ,consumer_characters ,calculatedbr_map) {
let games_refl = []
let prevstep = false
for( let step of history_steps ) { // step: 0 - год, 1 - серия (4), 2 - тип (7), 3 - период, 4 - действия
// если началась новая игра, то сохраняем шаг как предыдущий и переходим к следующему
if( !prevstep || !_.isEqual(prevstep.slice(0,3),step.slice(0,3)) ) {
prevstep = step
continue
}
let mode = { 1:'B' ,3:'C' ,7:'CB' }[ step[2] ] // 1 - Бертран, 3 - Курно, 7 - Курно+Бертран
let actions = prevstep[4]
// считаем ситуацию
let sit = actions_to_situation(actions, generators_characters[step[2]], consumer_characters)
let bar = {year:step[0] ,serie:step[1] ,gametype_name:actions[0].gametype_name ,period:step[3] ,model_id: 'refl-rank0'} // Общие поля для добавления
const pl_actions = d3.group(actions, d=>d.player)
{
let pl_id = 1;
if ( ranks[0] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[0] == 1 ) add_rank1_actions( games_refl ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[0] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
{
let pl_id = 2;
if ( ranks[1] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[1] == 1 ) add_rank1_actions( games_refl ,step ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[1] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
{
let pl_id = 3;
if ( ranks[2] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[2] == 1 ) add_rank1_actions( games_refl ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[2] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
}// for
return games_refl -->
Insert cell
Insert cell
games7player2real = game7data.filter(d=> d.year!=2019 && d.player==2 && d.gencons=='G1')
Insert cell
games7player2ranks_acts = [acts_data[0],acts_data[3],acts_data[6]].map( d => d[2].filter( dd => dd.player==2 && dd.gencons=='G1' ) )
Insert cell
games7player2cost_acts = {
const T = 'C';
return [ games7player2real.filter( d=>d.powercost==T ), games7player2ranks_acts[0].filter( d=>d.powercost==T ) ,games7player2ranks_acts[1].filter( d=>d.powercost==T ) ,games7player2ranks_acts[2].filter( d=>d.powercost==T ) ]
}
Insert cell
Insert cell
Insert cell
acts_data[0]
Insert cell
games7model021_111_acts = {
const T = 'P'
const G = 'G2'
const Y = 2020
return [
game7data.filter(d=> d.year==Y && d.player==1 && d.gencons==G && d.powercost==T)
,game7data.filter(d=> d.year==Y && d.player==2 && d.gencons==G && d.powercost==T)
,game7data.filter(d=> d.year==Y && d.player==3 && d.gencons==G && d.powercost==T)
,acts_data[0][2].filter( d=> d.year==Y && d.player==1 && d.gencons==G && d.powercost==T )
,acts_data[6][2].filter( d=> d.year==Y && d.player==2 && d.gencons==G && d.powercost==T )
,acts_data[1][2].filter( d=> d.year==Y && d.player==3 && d.gencons==G && d.powercost==T )
,acts_data[9][2].filter( d=> d.year==Y && d.player==1 && d.gencons==G && d.powercost==T )
,acts_data[3][2].filter( d=> d.year==Y && d.player==2 && d.gencons==G && d.powercost==T )
,acts_data[1][2].filter( d=> d.year==Y && d.player==3 && d.gencons==G && d.powercost==T )
]
}
Insert cell
games7payoffs = {
const Y = 2021
let t1 = game7results.filter(d=> d.Game==Y && d.Player==1 )
t1 = t1.map( d => { d.Payoff = parseFloat(d.Payoff); return d } )
let t2 = game7results.filter(d=> d.Game==Y && d.Player==2 )
t2 = t2.map( d => { d.Payoff = parseFloat(d.Payoff); return d } )
let t3 = game7results.filter(d=> d.Game==Y && d.Player==3 )
t3 = t3.map( d => { d.Payoff = parseFloat(d.Payoff); return d } )
return [
t1
,t2
,t3
,acts_data[0][2].filter( d=> d.year==Y && d.player==1 )
,acts_data[6][2].filter( d=> d.year==Y && d.player==2 )
,acts_data[1][2].filter( d=> d.year==Y && d.player==3 )
,acts_data[9][2].filter( d=> d.year==Y && d.player==1 )
,acts_data[3][2].filter( d=> d.year==Y && d.player==2 )
,acts_data[1][2].filter( d=> d.year==Y && d.player==3 )
]
}
Insert cell
/*Plot.plot({
title:"Выигрыши,1-й игрок - красный, 2-й - зелёный, 3-й - синий",
width: 1000,
height: 600,
x: {grid: true, label: "Период"}, y: {grid: true, label: "Прибыль"},
color: {legend: true},
marks: [
Plot.line(games7payoffs[2], {x: "Period", y: "Payoff", stroke: "Blue",strokeWidth:1,tip: true})
,Plot.line(games7payoffs[1], {x: "Period", y: "Payoff", stroke: "green",strokeWidth:1,tip: true})
,Plot.line(games7payoffs[0], {x: "Period", y: "Payoff", stroke: "Red",strokeWidth:1,tip: true})
,Plot.tickY(games7payoffs[5], {x: "period", y: "model_payoff", stroke:"Blue",strokeWidth:2,tip:true})
,Plot.tickY(games7payoffs[4], {x: "period", y: "model_payoff", stroke:"green",strokeWidth:2,tip:true})
,Plot.tickY(games7payoffs[3], {x: "period", y: "model_payoff", stroke:"Red",strokeWidth:2,tip:true})
,Plot.dot(games7payoffs[8], {x: "period", y: "model_payoff", stroke:"Blue",strokeWidth:2,tip:true,marker:"circle-stroke"})
,Plot.dot(games7payoffs[7], {x: "period", y: "model_payoff", stroke:"green",strokeWidth:2,tip:true,marker:"circle-stroke"})
,Plot.dot(games7payoffs[6], {x: "period", y: "model_payoff", stroke:"Red",strokeWidth:2,tip:true,marker:"circle-stroke"})
]
})*/
Insert cell
Insert cell
refl_models_all_variants[0][2].filter( d=> d.year==2020 && d.period==8 && d.player==2 )
Insert cell
MG_step1_data = {
let debug = []
let res = []
let steps = d3.flatGroup(
game7data.filter(a=>a.year!=2019)
.toSorted( (a,b) => a.year-b.year + (a.year==b.year)*(a.period-b.period) )
, ({year})=>year,({period})=>period
)
//debug.push({steps})
for( let a of steps ) {
let s = { year: a[0] ,period:a[1]
,1:{real: a[2].filter(d=>d.player==1)} ,2:{real: a[2].filter(d=>d.player==2)} ,3:{real: a[2].filter(d=>d.player==3)} }
s[1].r0 = refl_models_all_variants[0][2].filter( d=> d.year==s.year && d.period==s.period && d.player==1 )
s[1].r1 = refl_models_all_variants[9][2].filter( d=> d.year==s.year && d.period==s.period && d.player==1 )
s[1].r2 = refl_models_all_variants[18][2].filter( d=> d.year==s.year && d.period==s.period && d.player==1 )
s[2].r0 = refl_models_all_variants[0][2].filter( d=> d.year==s.year && d.period==s.period && d.player==2 )
s[2].r1 = refl_models_all_variants[3][2].filter( d=> d.year==s.year && d.period==s.period && d.player==2 )
s[2].r2 = refl_models_all_variants[6][2].filter( d=> d.year==s.year && d.period==s.period && d.player==2 )
s[3].r0 = refl_models_all_variants[0][2].filter( d=> d.year==s.year && d.period==s.period && d.player==3 )
s[3].r1 = refl_models_all_variants[1][2].filter( d=> d.year==s.year && d.period==s.period && d.player==3 )
s[3].r2 = refl_models_all_variants[2][2].filter( d=> d.year==s.year && d.period==s.period && d.player==3 )
res.push( s )
}
return [res,debug][0]
}
Insert cell
MG_step2_pay = {
const calcPayoff = (player,acts) => {
let sit = actions_to_situation( acts ,gametype_characters[7] ,characters13_consumers )
// calc market
let market = market_clearing( sit )
let pl_res = market.generators.filter( d => d.player_id == player )
// get payoff
let pay = pl_res.reduce( (acc,el,ind) => acc + (market.market_price - gametype_characters[7][player][ind].min_cost) * el.load ,0)
return pay
}
const f0to1 = (x => x==0 ? x+1 : x)
for( let a of MG_step1_data ) {
if ( a.period == 1 ) continue
for ( let player of [1,2,3] ) {
let secplayer = f0to1((player+1)%4) ,thirdplayer = f0to1((secplayer+1)%4)
// считаем выигрыши для 0-2 рангов
for( let r of [0,1,2] ) {
let acts = [...a[player]['r'+r] ,...a[secplayer].real ,...a[thirdplayer].real ]
a[player]['r'+r+'_payoff'] = calcPayoff( player, acts )
}
// считаем выигрыши для реального поведения
let acts = [...a[player].real ,...a[secplayer].real ,...a[thirdplayer].real ]
a[player]['real_payoff'] = calcPayoff( player, acts )
}
}
}
Insert cell
payoffs_for_figures =
MG_step1_data
.map( d => [{year:d.year,period:d.period,player:1 ,model:'real',payoff:d[1].real_payoff}
,{year:d.year,period:d.period,player:1 ,model:'r0',payoff:d[1].r0_payoff}
,{year:d.year,period:d.period,player:1 ,model:'r1',payoff:d[1].r1_payoff}
,{year:d.year,period:d.period,player:1 ,model:'r2',payoff:d[1].r2_payoff}
,{year:d.year,period:d.period,player:2 ,model:'real',payoff:d[2].real_payoff}
,{year:d.year,period:d.period,player:2 ,model:'r0',payoff:d[2].r0_payoff}
,{year:d.year,period:d.period,player:2 ,model:'r1',payoff:d[2].r1_payoff}
,{year:d.year,period:d.period,player:2 ,model:'r2',payoff:d[2].r2_payoff}
,{year:d.year,period:d.period,player:3 ,model:'real',payoff:d[3].real_payoff}
,{year:d.year,period:d.period,player:3 ,model:'r0',payoff:d[3].r0_payoff}
,{year:d.year,period:d.period,player:3 ,model:'r1',payoff:d[3].r1_payoff}
,{year:d.year,period:d.period,player:3 ,model:'r2',payoff:d[3].r2_payoff}
]
).flat()
Insert cell
year_n_player_payoffs = d3.group(payoffs_for_figures.filter(d=>d.period>1) ,d=>d.year)
Insert cell
Plot.plot({
title:"Платежи реальные и модели, 2020 год",
width: 1000,
height: 600,
x: {grid: true, label: "Период"}, y: {grid: true, label: "Платёж"},
color: {legend: true},
marks: [
Plot.line(year_n_player_payoffs.get(2020).filter(d=>d.model!='real') ,{x: "period", y: "payoff" ,z:"model" ,fy:"player" ,stroke:"model" ,tip: true})
,Plot.line(year_n_player_payoffs.get(2020).filter(d=>d.model=='real') ,{x: "period", y: "payoff" ,z:"model" ,fy:"player" ,stroke: "black",strokeWidth:3,strokeDasharray:"3 10",tip: true})
/*,Plot.line(year_n_player_payoffs.get(2020) ,{x: "period", y: "payoff" ,z:"model" ,stroke:"red",strokeWidth:4,strokeDasharray:"10 10",tip:true})
,Plot.line(year_n_player_payoffs.get(2020) ,{x: "period", y: "payoff" ,z:"model" ,stroke: "black",strokeWidth:1.5,tip: true})*/
]
})
Insert cell
Plot.plot({
title:"Платежи реальные и модели, 2021 год",
width: 1000,
height: 600,
x: {grid: true, label: "Период"}, y: {grid: true, label: "Платёж"},
color: {legend: true},
marks: [
Plot.line(year_n_player_payoffs.get(2021).filter(d=>d.model!='real') ,{x: "period", y: "payoff" ,z:"model" ,fy:"player" ,stroke:"model" ,tip: true})
,Plot.line(year_n_player_payoffs.get(2021).filter(d=>d.model=='real') ,{x: "period", y: "payoff" ,z:"model" ,fy:"player" ,stroke: "black",strokeWidth:3,strokeDasharray:"3 10",tip: true})
/*,Plot.line(year_n_player_payoffs.get(2020) ,{x: "period", y: "payoff" ,z:"model" ,stroke:"red",strokeWidth:4,strokeDasharray:"10 10",tip:true})
,Plot.line(year_n_player_payoffs.get(2020) ,{x: "period", y: "payoff" ,z:"model" ,stroke: "black",strokeWidth:1.5,tip: true})*/
]
})
Insert cell
Plot.plot({
title:"Заявки по мощности, 1-й игрок - красный, 2-й - зелёный, 3-й - синий",
width: 1000,
height: 600,
x: {grid: true, label: "Период"}, y: {grid: true, label: "Заявка по мощности"},
color: {legend: true},
marks: [
Plot.line(games7model021_111_acts[2], {x: "period", y: "bid", stroke: "Blue",strokeWidth:2,tip: true})
,Plot.line(games7model021_111_acts[1], {x: "period", y: "bid", stroke: "green",strokeWidth:3,tip: true})
,Plot.line(games7model021_111_acts[0], {x: "period", y: "bid", stroke: "Red",strokeWidth:1,tip: true})
,Plot.line(games7model021_111_acts[5], {x: "period", y: "bid", stroke:"Blue",strokeWidth:2,tip:true,marker:'circle'})
,Plot.line(games7model021_111_acts[4], {x: "period", y: "bid", stroke:"green",strokeWidth:2,tip:true,marker:'circle'})
,Plot.line(games7model021_111_acts[3], {x: "period", y: "bid", stroke:"Red",strokeWidth:1,tip:true,marker:'circle'})
,Plot.line(games7model021_111_acts[8], {x: "period", y: "bid", stroke:"Blue",strokeWidth:2,tip:true,marker:"circle-stroke"})
,Plot.line(games7model021_111_acts[7], {x: "period", y: "bid", stroke:"green",strokeWidth:2,tip:true,marker:"circle-stroke"})
,Plot.line(games7model021_111_acts[6], {x: "period", y: "bid", stroke:"Red",strokeWidth:1,tip:true,marker:"circle-stroke"})
]
})
Insert cell
Insert cell
Plot.plot({
title: "Игра 2020, по цене, 2-й игрок, 1-й генератор",
x: {grid: true, label: "По цене"}, y: {grid: true, label: "По мощности"},
marks: [
Plot.line(games7player2cost_acts[3].filter(d=>d.year==2020), {x: "period", y: "bid", stroke: "red", strokeWidth: 6 ,tip: true})
,Plot.line(games7player2cost_acts[2].filter(d=>d.year==2020), {x: "period", y: "bid", stroke: "Blue", strokeWidth: 3 ,tip: true})
,Plot.line(games7player2cost_acts[0].filter(d=>d.year==2020), {x: "period", y: "bid", stroke: "black", tip: true})
]
})
Insert cell
Plot.plot({
title: "Игра 2021, по мощности, 2-й игрок, 2-й генератор",
x: {grid: true, label: "По цене"}, y: {grid: true, label: "По мощности"},
marks: [
Plot.line(games7player2cost_acts[3].filter(d=>d.year==2021), {x: "period", y: "bid", stroke: "red", strokeWidth: 6 ,tip: true})
,Plot.line(games7player2cost_acts[2].filter(d=>d.year==2021), {x: "period", y: "bid", stroke: "blue", strokeWidth: 3 ,tip: true})
,Plot.line(games7player2cost_acts[0].filter(d=>d.year==2021), {x: "period", y: "bid", stroke: "black", tip: true})
]
})
Insert cell
Insert cell
Plot.plot({
/*title: "Оценки для игр типа [7]",*/
width: 800,
height: 500,
x: {grid: true, label: "По цене"}, y: {grid: true, label: "По мощности"},
marks: [
Plot.dot(graph_data, {x: "2", y: "3", stroke: "#000000", tip: true})
,Plot.text(graph_data, {x: "2", y: "3", text: "0" ,dx:-22 ,dy: 10, lineAnchor: "bottom"}),
]
})
Insert cell
gamesCB_steps
Insert cell
/*set_of_refl_models = {
let rmods = {}
for( let ind of set_of_ranks ) {
let str = ind[0]+'-'+ind[1]+'-'+ind[2]
rmods[str] = 'megamodel'
let tmp_7_refl = calc_reflexive_model(ind ,gamesCB_steps.filter(d=>d[0]!=2019) ,gametype_characters ,characters13_consumers ,games_br_map)
let tmp_13_refl = calc_reflexive_model(ind ,games_steps ,gametype_characters ,characters13_consumers ,games_13_br_map)
let m2_7 = model_score({game_history:game7data.filter(d=>d.year!=2019), model_results:tmp_7_refl})
let m2_13 = model_score({game_history:game13data, model_results:tmp_13_refl})
rmods[str] = [ ['13' ,Math.sqrt(m2_13[0]) ,Math.sqrt(m2_13[1])] ,['7' ,Math.sqrt(m2_7[0]) ,Math.sqrt(m2_7[1])] ,['13acts', tmp_13_refl], ['7acts',tmp_7_refl] ]
}
return rmods
}*/
Insert cell
gamesCB_steps.filter(d=>d[0]!=2019)
Insert cell
{ // простой поиск одной из точек Парето
let min13 = ['13',100000,100000], ranks13 = null, min7 = ['7',1000000,1000000], ranks7 = null;
for( let i in set_of_refl_models ) {
if( set_of_refl_models[i][0][1] <= min13[1] && set_of_refl_models[i][0][2] <= min13[2] ){
min13 = set_of_refl_models[i][0]
ranks13 = i
}
if( set_of_refl_models[i][1][1] <= min7[1] && set_of_refl_models[i][1][2] <= min7[2] ){
min7 = set_of_refl_models[i][1]
ranks7 = i
}
}
return {min13,ranks13,min7,ranks7}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
let m2 = model_score({game_history:game7data, model_results:games_br})
return ['Score of BR on games 7',Math.sqrt(m2[0]), Math.sqrt(m2[1]),m2[2]]
}
Insert cell
{
let m2 = model_score({game_history:game7data, model_results:games_7_refl_021})
return ['Score of R021 on games 7',Math.sqrt(m2[0]), Math.sqrt(m2[1]),m2[2]]
}
Insert cell
{
let m2 = model_score({game_history:game13data ,model_results: games_13_refl_021})
return ['Score of R021 on games 1 and 3',Math.sqrt(m2[0]), Math.sqrt(m2[1]),m2[2]]
}
Insert cell
{
let m2 = model_score({game_history:game13data ,model_results: games_13_br })
return ['Score of BR on games 1 and 3',Math.sqrt(m2[0]), Math.sqrt(m2[1]),m2[2]]
}
Insert cell
// сравнение по объёму моделей br и tmp_13_refl_021
d3.flatGroup( tmp_13_refl_021.filter(d=>d.serie==3 && d.powercost=='P').concat(games_13_br.filter(d=>d.serie==3 && d.powercost=='P')), d=>d.year ,d=>d.serie ,d=>d.period ,d=>d.player).map( d=> d[4][0].bid-d[4][0].bid )

Insert cell
function model_score({game_history:gamedata, model_results:modelresults} ,window ,step){
let score_x = 0 ,score_y = 0
let bugs = []
let aggreg = d3.flatGroup(_.concat(gamedata,modelresults) ,d=>d.year ,d=>d.serie ,d=>d.period ,d=>d.player)
// score method
for( let el of aggreg ) {
let [x,y,newbugs] = get_bid_difference(el[4]); // const actions = el[4]
score_x += x; score_y += y
bugs.push(...newbugs)
}
return [score_x ,score_y, bugs]
}
Insert cell
function get_bid_difference(actions) {
let bugs = []
let group_actions = d3.flatGroup(actions ,d=>d.gencons ,d=>d.powercost)
let [cost_score ,power_score] = [0,0]
for( let el of group_actions ) {
let bids = el[2]
if( bids.length != 2 ){
bugs.push({msg:'group_actions.length='+bids.length+' != 2',data:el})
continue
}
if ( (!_.isFinite(bids[0].bid)) || (!_.isFinite(bids[1].bid)) ) {
bugs.push({msg:'one or two bids are not a number:('+bids[0].bid+','+bids[1].bid+')' ,data:el})
continue
}
let bids_diff = Math.abs(bids[0].bid - bids[1].bid)
if( bids[0].powercost == 'C' ) {
cost_score += bids_diff**2
}
if( bids[0].powercost == 'P' ) {
power_score += bids_diff**2
}
}
return [cost_score ,power_score ,bugs]
}
Insert cell
Insert cell
Insert cell
function market_clearing({generators:generators_actions,consumers:consumers_actions}){ // actions: [{action_id|player_id:val,cost:val, power:val},...]
// sort by cost_bids
let gen_arr = JSON.parse(JSON.stringify(generators_actions)).sort((a,b)=> a.cost - b.cost);
let cons_arr = JSON.parse(JSON.stringify(consumers_actions)).sort((a,b)=> - (a.cost - b.cost) );
for( let i of gen_arr ) i.load = 0
for( let i of cons_arr ) i.load = 0
// go through both arrays
let total_power = 0, total_consume = 0, last_gen = false, last_cons = false, i = 0, j = 0
for( ; i < gen_arr.length && j < cons_arr.length && gen_arr[i].cost <= cons_arr[j].cost ; ){
[last_gen ,last_cons] = [false ,false]
let gen_diff = gen_arr[i].power-gen_arr[i].load,
cons_diff = cons_arr[j].power-cons_arr[j].load;
if( gen_diff < cons_diff ) {
gen_arr[i].load = gen_arr[i].power
cons_arr[j].load += gen_diff
total_power += gen_diff
total_consume += gen_diff
i++
last_gen = true
}
else {
gen_arr[i].load += cons_diff
cons_arr[j].load = cons_arr[j].power
total_power += cons_diff
total_consume += cons_diff
j+=1
last_cons = true
}
}// for
// set MCP
let MCP = (last_cons) ? gen_arr[i].cost : cons_arr[j].cost
// bid proportional load
for( let [k,g] of d3.flatGroup(gen_arr, d => d.cost) ){
if( g.length == 1 ) continue
let [tot_load, tot_pow] = g.reduce((a,b) => [a[0]+b.load,a[1]+b.power] ,[0,0])
if( Math.abs(tot_load - tot_pow) < 0.000001 ) continue
let koeff = tot_load / tot_pow
for( let i = 0 ; i < gen_arr.length ; i++ )
{ if( gen_arr[i].cost == k ) { gen_arr[i].load = gen_arr[i].power * koeff } }
}
//return MCP and loads
return {generators:gen_arr,consumers:cons_arr, market_price:MCP, total_power: total_power}
}
Insert cell
Insert cell
Insert cell
Insert cell
tests.map( d => [ d.desc, _.isEqual(d.output, market_clearing(d.input)) ] )
Insert cell
Insert cell
games_steps[1]
Insert cell
actions_to_situation(games_steps[1][4] ,gametype_characters[1] ,characters13_consumers)
Insert cell
best_response( 3 ,gametype_characters[1][3], actions_to_situation(games_steps[1][4] ,gametype_characters[1] ,characters13_consumers), 'B' )
Insert cell
// player_character: {min_cost:val, max_power:val}
function best_response (player_id, player_character, game_situation, mode='CB', max_cost = 25) {
let test = []
let situation = JSON.parse(JSON.stringify(game_situation)) // копируем, чтобы менять
// рассчитываем множество действий
let actions_set = []
if( mode == 'CB' ) { // Cournot+Bertrand
if( player_character.length > 1 ) { // a player with 2 generators
actions_set = d3.cross(
d3.range(player_character[0].min_cost,max_cost+1,1), d3.range(100,player_character[0].max_power+100,100)
,d3.range(player_character[1].min_cost,max_cost+1,1), d3.range(100,player_character[1].max_power+100,100)
)
//test.push({msg:'actionset',data:actions_set})
}
else {
actions_set = d3.cross( d3.range(player_character[0].min_cost,max_cost+1,1) ,d3.range(100,player_character[0].max_power+100,100) )
}
} else if ( mode == 'B' ) { // Bertrand
actions_set = d3.cross( d3.range(player_character[0].min_cost,max_cost+1,1), [player_character[0].max_power] )
} else if ( mode == 'C' ) { // Cournot
actions_set = d3.cross( [player_character[0].min_cost] ,d3.range(100,player_character[0].max_power+100,100) )
}
// ищем наилучший ответ
let br_payoff = 0, br_cost = 0, br_power = 0, br_cost2 = 0, br_power2 = 0
let pl_gens = situation.generators.filter( d => d.player_id == player_id )
for( let [cost ,power ,cost2 ,power2] of actions_set ) {
// set bid
let ord = 1;
for( let el of pl_gens ) { if(ord == 1) {el.cost = cost; el.power = power; ord += 1} else {el.cost = cost2; el.power = power2} } // меняется situation
// calc payoff
let res = market_clearing( situation )
let pl_res = res.generators.filter( d => d.player_id == player_id )
let pf = pl_res.reduce( (acc,el,ind) => acc + (res.market_price - player_character[ind].min_cost) * el.load ,0)
//let pf = (res.market_price - player_character.min_cost) * pl_res.load
//test.push(pf)
// update maximum payoff
if ( pf > br_payoff )
[br_payoff ,br_cost ,br_power ,br_cost2 ,br_power2] = [pf ,cost ,power ,cost2 ,power2]
}
if( player_character.length > 1 )
return [br_payoff ,{br_cost ,br_power ,br_cost2 ,br_power2} ,test]
return [br_payoff ,{br_cost ,br_power} ,test]
}
Insert cell
// gametype -> player -> parameters
gametype_characters = {
let characters = {
1:{
1:{min_cost:2,max_power:400}
,2:{min_cost:4,max_power:500}
,3:{min_cost:6,max_power:500}
,4:{min_cost:10,max_power:200}
,5:{min_cost:12,max_power:600}
,6:{min_cost:13,max_power:1000}
}
,2:{
1:{min_cost:2,max_power:400}
,2:{min_cost:4,max_power:500}
,3:{min_cost:6,max_power:500}
,4:{min_cost:10,max_power:200}
,5:{min_cost:12,max_power:600}
,6:{min_cost:13,max_power:1000}
}
,3:{
1:{min_cost:2,max_power:400}
,2:{min_cost:4,max_power:500}
,3:{min_cost:6,max_power:500}
,4:{min_cost:10,max_power:200}
,5:{min_cost:12,max_power:600}
,6:{min_cost:13,max_power:1000}
}
,7:{
1:[{min_cost:2,max_power:400,gen_id:1},{min_cost:12,max_power:500,gen_id:2}]
,2:[{min_cost:4,max_power:400,gen_id:1},{min_cost:10,max_power:300,gen_id:2}]
,3:{min_cost:6,max_power:600}
,4:{min_cost:13,max_power:1250}
}
}
for ( let g in characters ) {
for( let pl in characters[g] ) {
if( ! Array.isArray(characters[g][pl]) ) {
characters[g][pl] = [Object.assign(characters[g][pl],{gen_id:1})]
}
}
}
return characters
}
Insert cell
characters13_consumers = ({
'-1': {max_cost:14 ,max_power:1250}
})
Insert cell
Insert cell
[
_.isEqual( [3150,{br_cost: 11, br_power: 400, br_cost2: undefined, br_power2: undefined}] ,best_response(1,gametype_characters[7][1],tests[1].input,'B').slice(0,2))
,_.isEqual( [2500,{br_cost: 12, br_power: 300, br_cost2: 13, br_power2: 100}] ,best_response(1,gametype_characters[7][1],actions_to_situation(gamesCB_steps[13][4] ,gametype_characters[7] ,characters13_consumers),'CB').slice(0,2) )
]
Insert cell
{
let sit = JSON.parse(JSON.stringify(tests[0].input))
let obj = sit.generators.find( d => d.player_id == 1 )
obj.cost = 10
obj.power = 400
return market_clearing(sit)
}
Insert cell
Insert cell
// games_steps = [ {year,serie,gametype,period,[actions]},...]
games_steps = d3.flatGroup(game13data ,d=>d.year ,d=>d.serie ,d=>d.gametype ,d=>d.period).sort( (a,b) => 1000*Math.sign(a.year-b.year) + 100*Math.sign(a.serie-b.serie) + 10*Math.sign(a.period-b.period) + Math.sign(a.player-b.player) )
Insert cell
gamesCB_steps = d3.flatGroup( game7data ,d=>d.year ,d=>d.serie ,d=>d.gametype ,d=>d.period).sort( (a,b) => 1000*Math.sign(a.year-b.year) + 100*Math.sign(a.serie-b.serie) + 10*Math.sign(a.period-b.period) + Math.sign(a.player-b.player) )
Insert cell
// actions - массив объектов {player:x, bid:x, gencons:x, powercost:x, ...}
//
//
function actions_to_situation(actions,generator_characters, consumer_characters){
let generators = []
for( let el in generator_characters ) {
let pl_gens = generator_characters[el].map( // истинные генераторы игрока
d => ({ player_id: el ,cost: d.min_cost ,power: d.max_power ,gen_id:d.gen_id })
)
let pl_acts = actions.filter( d=>d.player==el ) // действия/заявки игрока
let double_generator = false
for( let a of pl_acts ) {
if( _.isNull(a.bid) || _.isUndefined(a.bid) ) continue
let gen_ind = parseInt(a.gencons[1]) // из строки "G1" берём 1 - номер генератора
let g = pl_gens.find(d=>d.gen_id==gen_ind)
if ( gen_ind == 2 )
double_generator = true // флаг что была заявка по второму генератору
if( a.powercost == 'C' )
g.cost = a.bid
if( a.powercost == 'P' )
g.power = a.bid
}
generators.push( ...pl_gens )
//if( double_generator ) // получается в генераторы игрока добавляется его второй, только если он по нему подавал заявку
// generators.push( pl_gens[1] )
}
let consumers = []
for( let k in consumer_characters ) {
consumers.push( { player_id: k, cost:consumer_characters[k].max_cost, power:consumer_characters[k].max_power } )
}
return { generators, consumers }
}
Insert cell
Insert cell
[
_.isEqual(actions_to_situation(gamesCB_steps[20][4],gametype_characters[7],characters13_consumers),
{
generators: [{player_id: "1", cost: 2, power: 400, gen_id: 1},{player_id: "1", cost: 14, power: 400, gen_id: 2},{player_id: "2", cost: 4, power: 400, gen_id: 1},{player_id: "2", cost: 10, power: 400, gen_id: 2},{player_id: "3", cost: 7, power: 600, gen_id: 1},{player_id: "4", cost: 13, power: 1250, gen_id: 1}]
,consumers: [{player_id: "-1", cost: 14, power: 1250}]
})
,_.isEqual(actions_to_situation(gamesCB_steps[7][4],gametype_characters[7],characters13_consumers)
,{
generators: [{player_id: "1", cost: 2, power: 400, gen_id: 1},{player_id: "1", cost: 12, power: 500, gen_id: 2},{player_id: "2", cost: 4, power: 200, gen_id: 1},{player_id: "2", cost: 13, power: 200, gen_id: 2},{player_id: "3", cost: 7, power: 300, gen_id: 1},{player_id: "4", cost: 13, power: 1250, gen_id: 1}
]
,consumers:
[{player_id: "-1", cost: 14, power: 1250}]
})
]
Insert cell
games_br = {
let games_br = []
let prevstep = false
for( let step of gamesCB_steps ) {
// если началась новая игра, то сохраняем шаг как предыдущий и переходим к следующему
if( !prevstep || !deepEqual(prevstep.slice(0,3),step.slice(0,3)) ) {
prevstep = step
continue
}
let mode = { 1:'B' ,3:'C' ,7:'CB' }[ step[2] ] // 1 - Бертран, 3 - Курно, 7 - Курно+Бертран
let actions = prevstep[4]
// считаем ситуацию на прошлом шаге
let prevsit = actions_to_situation(actions, gametype_characters[step[2]], characters13_consumers)
let bar = {year:step[0] ,serie:step[1] ,gametype_name:actions[0].gametype_name ,period:step[3] ,model_id: 'br'} // Общие поля для добавления
for( let pl_id of [1,2,3] ) {
let [br_payoff ,br_action ,test] = best_response(pl_id, gametype_characters[step[2]][pl_id], prevsit, mode)
games_br.push(_.assign({player:pl_id ,gencons:"G1" ,powercost:"P" ,bid: br_action.br_power, model_payoff:br_payoff}, bar))
games_br.push(_.assign({player:pl_id ,gencons:"G1" ,powercost:"C" ,bid: br_action.br_cost, model_payoff:br_payoff}, bar))
if( br_action.br_cost2 > -1 ) {
games_br.push(_.assign({player:pl_id ,gencons:"G2" ,powercost:"P" ,bid: br_action.br_power2, model_payoff:br_payoff}, bar))
games_br.push(_.assign({player:pl_id ,gencons:"G2" ,powercost:"C" ,bid: br_action.br_cost2, model_payoff:br_payoff}, bar))
}
}
prevstep = step
}
return games_br
}
Insert cell
games_13_br = {
let games_br = []
let prevstep = false
for( let step of games_steps ) {
// если началась новая игра, то сохраняем шаг как предыдущий и переходим к следующему
if( !prevstep || !deepEqual(prevstep.slice(0,3),step.slice(0,3)) ) {
prevstep = step
continue
}
let mode = { 1:'B' ,3:'C' ,7:'CB' }[ step[2] ] // 1 - Бертран, 3 - Курно, 7 - Курно+Бертран
let actions = prevstep[4]
// считаем ситуацию
let sit = actions_to_situation(actions, gametype_characters[step[2]], characters13_consumers)
let bar = {year:step[0] ,serie:step[1] ,gametype_name:actions[0].gametype_name ,period:step[3] ,model_id: 'br'} // Общие поля для добавления
for( let pl_id of [1,2,3] ) {
let [br_payoff ,br_action ,test] = best_response(pl_id, gametype_characters[step[2]][pl_id], sit, mode)
games_br.push(_.assign({player:pl_id ,gencons:"G1" ,powercost:"P" ,bid: br_action.br_power, model_payoff:br_payoff}, bar))
games_br.push(_.assign({player:pl_id ,gencons:"G1" ,powercost:"C" ,bid: br_action.br_cost, model_payoff:br_payoff}, bar))
if( br_action.br_cost2 > -1 ) {
games_br.push(_.assign({player:pl_id ,gencons:"G2" ,powercost:"P" ,bid: br_action.br_power2, model_payoff:br_payoff}, bar))
games_br.push(_.assign({player:pl_id ,gencons:"G2" ,powercost:"C" ,bid: br_action.br_cost2, model_payoff:br_payoff}, bar))
}
}
}
return games_br
}
Insert cell
games_br.slice(0,4)
Insert cell
Insert cell
Insert cell
games_br_map = _.groupBy(games_br,d=>''+d.year+'-'+d.serie+'-'+d.period+'-'+d.player)
Insert cell
games_13_br_map = _.groupBy(games_13_br,d=>''+d.year+'-'+d.serie+'-'+d.period+'-'+d.player)
Insert cell
Insert cell
games_7_refl_021 = calc_reflexive_model([0,2,1] ,gamesCB_steps ,gametype_characters ,characters13_consumers ,games_br_map)
Insert cell
games_13_refl_021 = calc_reflexive_model([0,2,1] ,games_steps ,gametype_characters ,characters13_consumers ,games_13_br_map)
Insert cell
Insert cell
function add_rank0_actions( to_array ,player_id ,actions ,bar ){
// rank 0 powercost bid
let [c ,p ,c2 ,p2] = rank0_action(player_id ,actions)
bar.model_id = "refl-rank0"
to_array.push(_.assign({player:player_id ,gencons:"G1" ,powercost:"P" ,bid: p, model_payoff:null}, bar))
to_array.push(_.assign({player:player_id ,gencons:"G1" ,powercost:"C" ,bid: c, model_payoff:null}, bar))
if( !(c2===undefined) ) {
to_array.push(_.assign({player:player_id ,gencons:"G2" ,powercost:"P" ,bid: p2, model_payoff:null}, bar))
to_array.push(_.assign({player:player_id ,gencons:"G2" ,powercost:"C" ,bid: c2, model_payoff:null}, bar))
}
}
Insert cell
function add_rank1_actions(to_array ,br_of_player) {
for (let a of br_of_player) {
to_array.push(a)
}
}
Insert cell
function add_rank2_actions(to_array ,player_id ,situation ,step ,calculatedbr_map ,bar ,generators_characters ,mode) {
let refl_sit = JSON.parse(JSON.stringify(situation)) // deep copy object

let other_players = [1,2,3].filter(d=>d!=player_id)
let rank1_gens = refl_sit.generators.filter( g=>g.player_id == other_players[0] )
let br_actions = calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+other_players[0]] // think about player as rank 1
let second_generator = false
// вставляем наилучший ответ игрока в его ситуацию
for ( let act of br_actions ) {
let gen_ind = parseInt(act.gencons[1]);// из строки "G1" берём 1
let g = rank1_gens.find(d=>d.gen_id==gen_ind);
if ( gen_ind == 2 )
second_generator = true // флаг что была заявка по второму генератору
if( act.powercost == 'C' )
g.cost = act.bid
if( act.powercost == 'P' )
g.power = act.bid
}

rank1_gens = refl_sit.generators.filter( g=>g.player_id == other_players[1] )
br_actions = calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+other_players[1]] // think about player as rank 1
second_generator = false
// вставляем наилучший ответ игрока в его ситуацию
for ( let act of br_actions ) {
let gen_ind = parseInt(act.gencons[1]);// из строки "G1" берём 1
let g = rank1_gens.find(d=>d.gen_id==gen_ind);
if( _.isUndefined(g) ) console.log( 'here: ',step )
if ( gen_ind == 2 )
second_generator = true // флаг что была заявка по второму генератору
if( act.powercost == 'C' )
g.cost = act.bid
if( act.powercost == 'P' )
g.power = act.bid
}
bar.model_id = "refl-rank2"
let [br_payoff ,br_action ,test] = best_response(player_id, generators_characters[step[2]][player_id], refl_sit, mode)
to_array.push(_.assign({player:player_id ,gencons:"G1" ,powercost:"P",bid: br_action.br_power, model_payoff:br_payoff}, bar))
to_array.push(_.assign({player:player_id ,gencons:"G1" ,powercost:"C",bid: br_action.br_cost, model_payoff:br_payoff}, bar))
if( br_action.br_cost2 > -1 ) {
to_array.push(_.assign({player:player_id ,gencons:"G2" ,powercost:"P" ,bid: br_action.br_power2, model_payoff:br_payoff}, bar))
to_array.push(_.assign({player:player_id ,gencons:"G2" ,powercost:"C" ,bid: br_action.br_cost2, model_payoff:br_payoff}, bar))
}
} // add_rank2_actions
Insert cell
_.isEqual(games_reflexive_112 ,tmp_refl)
Insert cell
tmp_refl = calc_reflexive_model([1,1,2] ,gamesCB_steps ,gametype_characters ,characters13_consumers ,games_br_map)
Insert cell
function calc_reflexive_model(ranks ,history_steps ,generators_characters ,consumer_characters ,calculatedbr_map) {
let games_refl = []
let prevstep = false
for( let step of history_steps ) { // step: 0 - год, 1 - серия (4), 2 - тип (7), 3 - период, 4 - действия
// если началась новая игра, то сохраняем шаг как предыдущий и переходим к следующему
if( !prevstep || !_.isEqual(prevstep.slice(0,3),step.slice(0,3)) ) {
prevstep = step
continue
}
let mode = { 1:'B' ,3:'C' ,7:'CB' }[ step[2] ] // 1 - Бертран, 3 - Курно, 7 - Курно+Бертран
let actions = prevstep[4]
// считаем ситуацию на прошлом шаге
let sit = actions_to_situation(actions, generators_characters[step[2]], consumer_characters)
let bar = {year:step[0] ,serie:step[1] ,gametype_name:actions[0].gametype_name ,period:step[3] ,model_id: 'refl-rank0'} // Общие поля для добавления
const pl_actions = d3.group(actions, d=>d.player)
{
let pl_id = 1;
if ( ranks[0] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[0] == 1 ) add_rank1_actions( games_refl ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[0] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
{
let pl_id = 2;
if ( ranks[1] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[1] == 1 ) add_rank1_actions( games_refl ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[1] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
{
let pl_id = 3;
if ( ranks[2] == 0 ) add_rank0_actions( games_refl ,pl_id ,actions ,bar )
if ( ranks[2] == 1 ) add_rank1_actions( games_refl ,calculatedbr_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id] )
if ( ranks[2] == 2 ) add_rank2_actions( games_refl ,pl_id ,sit ,step ,calculatedbr_map ,bar ,generators_characters ,mode )
}
prevstep = step
}// for
return games_refl
}
Insert cell
/*games_reflexive_112_old = {
let games_refl = []
let prevstep = false
for( let step of games_steps ) {
// если началась новая игра, то сохраняем шаг как предыдущий и переходим к следующему
if( !prevstep || !_.isEqual(prevstep.slice(0,3),step.slice(0,3)) ) {
prevstep = step
continue
}
let mode = ( step[2] == 1 ) ? 'B' : 'C' // 1 - Бертран, 3 - Курно
let actions = prevstep[4]
// считаем ситуацию
let sit = actions_to_situation(actions, characters13, characters13_consumers)
for( let i = 0 ; i < actions.length ; i++ ) {// считает best response для всех игроков
let pl_id = actions[i].player
if( pl_id == 1 ) {
// rank 1
let {model_cost ,model_power} = games_br_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id]
games_refl.push({year:step[0] ,serie:step[1] ,gametype_name:actions[i].gametype_name ,period:step[3] ,player:pl_id ,model_cost:model_cost ,model_power:model_power, model_payoff:null, model_id: 'refl-rank1'})
}
else if( pl_id == 2 ) {
// rank 1
let {model_cost ,model_power} = games_br_map[step[0]+'-'+step[1]+'-'+step[3]+'-'+pl_id]
games_refl.push({year:step[0] ,serie:step[1] ,gametype_name:actions[i].gametype_name ,period:step[3] ,player:pl_id ,model_cost:model_cost ,model_power:model_power, model_payoff:null, model_id: 'refl-rank1'})
}
else if( pl_id == 3 ) {
// rank 2
let refl_sit = JSON.parse(JSON.stringify(sit))
let pl1_gen = refl_sit.generators.filter( g=>g.player_id==1 )[0]
,pl2_gen = refl_sit.generators.filter( g=>g.player_id==2 )[0];
{let {model_cost ,model_power} = games_br_map[step[0]+'-'+step[1]+'-'+step[3]+'-1']
pl1_gen.cost = model_cost
pl1_gen.power = model_power}
{let {model_cost ,model_power} = games_br_map[step[0]+'-'+step[1]+'-'+step[3]+'-2']
pl2_gen.cost = model_cost
pl2_gen.power = model_power}
let [br_payoff ,br_cost ,br_power ,test] = best_response(pl_id, characters13[pl_id], refl_sit, mode)
games_refl.push({year:step[0] ,serie:step[1] ,gametype_name:actions[i].gametype_name ,period:step[3] ,player:pl_id ,model_cost:br_cost ,model_power:br_power, model_payoff:br_payoff, model_id: 'refl-rank2'})
}
}
}
return games_refl
}*/
Insert cell
function rank0_action(pl_id ,actions){
let cost, power ,cost2=undefined ,power2=undefined;
for( let bid of actions ) {
if ( bid.player == pl_id ) {
if ( bid.gencons == 'G1' && bid.powercost == 'P' ) power = bid.bid
if ( bid.gencons == 'G1' && bid.powercost == 'C' ) cost = bid.bid
if ( bid.gencons == 'G2' && bid.powercost == 'P') power2 = bid.bid
if ( bid.gencons == 'G2' && bid.powercost == 'C') cost2 = bid.bid
}
}
return [cost ,power ,cost2 ,power2]
}
Insert cell
Insert cell
[_.isEqual(rank0_action(2,gamesCB_steps[2][4]) ,[4,400,11,400])
,_.isEqual(rank0_action(1,games_steps[12][4]) ,[6,undefined,undefined,undefined])
,_.isEqual(rank0_action(3,games_steps[4][4]) ,[undefined ,300 ,undefined ,undefined])
]
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more