MultiAgentDecisionProcess  Release 0.2.1
ProblemFireFighting.cpp
Go to the documentation of this file.
1 
27 #include <algorithm>
28 
29 #include "ProblemFireFighting.h"
30 #include "IndexTools.h"
31 
32 
33 #define DEBUG_PFF 0
34 #define DEBUG_CTM 0 //Create Trans Model
35 #define DEBUG_COM 0 //Create Obs Model
36 #define DEBUG_CJA 0
37 #define DEBUG_CJO 0
38 #define DEBUG_CA 0
39 #define DEBUG_CO 0
40 
41 
42 using namespace std;
43 
44 //Default constructor
46  size_t nrAgents, size_t nrHouses, size_t nrFLs,
47  double costOfMove, bool forcePositionRepres)
48  :
50  SoftPrintBriefDescription(nrAgents, nrHouses, nrFLs),
51  SoftPrintDescription(nrAgents, nrHouses, nrFLs),
52  SoftPrintBriefDescription(nrAgents, nrHouses, nrFLs)
53  )
54  ,_m_nrAgents(nrAgents)
55  ,_m_nrHouses(nrHouses)
56  ,_m_nrFireLevels(nrFLs)
57 {
58  SetSparse(true);
59  SetNrAgents(nrAgents);
60 
61 
62  double S = pow((double)nrFLs, (double)nrHouses);
63  _m_nrJointFirelevels = (size_t) S;
64  _m_nrFLs_vec = vector<size_t>(nrHouses, nrFLs);
65 
66  //Create states, and ISD
67  if(costOfMove > 0.0 || forcePositionRepres)
68  {
69  cout << "Including position"<<endl;
70  _m_includePositions = true;
71  //we're duplicating the generation of states as the matlab code does
72  //(this is not the best thing as it generates states where one agent
73  //is in a start state and the other is not...)
74 
75 
76  //the s_vec has the form <fl...fl_h, pos...pos_n>
77  _m_nrStateFeatures = nrHouses+nrAgents;
78  size_t nrPos = nrHouses+1; //include the 'start' position.
79 
80  _m_nrFLs_vec = vector<size_t>(nrHouses, nrFLs);
81  vector< size_t > nrPos_vec = vector<size_t>(nrAgents, nrPos);
83  _m_nrPerStateFeatureVec.insert(
84  _m_nrPerStateFeatureVec.end(), //insert position
85  nrPos_vec.begin(), //the stuff that is
86  nrPos_vec.end() //appended...
87  );
88  if(DEBUG_PFF)
89  cout << "_m_nrPerStateFeatureVec=" <<
90  SoftPrintVector(_m_nrPerStateFeatureVec) << endl;
91  size_t nrS=1;
92  for(vector<size_t>::const_iterator it = _m_nrPerStateFeatureVec.begin();
93  it < _m_nrPerStateFeatureVec.end();
94  it++)
95  nrS *= *it;
96 
97  vector<double> isd(nrS, 0.0);
98  double nrStartStates = pow((double)nrFLs, (double)nrHouses);
99  double ssprob = 1.0 / nrStartStates;
100 
101  for(Index sI = 0; sI < nrS; sI++)
102  {
103  vector< Index> s_vec = GetStateVector(sI);
104  stringstream ss;
105  ss << "S_";
106  Index t1;
107  for(t1 = 0; t1 < nrHouses; t1++)
108  ss << "f" << s_vec.at(t1);
109  bool isStartState = true;
110  for(; t1 < _m_nrStateFeatures; t1++)
111  {
112  Index hI = s_vec.at(t1);
113  ss << "h";
114  if(hI == nrHouses) //start position
115  ss << "S";
116  else
117  {
118  ss << hI;
119  isStartState = false;
120  }
121  }
122  this->AddState(ss.str());
123  if(isStartState)
124  isd.at(sI) = ssprob;
125 
126  if(DEBUG_PFF)
127  {
128  cout << "added " << this->GetState(sI)->SoftPrintBrief()<<endl;
129  }
130  }
131  this->SetISD(isd);
132 
133  }
134  else
135  {
136  cout << "Not including positions" << endl;
137  _m_includePositions = false;
138  //the s_vec has the form <fl...fl_h>
139  _m_nrStateFeatures = nrHouses;
141 
142  if(DEBUG_PFF)
143  cout << "_m_nrPerStateFeatureVec=" <<
145 
146  size_t nrS = _m_nrJointFirelevels;
147  if(DEBUG_PFF)
148  cout << "nrStates="<<nrS<<endl;
149  for(Index sI = 0; sI < nrS; sI++)
150  {
151  vector< Index> s_vec = GetStateVector(sI);
152  stringstream ss;
153  ss << "S_" << SoftPrintVector(s_vec);
154  this->AddState(ss.str());
155  if(DEBUG_PFF)
156  {
157  cout << "added " << this->GetState(sI)->SoftPrintBrief()<<endl;
158  }
159  }
160  SetUniformISD();
161  }
162 
164  SetDiscount(1);
165 
166  // add actions:
168  if(DEBUG_CJA) cout << ">>>Creating joint actions and set..."<<endl;
169  // add joint actions
171  if(DEBUG_CA) cout << "testNRJA="<<testNRJA<<endl;
172 
174 
175  // add observations:
177  size_t testNRJO = ConstructJointObservations();
178  if(DEBUG_CO) cout << "testNRJO="<<testNRJO<<endl;
179 
181 
182  // add the transition model
183  if(DEBUG_PFF) cout << ">>>Adding Transition model..."<<endl;
186 
187  // add observation model
188  if(DEBUG_PFF) cout << ">>>Adding Observation model..."<<endl;
192 
193  // add rewards
195  FillRewardModel();
196  if(DEBUG_PFF) cout << "Model created..."<<endl;
198 }
199 
200 /*
201 //Copy constructor.
202 ProblemFireFighting::ProblemFireFighting(const ProblemFireFighting& o)
203 {
204 }
205 //Destructor
206 ProblemFireFighting::~ProblemFireFighting()
207 {
208 }
209 //Copy assignment operator
210 ProblemFireFighting& ProblemFireFighting::operator= (const ProblemFireFighting& o)
211 {
212  if (this == &o) return *this; // Gracefully handle self assignment
213  // Put the normal assignment duties here...
214 
215  return *this;
216 }
217 */
218 
220  size_t nrAgents, size_t nrHouses, size_t nrFLs)
221 {
222  stringstream ss;
223  ss << "FireFighting_" << nrAgents <<
224  "_" << nrHouses <<
225  "_" << nrFLs;
226  return ss.str();
227 }
228 
229 std::string ProblemFireFighting::SoftPrintDescription(size_t nrAgents,
230  size_t nrHouses, size_t nrFLs)
231 {
232  stringstream ss;
233  ss << "The regular (non-factored) FireFighting problem with" << nrAgents <<
234  " Agents, " << nrHouses << " houses and "
235  << nrFLs << " fire levels for each house";
236  return ss.str();
237 
238 }
239 
241 {
242  for(Index agentIndex=0; agentIndex < _m_nrAgents; agentIndex++)
243  {
244  size_t nrActionsThisAgent = _m_nrHouses;
245  _m_nrActions.push_back(nrActionsThisAgent);
246  _m_actionVecs.push_back( vector<ActionDiscrete>() );
247  for(Index actionI=0; actionI < nrActionsThisAgent; actionI++)
248  {
249  stringstream ss;
250  //ss << "Ag" <<agentIndex << ":House" << actionI;
251  ss << "go" << actionI;
252  string name = ss.str();
253  ss.str("");
254  ss << "Action " << actionI << " of agent " << agentIndex
255  << ": go to and fight fire at house "<<actionI;
256  string descr = ss.str();
257 
258  ActionDiscrete ad_temp = ActionDiscrete(actionI,name,descr);
259  _m_actionVecs[agentIndex].push_back( ad_temp );
260  }
261  }
262 }
263 
265 {
267  for(Index agentIndex=0; agentIndex < _m_nrAgents; agentIndex++)
268  {
269  size_t nrObservationsThisAgent = 2; //flames or no flames
270  _m_nrObservations.push_back(nrObservationsThisAgent);
271  _m_observationVecs.push_back( vector<ObservationDiscrete>() );
272  for(Index obsI=0; obsI < nrObservationsThisAgent; obsI++)
273  {
274 
275  string whatObs;
276  switch(obsI){
277  case(FLAMES): whatObs = "Flames__";
278  break;
279  case(NOFLAMES): whatObs = "NoFlames";
280  break;
281  }
282  stringstream ss;
283  //ss << "Ag" <<agentIndex << ":" << whatObs;
284  ss << whatObs;
285  string name = ss.str();
286  ss.str("");
287  ss << "Observation " << obsI << " of agent " << agentIndex << ": " << whatObs;
288  string descr = ss.str();
289  ObservationDiscrete od_temp = ObservationDiscrete(obsI,name,descr);
290  _m_observationVecs[agentIndex].push_back( od_temp );
291  }
292  }
293 }
294 
296 NumberOfContainedStartPositions(const vector<Index>& state)
297  const
298 {
300  return(0);
301 
302  size_t nrSPs = 0;
303  //loop over the position features:
304  for(Index i = _m_nrHouses; i < _m_nrStateFeatures; i++)
305  if(state.at(i) == _m_nrHouses) //the 'start' postion index = nrHouses
306  nrSPs++;
307  return nrSPs;
308 
309 }
310 
312 {
313  // add transitions:
314  for(Index ja=0; ja<GetNrJointActions(); ja++)
315  for(Index s1=0; s1<GetNrStates();s1++)
316  {
317 #if DEBUG_CTM
318  cout << "Transitions from s1="<<s1<<endl;
319 #endif
320  vector< Index > s1_vec = GetStateVector(s1);
321 /* skip check for matlab generation compatibility
322  size_t nrSPs1 = NumberOfContainedStartPositions(s1_vec);
323  if(nrSPs1 > 0 && nrSPs1 != GetNrAgents())
324  {
325  //illegal state, the prob. is zero except for transition
326  //to self:
327  SetTransitionProbability(s1, ja, s1, 1.0);
328  //else 0, but we do not need to add that
329  continue;
330  }
331 */
332  //Since movements are deterministic, we can simply fill out
333  //the position elements of the state factor
334  //therefore we only need to loop over joint-firelevel vectors
335  //here
336  for(Index s2=0; s2<_m_nrJointFirelevels;s2++)
337  {
338  vector< Index > s2_vec = IndexTools::JointToIndividualIndices
339  (s2, _m_nrFLs_vec);
340  //no longer necessary since we fill in the position components
341  //if(NumberOfContainedStartPositions(s2_vec) > 0)
342  //continue;
343 
344  vector< Index > s1_vec_stripped(&s1_vec[0],
345  &s1_vec[_m_nrHouses] );
346  vector< Index > ja_vec = JointToIndividualActionIndices(ja);
347  double p = ComputeTransitionProb(s1_vec_stripped,
348  ja_vec, s2_vec);
349 #if DEBUG_CTM
350  cout << "Trans from s="
351  << SoftPrintVector(s1_vec)
352  << ", a="
353  << SoftPrintVector(ja_vec)
354  << " to s'="
355  << SoftPrintVector(s2_vec)
356  << " Prob=" << p << endl;
357 #endif
358  if(p > 0.0)
359  {
360  //compute full s2 index
361  vector< Index >& full_s2 = s2_vec;
362  full_s2.insert(full_s2.end(), ja_vec.begin(), ja_vec.end());
365  SetTransitionProbability(s1, ja, fs2I, p);
366  }
367  }
368  }
369 }
370 
372  const std::vector< Index>& s1,
373  const std::vector< Index>& ja,
374  const std::vector< Index>& s2
375  ) const
376 {
377  double p = 1.0;
378  for(Index hI=0; hI < s1.size(); hI++)
379  {
380  Index curLevel = s1.at(hI);
381  Index nextLevel = s2.at(hI);
382  Index nrAgentsAtLocation = 0;
383  for(Index aI=0; aI < ja.size(); aI++)
384  if(ja.at(aI) == hI)
385  nrAgentsAtLocation++;
386 #if 0 && DEBUG_CTM
387  cout << "hI="<<hI<<" #agents="<<nrAgentsAtLocation << " ";
388 #endif
389  //this is dependent on s1 right?:
390  bool neighborIsBurning = isNeighborBurning(s1, hI);
391 
392  Index sameLevel = curLevel;
393  Index higherLevel = min((size_t)sameLevel+1, _m_nrFireLevels-1);
394  Index lowerLevel = (curLevel==0) ? 0 : (curLevel-1);
395  double p2=0.0;// the prob. factor of ThisHouseFirelevel;
396  switch(nrAgentsAtLocation)
397  {
398  case(0):
399  {
400  //this is kind of strange: when a house is not burning, but
401  //its neigbhor is, it will increase its FL with p=0.8
402  //but when it is already burning (and its neighbor is not), it
403  //increase with p=0.6...
404 
405  //fire is likely to increase
406  if(neighborIsBurning)
407  {
408  if(nextLevel == sameLevel)
409  p2+=0.2;
410  if(nextLevel == higherLevel)
411  p2+=0.8;
412  }
413  else if (curLevel == 0) //fire won't get ignited
414  {
415  if(0 == nextLevel)
416  p2=1.0;
417  else //not possible so we can quit...
418  p2=0.0;
419  }
420  else //normal burning house
421  {
422  if(nextLevel == sameLevel)
423  p2+=0.6;
424  if(nextLevel == higherLevel)
425  p2+=0.4;
426  }
427  break;
428  }
429  case(1):
430  {
431  //fire is likely to decrease
432  if(neighborIsBurning)
433  {
434  if(nextLevel == sameLevel)
435  p2+=0.4;
436  if(nextLevel == lowerLevel)
437  p2+=0.6; //.6 prob of extuinguishing 1 fl
438  }
439  else if (curLevel == 0) //fire won't get ignited
440  {
441  if(0 == nextLevel)
442  p2=1.0;
443  else //not possible so we can quit...
444  p2=0.0;
445  }
446  else //normal burning house
447  {
448  if(nextLevel == sameLevel)
449  p2+=0.0;
450  if(nextLevel == lowerLevel)
451  p2+=1.0;
452  }
453  break;
454  }
455  default:
456  {
457  //more than 1 agent: fire is extinguished
458  if(0 == nextLevel)
459  p2=1.0;
460  else //not possible so we can quit...
461  p2=0.0;
462  }
463 
464 
465  }
466 #if 0 && DEBUG_CTM
467  cout << "p=" << p << ", p2=" << p2;
468 #endif
469  p *= p2;
470 #if 0 && DEBUG_CTM
471  cout << ", new p=" << p << " - ";
472 #endif
473 
474  }
475 #if DEBUG_CTM
476  cout << "returning p=" << p << endl;
477 #endif
478  return p;
479 }
480 
481 bool ProblemFireFighting::isNeighborBurning( const std::vector< Index>& s,
482  Index hI)
483 {
484  bool b = false;
485  if(hI > 0) //check 'lower' neighbor
486  if(s.at(hI-1) > 0)
487  b = true;
488  if(hI+1 < s.size()) //check 'higher' neighbor
489  if(s.at(hI+1) > 0)
490  b = true;
491 
492  return(b);
493 
494 }
495 
497 {
498  for(Index ja=0; ja< GetNrJointActions(); ja++)
499  for(Index s1=0; s1<GetNrStates();s1++)
500  for(Index jo=0; jo<GetNrJointObservations();jo++)
501  {
502  vector< Index > ja_vec = JointToIndividualActionIndices(ja);
503  vector< Index > s1_vec = GetStateVector(s1);
504  vector< Index > jo_vec =
506 
507  double prob = ComputeObservationProb(ja_vec, s1_vec, jo_vec);
508 
509  SetObservationProbability(ja, s1, jo, prob);
510  }
511 }
513  const std::vector< Index>& ja,
514  const std::vector< Index>& s1,
515  const std::vector< Index>& jo
516  ) const
517 {
518  double p_jo = 1.0;
519  for(Index agI=0; agI < ja.size(); agI++)
520  {
521  double p_o_thisAgent = 0.0;
522  Index hI, FL;
524  {
525  hI = s1.at(_m_nrHouses + agI);
526  if(hI == _m_nrHouses) // agent at start position
527  FL = 0;
528  else
529  FL = s1.at(hI);
530  }
531  else
532  {
533  hI=ja.at(agI); //the position (house) of agI
534  FL = s1.at(hI); //the firelevel at that house
535  }
536  //we compute P(FLAMES)
537  double pFlames = 0.0;
538  switch(FL)
539  {
540  case(0): //no fire
541  pFlames = 0.2; // 0.2 prob. of incorrectly observing
542  break;
543  case(1):
544  pFlames = 0.5;
545  break;
546  default:
547  pFlames = 0.8;
548  }
549  double pNoFlames = 1.0-pFlames;
550  observation_t obsAgI = (observation_t) jo.at(agI);
551  switch(obsAgI)
552  {
553  case(FLAMES):
554  p_o_thisAgent = pFlames;
555  break;
556  case(NOFLAMES):
557  p_o_thisAgent = pNoFlames;
558  break;
559  }
560  p_jo *= p_o_thisAgent;
561  }
562  return p_jo;
563 }
565 {
566 
567  for(Index s1=0; s1<GetNrStates();s1++)
568  for(Index ja=0; ja<GetNrJointActions(); ja++)
569  for(Index s2=0; s2<GetNrStates();s2++)
570  {
571  double r = ComputeReward(s2);
572  SetReward(s1, ja, s2, r);
573  }
574 }
575 
577 {
578  vector<Index> fl_vec = GetStateVector(sI);
579  double r = 0.0;
580  //for( vector<Index>::const_iterator it = fl_vec.begin();
581  //it != fl_vec.end();
582  //it++)
583  //r -= (double) *it;
584  for(Index hI = 0; hI < _m_nrHouses; hI++)
585  r -= (double) fl_vec.at(hI);
586 
587  return(r);
588 }
589