SMOClosed.php 11.5 KB
<?php
    namespace frontend\models;

    use yii\base\Exception;
    use yii\base\InvalidParamException;
    use yii\base\Model;

    class SMOClosed extends Model
    {

        public $n;

        public $N;

        public $p;

        public $K;

        public $r;

        public $mu;

        public $e;

        public $b;

        public $k;

        public $probs;

        public $SMO;

        public $C;

        public $L;

        public $R;

        public $M;

        public $La;

        public $T;

        public $Q;

        function __construct(array $config)
        {
            parent::__construct($config);
            if(!intval($this->n)) {
                throw new InvalidParamException('Кількість СМО має бути цілим невід\'ємним числом');
            } else {
                $this->k[ 0 ] = 0;
                for($i = 1; $i <= $this->n; $i++) {
                    for($j = 1; $j <= $this->n; $j++) {
                        $this->p[ $i ][ $j ] = 0;
                        $this->r[ $i ] = 1;
                        $this->mu[ $i ] = 0;
                    }
                }
            }
        }

        public function attributeLabels()
        {
            return [
                'n'     => 'Кількість систем масового обслуговування (n)',
                'N'     => 'Кількість вимог в мережі масового обслуговування (N)',
                'p'     => 'Матриця ймовірностей (p<sub>i,j</sub>)',
                'K'     => 'Показники системи масового обслуговування (K)',
                'r'     => 'Кількість каналів обслуговування (r)',
                'mu'    => 'Інтенсивність обслуговування каналом (1/&mu;)',
                'e'     => 'Коефіцієнт передачі (e)',
                'b'     => 'Початкова СМО (e = 1)',
                'k'     => 'Масив вимог',
                'probs' => 'Допоміжні функції p<sub>i</sub>(k)',
                'SMO'   => 'Ймовірність перебування j вимоги в i-тій СМО P<sub>СМО<sub>i</sub></sub>(j)',
                'C'     => 'Нормуючий множник (C(N))',
                'L'     => 'Середня кількість вимог у черзі СМО<sub>i</sub> (L<sub>i</sub>)',
                'R'     => 'Середня кількість зайнятих пристроїв у СМО<sub>i</sub> (R<sub>i</sub>)',
                'M'     => 'Середня кількість вимог у СМО<sub>i</sub> (M<sub>i</sub>)',
                'La'    => 'Інтенсивність вихідного потоку вимог у СМО<sub>i</sub> (&lambda;<sub>i</sub>)',
                'T'     => 'Середній час перебування вимоги у СМО<sub>i</sub> (T<sub>i</sub>)',
                'Q'     => 'Середній час очікування у черзі СМО<sub>i</sub> (Q<sub>i</sub>)',
            ];
        }

        public function rules()
        {
            return [
                [
                    [ 'b' ],
                    'required',
                ],
                [
                    [
                        'N',
                    ],
                    'integer',
                    'min' => 1,
                ],
                [
                    [ 'n' ],
                    'integer',
                    'min' => 2,
                    'max' => 3,
                    'message' => 'На даний момент допустимі значення кількості СМО лише 2 або 3',
                ],
                [
                    [
                        'p',
                        'mu',
                    ],
                    'safe',
                ],
                [
                    [ 'r' ],
                    'each',
                    'rule' => [
                        'integer',
                        'min' => 1,
                    ],
                ],
                [
                    [ 'mu' ],
                    'each',
                    'rule' => [
                        'number',
                        'min' => 0,
                    ],
                ],
                [
                    [ 'b' ],
                    'integer',
                    'min' => 1,
                ],
                [
                    [ 'b' ],
                    'compare',
                    'compareAttribute' => 'n',
                    'operator'         => '<=',
                ],
                [
                    [ 'b' ],
                    'default',
                    'value' => 1,
                ],
            ];
        }

        public function buildk()
        {
            if(!empty($this->N)) {
                for($i = 1; $i <= $this->N; $i++) {
                    $this->k[$i] = $i;
                }
            }
        }

        public function buildE($antiloop = true)
        {
            $this->e[ $this->b ] = 1;
            for($k = 1; $k <= $this->n; $k++) {
                if($k == $this->b) {
                    continue;
                } else {
                    $this->e[ $k ] = '';
                }
            }
            foreach($this->p as $i => $vals) {
                foreach($vals as $j => $val) {
                    if($j == $this->b) {
                        continue;
                    }
                    if($val != 0) {
                        $this->e[ $j ] .= '{' . $i . '};';
                    }
                }
            }
            do {
                $iteration = 0;
                $found = 0;
                foreach($this->e as $i => $val) {
                    if(!preg_match('/\{\d\}/', $val)) {
                        foreach($this->e as $j => $value) {
                            if(preg_match('/\{' . $i . '\}/', $this->e[ $j ])) {
                                $this->e[ $j ] = preg_replace('/\{' . $i . '\}/', ( $this->p[ $i ][ $j ] * $val ), $this->e[ $j ]);
                                $found = 1;
                            }
                        }
                    }
                }
                if($antiloop) {
                    $iteration++;
                }
            } while($found && $iteration < 100);
            foreach($this->e as $i => $val) {
                if(strpos($val, ';') !== false) {
                    $this->e[ $i ] = array_sum(explode(';', $val));
                }
            }
        }

        public function buildProbs()
        {
            for($q = 1; $q <= $this->n; $q++) {
                foreach($this->k as $k) {
                    $prob = pow($this->e[ $q ] * $this->mu[ $q ], $k);
                    if($k <= $this->r[ $q ]) {
                        $prob = $prob * 1 / $this->factorial($k);
                    } else {
                        $prob = $prob * 1 / $this->factorial($this->r[ $q ]) * pow($this->r[ $q ], ( $k - $this->r[ $q ] ));
                    }
                    $this->probs[ $q ][ $k ] = $prob;
                    unset( $prob );
                }
            }
        }

        public function factorial($x)
        {
            $x = intval($x);
            if(!is_int($x) || $x < 0) {
                throw new Exception('Factorial must be greater than 0');
            }
            $res = 1;
            for($i = 1; $i <= $x; $i++) {
                $res *= $i;
            }
            return $res;
        }

        public function buildC()
        {
            $result = 0;
            if($this->n == 2) {
                for($a = 0; $a <= $this->N; $a++) {
                    $result += $this->probs[1][$a] * $this->probs[2][$this->N - $a];
                }
            } elseif($this->n == 3) {
                for($a = 0; $a <= $this->N; $a++) {
                    $sum = 0;
                    for($b = 0; $b <= ( $this->N - $a ); $b++) {
                        $sum += $this->findSum($b, $a);
                    }
                    $result += $sum * $this->probs[ 1 ][ $a ];
                    unset( $sum );
                }
            }
            $this->C = pow($result, ( -1 ));
        }

        public function findSum($b, $a)
        {
            return $this->probs[ 2 ][ $b ] * $this->probs[ 3 ][ $this->N - $a - $b ];
        }

        public function buildSMO()
        {
            for($q = 1; $q <= $this->n; $q++) {
                foreach($this->k as $k) {
                    $sum = 0;
                    if($this->n == 2) {
                        if($q == 1) {
                            $sum += $this->probs[1][$k]*$this->probs[2][$this->N - $k];
                        } elseif($q == 2) {
                            $sum += $this->probs[1][$this->N - $k]*$this->probs[2][$k];
                        }
                    } elseif($this->n == 3) {
                        for($a = 0; $a <= ($this->N - $k); $a++) {
                            if($q == 1) {
                                $sum += $this->probs[1][$k]*$this->probs[2][$a]*$this->probs[3][($this->N - $k - $a)];
                            } elseif($q == 2) {
                                $sum += $this->probs[1][$a]*$this->probs[2][$k]*$this->probs[3][($this->N - $k - $a)];
                            } elseif($q ===3) {
                                $sum += $this->probs[1][$a]*$this->probs[2][($this->N - $k - $a)]*$this->probs[3][$k];
                            }
                        }
                    }
                    $this->SMO[$q][$k] = $sum*$this->C;
                    unset($sum);
                }
            }
        }

        public function testSMO()
        {
            $message = '';
            foreach($this->SMO as $K => $vals) {
                $message .= 'SUM of SMO'.$K.': ';
                $sum = 0;
                foreach($vals as $val) {
                    $sum += $val;
                }
                $message .= $sum.'; <br>';
                unset($sum);
            }
            return $message;
        }

        public function buildL()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $sum = 0;
                for($j = ($this->r[$i] + 1); $j <= $this->N; $j++) { // Maybe error
                    $sum += ($j - $this->r[$i]) * $this->SMO[$i][$j];
                }
                $this->L[$i] = $sum;
                unset($sum);
            }
        }

        public function buildR()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $sum = 0;
                for($j = 0; $j <= ($this->r[$i] - 1); $j++) {
                    $sum += ($this->r[$i] - $j) * $this->SMO[$i][$j];
                }
                $sum = $this->r[$i] - $sum;
                $this->R[$i] = $sum;
                unset($sum);
            }
        }

        public function buildM()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $this->M[$i] = $this->L[$i] + $this->R[$i];
            }
        }

        public function buildLa()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $this->La[$i] = $this->R[$i] * pow($this->mu[$i], (-1));
            }
        }

        public function buildT()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $this->T[$i] = $this->M[$i] / $this->La[$i];
            }
        }

        public function buildQ()
        {
            for($i = 1; $i <= $this->n; $i++) {
                $this->Q[$i] = $this->L[$i] / $this->La[$i];
            }
        }
    }