You may think that the Perkun/Perkun2 syntax is rather odd. I was thinking about a comparison - for example with C++. And I came up with the following example:
variables
{
input variable a:{false,true},b:{false,true},c:{false,true};
output variable action:{false,true};
hidden variable d:{false,true},e:{false,true},f:{false,true};
}
Now imagine the following class in C++-like pseudocode:
class x
{
private:
class hidden { bool d,e,f; };
std::map<hidden,double> distribution;
public:
bool get_decision(bool a, bool b, bool c) const;
};
In other words we have a class with a probability distribution over a cartesian product of the hidden variables and a single function mapping the input variables into (one) output variable. Note that if there were no hidden variables then our distribution would disappear and we would have a stateless class (or simply a function) get_decision.
You might ask what is the benefit of using Perkun rather then simply hard code the function mapping input to output. I think that in simple cases it may be obviously simple to hard code it. But it is a trap. By hard coding it we do not explain the machine WHY the mapping looks so, we only provide it with the end result. We might end up with the hard coded solutions for myriads of different input sets. It might be even so that the idea of telling the machine how to derive the result from simple components (payoff,model) will be treated as highly experimental. Well, Perkun/Perkun2 are highly experimental. In spite of that I think they open intriguing possibilities as new technologies of programming.
BTW. The fact I usually only use a single output variable is a convention. You are free to use multiple output variables.
Wednesday, August 31, 2016
Tuesday, August 30, 2016
PerkunWars - a simple fantasy game based on Perkun.
I would like to introduce a small project you can download from https://sourceforge.net/projects/perkunwars/ - PerkunWars - a simple fantasy game.
In the game there is one player (Valder), three NPCs (Thragos, Dorban, Pregor) and a vampire. There are three locations (Wyzima, Shadizar and Novigrad). Click on a town to move there (you may also use a menu action).
If you meet any NPCs you may chat with them. The chat window will display something like:
Pregor >I was staying here, in Shadizar. The vampire? He is in Wyzima. I am staying here...
Thragos >I was staying here, in Shadizar. The vampire? He may be in Wyzima. He may be in Novigrad. I am staying here...
You may have noticed that Pregor and Thragos are avoiding the vampire. There is one more NPC - Dorban, who is a witcher and therefore is constantly hunting the vampire. You may attack the vampire yourself (garlic and holy water are helpful). But it makes no sense to attack him alone. You should attack him when the NPCs are around.
This simple game is based on Perkun. Open the file src/perkun_wars.cc. You will see the code creating pipes and forks. For each NPC there is a child process created (running the function main_perkun). An instance of object npc is created and it parses the Perkun specification. What is npc? See the file inc/perkun_wars.h. You will see the code:
class npc: public perkun::optimizer_with_all_data
So for each NPC (Dorban, Pregor and Thragos) there is an instance of perkun::optimizer_with_all_data with some redefined virtual functions, parsing a Perkun specification!
Now take a look at the directory perkun/final_code. It contains the Perkun specifications named after the NPCs. Take a look at the perkun/final_code/pregor_general.perkun. Note the payoff function:
payoff
{
set({where_is_Pregor=>place_Wyzima, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Wyzima, do_I_see_vampire=>true}, 0.0);
set({where_is_Pregor=>place_Shadizar, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Shadizar, do_I_see_vampire=>true}, 0.0);
set({where_is_Pregor=>place_Novigrad, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Novigrad, do_I_see_vampire=>true}, 0.0);
}
Now check the payoff for Dorban (the file perkun/final_code/dorban_general.perkun):
payoff
{
set({where_is_Dorban=>place_Wyzima, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Wyzima, do_I_see_vampire=>true}, 100.0);
set({where_is_Dorban=>place_Shadizar, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Shadizar, do_I_see_vampire=>true}, 100.0);
set({where_is_Dorban=>place_Novigrad, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Novigrad, do_I_see_vampire=>true}, 100.0);
}
Did you notice something? Of course the Dorban's payoff function makes him to follow the vampire, while Pregor tries to avoid him. This is how we use the payoff function.
The Dorban's variables are:
variables
{
input variable where_is_Dorban:
{place_Wyzima,place_Shadizar,place_Novigrad};
input variable do_I_see_vampire:{false,true};
output variable action:{do_nothing,goto_Wyzima,goto_Shadizar,goto_Novigrad};
hidden variable where_is_vampire:{place_Wyzima,place_Shadizar,place_Novigrad};
}
Note that we have one hidden variable here - where_is_vampire. Of course Dorban knows where is the vampire if he can see him (i.e. it is impossible for the vampire to be elsewhere when Dorban can see him). This is solved with the command "impossible" in the Dorban's model. But in general it is a hidden variable.
In the game there is one player (Valder), three NPCs (Thragos, Dorban, Pregor) and a vampire. There are three locations (Wyzima, Shadizar and Novigrad). Click on a town to move there (you may also use a menu action).
If you meet any NPCs you may chat with them. The chat window will display something like:
Pregor >I was staying here, in Shadizar. The vampire? He is in Wyzima. I am staying here...
Thragos >I was staying here, in Shadizar. The vampire? He may be in Wyzima. He may be in Novigrad. I am staying here...
You may have noticed that Pregor and Thragos are avoiding the vampire. There is one more NPC - Dorban, who is a witcher and therefore is constantly hunting the vampire. You may attack the vampire yourself (garlic and holy water are helpful). But it makes no sense to attack him alone. You should attack him when the NPCs are around.
This simple game is based on Perkun. Open the file src/perkun_wars.cc. You will see the code creating pipes and forks. For each NPC there is a child process created (running the function main_perkun). An instance of object npc is created and it parses the Perkun specification. What is npc? See the file inc/perkun_wars.h. You will see the code:
class npc: public perkun::optimizer_with_all_data
So for each NPC (Dorban, Pregor and Thragos) there is an instance of perkun::optimizer_with_all_data with some redefined virtual functions, parsing a Perkun specification!
Now take a look at the directory perkun/final_code. It contains the Perkun specifications named after the NPCs. Take a look at the perkun/final_code/pregor_general.perkun. Note the payoff function:
payoff
{
set({where_is_Pregor=>place_Wyzima, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Wyzima, do_I_see_vampire=>true}, 0.0);
set({where_is_Pregor=>place_Shadizar, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Shadizar, do_I_see_vampire=>true}, 0.0);
set({where_is_Pregor=>place_Novigrad, do_I_see_vampire=>false}, 100.0);
set({where_is_Pregor=>place_Novigrad, do_I_see_vampire=>true}, 0.0);
}
Now check the payoff for Dorban (the file perkun/final_code/dorban_general.perkun):
payoff
{
set({where_is_Dorban=>place_Wyzima, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Wyzima, do_I_see_vampire=>true}, 100.0);
set({where_is_Dorban=>place_Shadizar, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Shadizar, do_I_see_vampire=>true}, 100.0);
set({where_is_Dorban=>place_Novigrad, do_I_see_vampire=>false}, 0.0);
set({where_is_Dorban=>place_Novigrad, do_I_see_vampire=>true}, 100.0);
}
Did you notice something? Of course the Dorban's payoff function makes him to follow the vampire, while Pregor tries to avoid him. This is how we use the payoff function.
The Dorban's variables are:
variables
{
input variable where_is_Dorban:
{place_Wyzima,place_Shadizar,place_Novigrad};
input variable do_I_see_vampire:{false,true};
output variable action:{do_nothing,goto_Wyzima,goto_Shadizar,goto_Novigrad};
hidden variable where_is_vampire:{place_Wyzima,place_Shadizar,place_Novigrad};
}
Note that we have one hidden variable here - where_is_vampire. Of course Dorban knows where is the vampire if he can see him (i.e. it is impossible for the vampire to be elsewhere when Dorban can see him). This is solved with the command "impossible" in the Dorban's model. But in general it is a hidden variable.
New releases of Perkun and Perkun2. The problem with Perkun2 has been solved!
There is a new release of Perkun (0.1.1) and Perkun2 (0.0.3).
You may download them from https://sourceforge.net/projects/perkun/ and https://sourceforge.net/projects/perkun2/.
In Perkun there are no substantial changes, just a couple new getters. In Perkun2 there is:
I am currently trying to implement something similar to https://sourceforge.net/projects/perkunwars/ - a simple game demonstrating how to use both Perkun and Perkun2 in your own projects.
You may download them from https://sourceforge.net/projects/perkun/ and https://sourceforge.net/projects/perkun2/.
In Perkun there are no substantial changes, just a couple new getters. In Perkun2 there is:
- an extra parameter (agent name) passed to the print_prompt sub in Perl
- enhanced code to interpret the actions
- modified procedure loop
I am currently trying to implement something similar to https://sourceforge.net/projects/perkunwars/ - a simple game demonstrating how to use both Perkun and Perkun2 in your own projects.
Wednesday, August 24, 2016
What's wrong with Perkun2?
I wish to explain more precisely what is wrong with Perkun2. Imagine a specification:
values {}
agents
{
agent a1 {}
agent a2 {}
...
agent an {}
}
interfaces
{
interface a1 => a2 {}
...
interface an => a1 {}
}
In other words we have n agents performing the actions interchangeably, according to the pattern a1,a2,...,an,a1,a2,...,an,...
Now the algorithm I propose in Perkun2 consists of two parts:
What is a little problematic is the fact that the agent ai (i>1) has the model and payload defined in terms of his own variables. Quite logical. We have to use the interfaces to map these variables into the ones observable by the agent a1.
I am sorry about the trouble again. I will try to fix it. I started with the small improvement passing the current agent name to the print_prompt sub. For example you may type:
<<PERL
$$Perkun2::Optimizer::optimizer{print_prompt} =
sub
{
my ($this, $agent_name) = @_;
print "SUPER PERKUN2 (", $agent_name, ")> ";
};
PERL
(This enhancement is not published yet!) This way the Perkun2 will ask for input variables before the agents moves:
SUPER PERKUN2 (a1)>
SUPER PERKUN2 (a2)>
...
SUPER PERKUN2 (an)>
SUPER PERKUN2 (a1)>
SUPER PERKUN2 (a2)>
...
But it will find the optimal decision only for the agent a1 (even though it is observing the game for all agents).
values {}
agents
{
agent a1 {}
agent a2 {}
...
agent an {}
}
interfaces
{
interface a1 => a2 {}
...
interface an => a1 {}
}
In other words we have n agents performing the actions interchangeably, according to the pattern a1,a2,...,an,a1,a2,...,an,...
Now the algorithm I propose in Perkun2 consists of two parts:
- how to optimize the actions (output variable values) in order to maximize the expected value of the payload function
- how to interpret what has actually happened (how to update the belief)
What is a little problematic is the fact that the agent ai (i>1) has the model and payload defined in terms of his own variables. Quite logical. We have to use the interfaces to map these variables into the ones observable by the agent a1.
I am sorry about the trouble again. I will try to fix it. I started with the small improvement passing the current agent name to the print_prompt sub. For example you may type:
<<PERL
$$Perkun2::Optimizer::optimizer{print_prompt} =
sub
{
my ($this, $agent_name) = @_;
print "SUPER PERKUN2 (", $agent_name, ")> ";
};
PERL
(This enhancement is not published yet!) This way the Perkun2 will ask for input variables before the agents moves:
SUPER PERKUN2 (a1)>
SUPER PERKUN2 (a2)>
...
SUPER PERKUN2 (an)>
SUPER PERKUN2 (a1)>
SUPER PERKUN2 (a2)>
...
But it will find the optimal decision only for the agent a1 (even though it is observing the game for all agents).
Friday, August 19, 2016
WARNING: Perkun2 contains a bug!
There is a serious bug in Perkun2. It fails to interpret the input variables values properly when multiple agents are in place. I created a model for two players and found out that Perkun2 always gets "surprised".
I am very sorry about the bug, I will try to fix it.
The optimization itself seems to work properly.
I am very sorry about the bug, I will try to fix it.
The optimization itself seems to work properly.
Sunday, August 7, 2016
Perkun 0.1.0 and Perkun2 0.0.2 released!
I have released Perkun 0.1.0. There are some changes in the Perkun's behaviour:
- the default model and default payoff function are filled with zeros
- the test_model code is disabled
- the Prolog generators are better (they skip the zeros in menu set thus producing smaller Perkun code)
Subscribe to:
Posts (Atom)