Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 140
ParetoAbc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 5
1406.00
0.00% covered (danger)
0.00%
0 / 140
 deduceIntento
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 41
 deduce
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 33
 byValue
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 30
 byNumberOfItems
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 32
 array_key_last
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 4
<?php
namespace ia\Lib;
class ParetoAbc {
    public static function deduceIntento($products, $levels = ['A','B','C']) {
        if(empty($products) || empty($levels)) {
            return [];
        }
        arsort($products, SORT_NUMERIC);
echo "<pre>prod = ".print_r($products, true);
        $run = 0;
        foreach($products as $productId => $value) {
            $run += $value;
            $acc[$productId] = $run;
        }
echo "<pre>acc = ".print_r($acc, true);
        foreach($acc as $productId => $value) {
            //@TODO que hacer en valores negativos ? aceptar, pasar a cero, abs, rechazar?
            if(isset($valuePrev)) {
                $diff[$productId] = abs($valuePrev - $value);
            } else {
                $diff[$productId] = 0;
            }
            $valuePrev = $value;
        }
        arsort($diff, SORT_NUMERIC);
        $topInflection = array_slice($diff, 0, count($levels)-1, true);
echo "<pre>diff = ".print_r($diff, true);
echo "<pre>topf = ".print_r($topInflection, true);
        foreach($levels as $levelKey) {
            $levelValue[$levelKey] = 0.00;
            $productsPerLevel[$levelKey] = [];
        }
        $levelsClone = $levels;
        $currentKey = array_shift($levelsClone);
        foreach($products as $productId => $value) {
            if(!empty($levelsClone) && array_key_exists($productId, $topInflection)) {
                $currentKey = array_shift($levelsClone);
            }
            $productsPerLevel[$currentKey][] = $productId;
            $levelValue[$currentKey] += $value;
        }
        $sumProducts = array_sum($products);
        $countProducts = count($products);
        foreach($levels as $levelKey) {
            $numItems = count($productsPerLevel[$levelKey]);
            $pareto[$levelKey] = [
                'percent_of_value' => $levelValue[$levelKey]/$sumProducts,
                'total_value' => $levelValue[$levelKey],
                'percent_of_items' => $numItems / $countProducts,
                'number_of_items' => $numItems,
            ];
        }
        return [
            'classified' => $productsPerLevel,
            'pareto' => $pareto,
            'levels' => $levels,
            'totals' => ['sum' => $sumProducts, 'count' => $countProducts],
        ];
    }
    public static function deduce($products, $levels = ['A','B','C']) { // no jala bien
        if(empty($products) || empty($levels)) {
            return [];
        }
        arsort($products, SORT_NUMERIC);
        foreach($products as $productId => $value) {
            //@TODO que hacer en valores negativos ? aceptar, pasar a cero, abs, rechazar?
            if(isset($valuePrev)) {
                $diff[$productId] = abs($valuePrev - $value);
            } else {
                $diff[$productId] = 0;
            }
            $valuePrev = $value;
        }
//echo "<pre>diff = ".print_r($diff, true);
        arsort($diff, SORT_NUMERIC);
        $topInflection = array_slice($diff, 0, count($levels)-1, true);
        foreach($levels as $levelKey) {
            $levelValue[$levelKey] = 0.00;
            $productsPerLevel[$levelKey] = [];
        }
        $levelsClone = $levels;
        $currentKey = array_shift($levelsClone);
        foreach($products as $productId => $value) {
            if(!empty($levelsClone) && array_key_exists($productId, $topInflection)) {
                $currentKey = array_shift($levelsClone);
            }
            $productsPerLevel[$currentKey][] = $productId;
            $levelValue[$currentKey] += $value;
        }
        $sumProducts = array_sum($products);
        $countProducts = count($products);
        foreach($levels as $levelKey) {
            $numItems = count($productsPerLevel[$levelKey]);
            $pareto[$levelKey] = [
                'percent_of_value' => $levelValue[$levelKey]/$sumProducts,
                'total_value' => $levelValue[$levelKey],
                'percent_of_items' => $numItems / $countProducts,
                'number_of_items' => $numItems,
            ];
        }
        return [
            'classified' => $productsPerLevel,
            'pareto' => $pareto,
            'levels' => $levels,
            'totals' => ['sum' => $sumProducts, 'count' => $countProducts],
        ];
    }
    public static function byValue($products, $levels = ['A' => 0.8, 'B' => 0.15, 'C' => 0.05]) {
        if(empty($products) || empty($levels)) {
            return [];
        }
        arsort($products, SORT_NUMERIC);
        $sumProducts = array_sum($products);
        foreach($levels as $levelKey => $percent) {
            $limits[$levelKey] = ceil($percent *  $sumProducts);
        }
//echo "<pre>limits = ".print_r($limits, true);
        $limitsClone = array_reverse($limits);
        $currentKey = self::array_key_last($limitsClone);
        $levelLimit = array_pop($limitsClone);
        $tot = 0.00;
        foreach($products as $k => $value) {
            if(  $tot >= $levelLimit && !empty($limitsClone)  ) { //@TODO minimum diference to consider equal?
                $currentKey = self::array_key_last($limitsClone);
                $levelLimit = array_pop($limitsClone);
                $tot = 0.00;
            }
            $tot += $value;
            $productsPerLevel[$currentKey][$k] = $value;
        }
        $countProducts = count($products);
        foreach($productsPerLevel as $level => $items) {
            $totalItems = array_sum($items);
            $numberItems = count($items);
            $pareto[$level] = [
                'percent_of_value' => $totalItems/$sumProducts,
                'total_value' => $totalItems,
                'percent_of_items' => $numberItems/$countProducts,
                'number_of_items' => $numberItems,
            ];
        }
        return [
            'classified' => $productsPerLevel,
            'pareto' => $pareto,
            'levels' => $levels,
            'totals' => ['sum' => $sumProducts, 'count' => $countProducts],
        ];
    }
    public static function byNumberOfItems($products, $levels = ['A' => 0.2, 'B' => 0.25, 'C' => 1 - 0.2 - 0.25]) {
        if(empty($products) || empty($levels)) {
            return [];
        }
        arsort($products, SORT_NUMERIC);
        $sliceFrom = 0;
        $sumProducts = array_sum($products);
        $countProducts = count($products);
        $lastKey = self::array_key_last($levels);
        foreach($levels as $levelKey => $percent) {
            $itemsInLevel = ceil($percent * $countProducts); //@TODO ceil, floor, round?
            if($itemsInLevel <= 0) {
                $productsPerLevel[$levelKey] = ['XEO'];
                $pareto[$levelKey] = [
                    'percent_of_value' => 0.00,
                    'total_value' => 0.00,
                    'percent_of_items' => 0.00,
                    'number_of_items' => $itemsInLevel,
                ];
            } else {
                if($levelKey === $lastKey) {
                    $items = array_slice($products, $sliceFrom);
                } else {
                    $items = array_slice($products, $sliceFrom, $itemsInLevel);
                    $sliceFrom += $itemsInLevel;
                }
                $productsPerLevel[$levelKey] = array_keys($items);
                $totalItems = array_sum($items);
                $numberItems = count($items);
                $pareto[$levelKey] = [
                    'percent_of_value' => $totalItems/$sumProducts,
                    'total_value' => $totalItems,
                    'percent_of_items' => $numberItems/$countProducts,
                    'number_of_items' => $numberItems,
                ];
            }
        }
        return [
            'classified' => $productsPerLevel,
            'pareto' => $pareto,
            'levels' => $levels,
            'totals' => ['sum' => $sumProducts, 'count'=>$countProducts],
        ];
    }
    private static function array_key_last($products) {
        if( function_exists( 'array_key_last' ) ) {
            return array_key_last($products);
        }
        end( $products );
        return key( $products );
    }
}