////////////////////////////////////////////////////////////////////////////
// Model CENTRALA.CPP             SIMLIB/C++
//
// Příklad simulačního programu - hovory přes centrálu
//
// Velký podnik má vnitřní telefonní síť se 200 klapkami, spojenou přes
// centrálu s 6 telefony s veřejnou sití. Předpokládejme, že požadavky
// spojení přicházejí z veřejné sití průměrně po 2 minutách (s exponen-
// ciálním rozložením). V případě, že klapka není volná s pravděpodob-
// ností 90% si volající počká než se uvolní. Hovor trvá průměrně 7minut.
// Současně se uskutečňují vnitřní hovory průměrně po 30 sekund a trvají
// průměrně 3 minuty. Přibližně po 10 minutách přijde požadavek na hovor
// zevnitř ven, který trvá průměrně 10 minut. Zjistěte průměrné zatížení
// centrály a průměrné doby čekání na spojení vnějších
// a vnitřních hovorů.
//

#include "simlib.h"

////////////////////////////////////////////////////////////////////////////
// časové konstanty  (za jednotku času považujeme 1 minutu)
const double DOBA_SIMULACE       = 8*60;// 8 hodin

// střední doba mezi příchody:
const double PRICHOD_VNEJSICH    = 2;   // vnějších požadavků
const double PRICHOD_VNITRNICH   = 0.5; // vnitřních požadavků
const double PRICHOD_ZEVNITR_VEN = 10;  // požadavků zevnitř ven

// doby hovoru v jednotlivých případech:
const double HOVOR_VNEJSI        = 7;
const double HOVOR_VNITRNI       = 3;
const double HOVOR_ZEVNITR_VEN   = 10;

////////////////////////////////////////////////////////////////////////////
// deklarace globálních objektů
const int N_TEL = 200;          // počet telefonů
Store Centrala("Centrála",6);   // centrála - kapacita 6 spojení najednou
Facility Telefon[N_TEL];        // telefony

Histogram Tabulka1("Čekaní na spojení: vnitřní požadavky",0,0.1,20);
Histogram Tabulka2("Čekaní na spojení: vnější požadavky",0,0.1,20);

// náhodný výběr telefonu (rovnoměrné rozdělení) 
int RandomTel() {
    return int(N_TEL*Random()); //  0 .. N_TEL-1
}

////////////////////////////////////////////////////////////////////////////
// třídy modelující hovory
//
class Hovor : public Process {
 protected:
   double prichod;             // doba vstupu požadavku do vnitřní sítě
   int odkud, kam;             // čísla telefonů (-1 == venku)
 public:
   Hovor() : prichod(0), odkud(-1), kam(-1) { Activate(); }
};

class HovorZvenku : public Hovor { // vnější požadavky
   void Behavior() {
      kam = RandomTel();        // komu se volá
      Enter(Centrala,1);        // obsadí jeden z telefonů centrály
      prichod = Time;           // požadavek vstoupil do vnitřní sítě
      if (!Telefon[kam].Busy() || Random()<0.9) {
	 // případ, že volaný telefon je volný, anebo obsazený ale
	 // volající je ochoten čekat (p=90%).
	 Seize(Telefon[kam]);      // obsazení nebo čekání
	 Tabulka2(Time-prichod);   // záznam doby čekání do tabulky
	 Wait(Exponential(HOVOR_VNEJSI)); // probíhá hovor
	 Release(Telefon[kam]);    // zavěšení telefonu = uvolnění linky
      }
      Leave(Centrala,1);           // uvolnění jednoho telefonu centrály
   } //Behavior
 public:
   static void Create() { new HovorZvenku; }
};

class VnitrniHovor : public Hovor { // hovory uvnitř podniku
   double prichod;              // doba příchodu požadavku
   void Behavior() {
      // náhodně vybere volající telefon - 'odkud' (musí být volný)
      do odkud=RandomTel(); while(Telefon[odkud].Busy());
      prichod=Time;
      Seize(Telefon[odkud]);    // zvedne telefon (obsadí vnitřní linku)
      // náhodně vybere volané číslo telefonu - kam (podmínka: kam!=odkud)
      do kam=RandomTel(); while(kam==odkud);
      // vytočí číslo a čeká...
      Seize(Telefon[kam]);      // volaný zvedá telefon
      Tabulka1(Time-prichod);   // záznam doby čekání
      Wait(Exponential(HOVOR_VNITRNI)); // probíhá hovor
      Release(Telefon[kam]);    // hovor skončil = uvolnění linek
      Release(Telefon[odkud]);
   } //Behavior
 public:
   static void Create() { new VnitrniHovor; }
};

class HovorZevnitrVen : public Hovor { // požadavky na hovory ven
   void Behavior() {
      // náhodně vybere volající telefon - 'odkud' (musí být volný)
      do odkud=RandomTel(); while(Telefon[odkud].Busy());
      Seize(Telefon[odkud]);    // zvedne telefon (obsadí linku)
      Enter(Centrala,1);        // obsadí jeden z telefonů centrály
      Wait(Exponential(HOVOR_ZEVNITR_VEN));  // probíhá hovor
      Leave(Centrala,1);        // uvolnění telefonu centrály
      Release(Telefon[odkud]);  // zavěsí telefon = uvolnění linky
   } //Behavior
 public:
   static void Create() { new HovorZevnitrVen; }
};

/////////////////////////////////////////////////////////////////////////////
// generátor požadavků
//
typedef void (*CreatePtr_t)();         // typ ukazatel na statickou metodu
class Generator : public Event {       // generátor vnějších požadavků
   CreatePtr_t create;  // ukazatel na metodu Create()
   double dt;           // interval mezi vytvořením požadavků
   void Behavior() {
      create();                        // generování požadavku
      Activate(Time+Exponential(dt));  // další požadavek
   }
 public:
   Generator(CreatePtr_t p, double _dt) : create(p), dt(_dt) {
     Activate();
   }
};

/////////////////////////////////////////////////////////////////////////////
// Experiment
//
int main() {
   SetOutput("centrala.out");
   _Print(" CENTRALA - model telefonování přes centrálu\n");
   Init(0,DOBA_SIMULACE);                // inicializace experimentu
   // aktivace generátorů požadavků
   new Generator(HovorZvenku::Create, PRICHOD_VNEJSICH);
   new Generator(VnitrniHovor::Create, PRICHOD_VNITRNICH);
   new Generator(HovorZevnitrVen::Create, PRICHOD_ZEVNITR_VEN);
   // simulace
   Run();
   // tisk výsledků
   Centrala.Output();
   Tabulka1.Output();
   Tabulka2.Output();
   return 0;
}

// konec


syntax highlighted by Code2HTML, v. 0.9.1