| 7 | |
| 8 | {{{ |
| 9 | class MultiList |
| 10 | """ |
| 11 | This class provides a generic n-dimensional multi-list containing any other type. |
| 12 | The shape of a MultiList is a list of ints specifying the length of each dimension. |
| 13 | Dimensions are called axes. |
| 14 | The count is the total number of elements in the ML. |
| 15 | |
| 16 | For efficiency reasons, the MultiList class avoids copying its underlying |
| 17 | data as much as possible. A ML can be a read-only view that shares |
| 18 | data with an owner ML. The view can have |
| 19 | a different shape, count, and/or order of axes than its owner. |
| 20 | One way to construct a view is to call ml.slice |
| 21 | |
| 22 | Methods that perform operation in place return "this" which allows for method chaining. |
| 23 | For example, |
| 24 | ml.permute(order).reshape(shape).transpose |
| 25 | If you want to perform operations on a view instead of the owner, call |
| 26 | ml.view.permute(order).reshape(shape).transpose |
| 27 | |
| 28 | MultiList supports indexing, for example |
| 29 | element = ml[i,j,k] |
| 30 | ml[i,j,k] = element |
| 31 | There are plans to support syntactical multidimensional slicing, such as |
| 32 | ml2 = ml[a:b, c:d] |
| 33 | However, at the moment, you should use .slice instead |
| 34 | |
| 35 | Inspiration for MultiList comes from similar libraries such as |
| 36 | Boost.MultiArray -- http://www.boost.org/doc/libs/1_50_0/libs/multi_array/doc/reference.html |
| 37 | Numpy.Array -- http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html |
| 38 | Ruby NArray -- http://narray.rubyforge.org/SPEC.en |
| 39 | MATLAB -- http://www.mathworks.com/products/matlab/ |
| 40 | |
| 41 | For further discussion on MultiLists, see the forum |
| 42 | http://cobra-language.com/forums/viewtopic.php?f=4&t=974 |
| 43 | """ |
| 44 | |
| 45 | shared |
| 46 | |
| 47 | const maxCount = 2_100_000_000 (as int) |
| 48 | |
| 49 | const maxDimRank = 10_000_000 (as int) |
| 50 | |
| 51 | const minDimRank = 1 (as int) |
| 52 | |
| 53 | |
| 54 | var _count as int |
| 55 | |
| 56 | var _data as T[] |
| 57 | |
| 58 | var _dimOrder as IList<of int> |
| 59 | """ |
| 60 | Maps the order of the axes stored internally to |
| 61 | the external permuted order |
| 62 | """ |
| 63 | |
| 64 | var _inverseDimOrder as IList<of int> |
| 65 | |
| 66 | var _isPermuted as bool |
| 67 | |
| 68 | var _isReadOnly as bool |
| 69 | |
| 70 | var _isReferred as bool |
| 71 | """ |
| 72 | If a referrer is GC'ed, _isReferred will still be true |
| 73 | """ |
| 74 | |
| 75 | var _numDims as int |
| 76 | |
| 77 | var _owner as MultiList<of T>? |
| 78 | |
| 79 | var _ranges as IList<of Pair<of int>> |
| 80 | """ |
| 81 | For readonly multilists (aka views), _ranges is the range of elements per axis |
| 82 | included in the view. |
| 83 | """ |
| 84 | |
| 85 | var _shape as IList<of int> |
| 86 | """ |
| 87 | Shape is the size of each axis in the view |
| 88 | """ |
| 89 | |
| 90 | var _strides as IList<of int> |
| 91 | """ |
| 92 | A stride is the number of places in _data separating |
| 93 | two adjacent elements of a particular axes. |
| 94 | Elements are stored in row major order. |
| 95 | for equation, see |
| 96 | http://en.wikipedia.org/wiki/Row-major_order#Generalization_to_higher_dimensions |
| 97 | A slice has the same strides as its owner |
| 98 | """ |
| 99 | |
| 100 | var _viewCount as int? |
| 101 | |
| 102 | cue init(shape as vari int) |
| 103 | |
| 104 | cue init(shape as IList<of int>) |
| 105 | """ |
| 106 | Constructor for a multilists that "owns" its data |
| 107 | """ |
| 108 | |
| 109 | cue init(original as MultiList<of T>, ranges as IList<of Pair<of int>>) |
| 110 | """ |
| 111 | The readonly view constructor returned from a slice |
| 112 | """ |
| 113 | |
| 114 | cue init(shape as IList<of int>, data as T*) |
| 115 | """ |
| 116 | Length of data can be less than the count but not more |
| 117 | """ |
| 118 | |
| 119 | get count as int |
| 120 | |
| 121 | get isPermuted as bool |
| 122 | |
| 123 | get isReadOnly as bool |
| 124 | |
| 125 | get isReferred as bool |
| 126 | |
| 127 | get numDims as int |
| 128 | |
| 129 | get owner as MultiList<of T>? |
| 130 | """ |
| 131 | In ml2 = ml1.slice, ml1 is the owner |
| 132 | and ml2 is a view |
| 133 | """ |
| 134 | |
| 135 | get shape as IList<of int> |
| 136 | |
| 137 | get toList as IList<of T> |
| 138 | |
| 139 | get view as MultiList<of T> |
| 140 | |
| 141 | pro [indices as vari int] as T |
| 142 | |
| 143 | def clone |
| 144 | """ |
| 145 | Returns a shallow copy |
| 146 | """ |
| 147 | |
| 148 | def enumerate |
| 149 | |
| 150 | def equals(obj as Object?) |
| 151 | |
| 152 | def equals(m as MultiList<of T>) |
| 153 | """ |
| 154 | Equal if shapes are the same, and |
| 155 | elements are in the same order. |
| 156 | Ignores .isReadOnly, .isPermuted, .isReferred |
| 157 | """ |
| 158 | |
| 159 | def fill(data as T*) |
| 160 | |
| 161 | def fill(start as int, data as T*) |
| 162 | """ |
| 163 | Throw IndexOutOfRangeException if the length of data + start exceeds .count |
| 164 | """ |
| 165 | |
| 166 | def getHashCode |
| 167 | """ |
| 168 | As a completely mutable object, MultiList does not |
| 169 | support getHashCode |
| 170 | """ |
| 171 | |
| 172 | def permute(order as IList<of int>) |
| 173 | """ |
| 174 | Permutes the axes in place |
| 175 | """ |
| 176 | |
| 177 | def reshape(shape as IList<of int>) |
| 178 | """ |
| 179 | Same as reshape(shape, false, false) |
| 180 | """ |
| 181 | |
| 182 | def reshape(shape as IList<of int>, noCopy as bool, unsafe as bool) |
| 183 | """ |
| 184 | Reshapes the axes in place, |
| 185 | unsafe == true will reshape the MultiList even if isReferred == true |
| 186 | and the count of the shape is different than .count |
| 187 | Will cause a data copy if necessary. |
| 188 | If a view is copied, it's owner will be nil and .isReadOnly will be false |
| 189 | """ |
| 190 | |
| 191 | def slice(ranges as vari Pair<of int>) |
| 192 | """ |
| 193 | Returns a readonly view of the ML. |
| 194 | If ranges are provided for the first few axes, |
| 195 | then the remaining ranges default to the whole axis. |
| 196 | ml.slice() |
| 197 | to-do: implement syntactic slicing as a property. |
| 198 | This method is a placeholder. |
| 199 | """ |
| 200 | |
| 201 | def toString |
| 202 | |
| 203 | def transpose |
| 204 | """ |
| 205 | Reverses the order of axes in place |
| 206 | """ |
| 207 | }}} |
| 208 | |