Code Coverage for /src/SciPhp/NdArray/VisitorTrait.php

 
Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
VisitorTrait
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
4 / 4
12
100.00% covered (success)
100.00%
1 / 1
 walk
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 walk_recursive
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 iterate
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 axis
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
6
1 <?php
2
3 declare(strict_types=1);
4
5 namespace SciPhp\NdArray;
6
7 use RecursiveIteratorIterator;
8 use SciPhp\NdArray;
9 use SciPhp\NumPhp as np;
10 use Webmozart\Assert\Assert;
11
12 /**
13  * Visitor methods
14  */
15 trait VisitorTrait
16 {
17     /**
18      * Walk on first dimension
19      */
20     final public function walk(callable $func): NdArray
21     {
22         array_walk($this->data, $func);
23
24         return $this;
25     }
26
27     /**
28      * Walk on last dimension
29      */
30     final public function walk_recursive(callable $func): NdArray
31     {
32         array_walk_recursive($this->data, $func);
33
34         return $this;
35     }
36
37     /**
38      * Iterate on next value
39      *
40      * @return int|float
41      */
42     final public function iterate(RecursiveIteratorIterator &$iterator)
43     {
44         while ($iterator->valid()) {
45             if (! is_array($iterator->current())) {
46                 $value = $iterator->current();
47
48                 $key = $iterator->key();
49
50                 $iterator->next();
51                 // At first iteration on 1 dim array,
52                 // key is not incremented
53                 if ($key === $iterator->key()) {
54                     $iterator->next();
55                 }
56
57                 return $value;
58             }
59
60             $iterator->next();
61         }
62
63         $iterator->rewind();
64
65         return $this->iterate($iterator);
66     }
67
68     /**
69      * Execute axis operations and return an aggregate
70      *
71      * @param int|float $number
72      * @return int|NdArray
73      */
74     final public function axis(callable $func, $number = null, bool $keepdims = false)
75     {
76         if (! \is_null($number)) {
77             Assert::integer(
78                 $number,
79                 'Axis number must be an integer. Given: %s'
80             );
81
82             Assert::greaterThanEq(
83                 $number,
84                 0,
85                 'Axis number must be greater than 0. Given: %s'
86             );
87
88             Assert::lessThan(
89                 $number,
90                 $this->ndim,
91                 'Axis number must be lower than '
92                 . ($this->ndim - 1)
93                 . 'Given: %s'
94             );
95
96             Assert::lessThanEq(
97                 $this->ndim,
98                 2,
99                 'Axis implementation does not support dimension > 2. Given: %s'
100             );
101         }
102
103         $fn = function (&$value, $key) use ($func, $number): void {
104             $index = $number === 0
105                 ? ": , {$key}"
106                 : "{$key}, :";
107
108             $value = $func($this->offsetGet($index)->data);
109         };
110
111         // keepdims handling
112         $targetShape = $this->shape;
113         if ($keepdims) {
114             $targetShape[$number] = 1;
115         } else {
116             unset($targetShape[$number]);
117         }
118
119         // No axis number
120         if (\is_null($number)) {
121             if ($keepdims) {
122                 $targetShape = array_fill(0, $this->ndim, 1);
123                 return np::full($targetShape, $func($this->data));
124             }
125
126             return $func($this->data);
127         }
128
129         return np::zeros($this->shape[$this->ndim - 1 - $number])
130             ->walk($fn)
131             ->reshape(...$targetShape);
132     }
133 }