shape.hpp 12 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
Paul's avatar
Paul committed
24
25
#ifndef MIGRAPHX_GUARD_MIGRAPHLIB_SHAPE_HPP
#define MIGRAPHX_GUARD_MIGRAPHLIB_SHAPE_HPP
Paul's avatar
Paul committed
26
27
28

#include <vector>
#include <cassert>
Paul's avatar
Paul committed
29
#include <ostream>
Paul's avatar
Paul committed
30
#include <numeric>
Paul's avatar
Paul committed
31
#include <memory>
32
#include <set>
Paul's avatar
Paul committed
33

34
#include <migraphx/functional.hpp>
Paul's avatar
Paul committed
35
36
#include <migraphx/errors.hpp>
#include <migraphx/half.hpp>
37
#include <migraphx/serialize.hpp>
Paul's avatar
Paul committed
38
#include <migraphx/config.hpp>
Paul's avatar
Paul committed
39

Paul's avatar
Paul committed
40
namespace migraphx {
Paul's avatar
Paul committed
41
inline namespace MIGRAPHX_INLINE_NS {
Paul's avatar
Paul committed
42

43
struct value;
Paul's avatar
Paul committed
44
45
struct shape_impl;

Paul's avatar
Paul committed
46
47
struct shape
{
Paul's avatar
Paul committed
48
49

// Add new types here
Paul's avatar
Paul committed
50
// clang-format off
Paul's avatar
Paul committed
51
#define MIGRAPHX_SHAPE_VISIT_TYPES(m) \
52
    m(bool_type, bool) \
Paul's avatar
Paul committed
53
    m(half_type, half) \
Paul's avatar
Paul committed
54
    m(float_type, float) \
Paul's avatar
Paul committed
55
56
57
58
59
60
61
62
    m(double_type, double) \
    m(uint8_type, uint8_t) \
    m(int8_type, int8_t) \
    m(uint16_type, uint16_t) \
    m(int16_type, int16_t) \
    m(int32_type, int32_t) \
    m(int64_type, int64_t) \
    m(uint32_type, uint32_t) \
Paul's avatar
Paul committed
63
    m(uint64_type, uint64_t)
bpickrel's avatar
bpickrel committed
64
    // clang-format on
Paul's avatar
Paul committed
65

Paul's avatar
Paul committed
66
#define MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES(x, t) x,
Paul's avatar
Paul committed
67
68
    enum type_t
    {
Paul Fultz II's avatar
Paul Fultz II committed
69
        MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES) tuple_type
Paul's avatar
Paul committed
70
    };
Paul's avatar
Paul committed
71
#undef MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES
Paul's avatar
Paul committed
72

Paul's avatar
Paul committed
73
    template <class T, class = void>
Paul's avatar
Paul committed
74
    struct get_type;
Paul's avatar
Paul committed
75
#define MIGRAPHX_SHAPE_GENERATE_GET_TYPE(x, t)                \
Paul's avatar
Paul committed
76
    template <class T>                                        \
Paul's avatar
Paul committed
77
    struct get_type<t, T> : std::integral_constant<type_t, x> \
Paul's avatar
Paul committed
78
79
    {                                                         \
    };
Paul's avatar
Paul committed
80
81
    MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_GET_TYPE)
#undef MIGRAPHX_SHAPE_GENERATE_GET_TYPE
Paul's avatar
Paul committed
82

wsttiger's avatar
wsttiger committed
83
84
85
86
87
    template <class T>
    struct get_type<const T> : get_type<T>
    {
    };

Charlie Lin's avatar
Charlie Lin committed
88
89
90
91
    struct dynamic_dimension
    {
        std::size_t min = 0;
        std::size_t max = 0;
92
        std::set<std::size_t> optimals{};
Charlie Lin's avatar
Charlie Lin committed
93
94

        template <class Self, class F>
95
96
        static auto reflect(Self& self, F f)
        {
97
            return pack(f(self.min, "min"), f(self.max, "max"), f(self.optimals, "optimals"));
98
        }
Charlie Lin's avatar
Charlie Lin committed
99
100
101
102
103
104
105

        bool is_fixed() const;
        bool has_optimal() const;

        friend bool operator==(const dynamic_dimension& x, const dynamic_dimension& y);
        friend bool operator!=(const dynamic_dimension& x, const dynamic_dimension& y);
        friend std::ostream& operator<<(std::ostream& os, const dynamic_dimension& x);
106
107
108
109
110
111

        // compare to fixed std::size_t dimension
        friend bool operator==(const dynamic_dimension& x, const std::size_t& y);
        friend bool operator==(const std::size_t& x, const dynamic_dimension& y);
        friend bool operator!=(const dynamic_dimension& x, const std::size_t& y);
        friend bool operator!=(const std::size_t& x, const dynamic_dimension& y);
Charlie Lin's avatar
Charlie Lin committed
112
113
114
115
116
117
118

        // add and subtract fixed std::size_t dimension
        dynamic_dimension& operator+=(const std::size_t& x);
        dynamic_dimension& operator-=(const std::size_t& x);
        friend dynamic_dimension operator+(const dynamic_dimension& x, const std::size_t& y);
        friend dynamic_dimension operator+(const std::size_t& x, const dynamic_dimension& y);
        friend dynamic_dimension operator-(const dynamic_dimension& x, const std::size_t& y);
Charlie Lin's avatar
Charlie Lin committed
119
120
    };

121
122
    static const std::vector<type_t>& types();

123
124
125
    static std::string name(type_t t);
    static std::string cpp_type(type_t t);

Paul's avatar
Paul committed
126
127
128
129
    shape();
    shape(type_t t);
    shape(type_t t, std::vector<std::size_t> l);
    shape(type_t t, std::vector<std::size_t> l, std::vector<std::size_t> s);
Paul's avatar
Paul committed
130

Charlie Lin's avatar
Charlie Lin committed
131
132
133
134
135
136
    // Force all calls of the format `shape( type_t, { size_t compatibles } )` to map to
    // shape(type_t, std::vector<std::size_t> l)
    shape(type_t t, std::initializer_list<std::size_t> d);

    shape(type_t t, std::vector<dynamic_dimension> dims);

137
138
    // Construct a dynamic shape from vectors of mins, maxes, and optimals.
    // optimals_list is a vector of optimals that corresponds to each min and max.
139
140
141
    shape(type_t t,
          std::vector<std::size_t> mins,
          std::vector<std::size_t> maxes,
142
          std::vector<std::set<std::size_t>> optimals_list);
143

Paul's avatar
Paul committed
144
145
146
147
148
149
    template <class Range>
    shape(type_t t, const Range& l) : shape(t, std::vector<std::size_t>(l.begin(), l.end()))
    {
    }

    template <class Range1, class Range2>
Paul's avatar
Paul committed
150
    shape(type_t t, const Range1& l, const Range2& s)
Paul's avatar
Paul committed
151
152
153
154
155
        : shape(t,
                std::vector<std::size_t>(l.begin(), l.end()),
                std::vector<std::size_t>(s.begin(), s.end()))
    {
    }
Paul's avatar
Paul committed
156

Paul Fultz II's avatar
Paul Fultz II committed
157
158
    shape(const std::vector<shape>& subs);

159
160
    static shape
    from_permutation(type_t t, const std::vector<std::size_t>& l, const std::vector<int64_t>& perm);
Paul's avatar
Paul committed
161
    type_t type() const;
Paul's avatar
Paul committed
162
163
    const std::vector<std::size_t>& lens() const;
    const std::vector<std::size_t>& strides() const;
Charlie Lin's avatar
Charlie Lin committed
164

165
166
167
168
169
170
    /*!
     * The number of dimensions in the shape.
     * Same as the number of indices required to get a data value.
     */
    std::size_t ndim() const;

Charlie Lin's avatar
Charlie Lin committed
171
172
173
    /*!
     * Return the number of elements in the tensor.
     */
Paul's avatar
Paul committed
174
    std::size_t elements() const;
Charlie Lin's avatar
Charlie Lin committed
175
176
177
178
179

    /*!
     * Return the number of total bytes used for storage of the tensor data; includes subshapes.
     * For dynamic shape, returns the maximum number of bytes presuming a packed shape.
     */
Paul's avatar
Paul committed
180
    std::size_t bytes() const;
Charlie Lin's avatar
Charlie Lin committed
181
182
183
184
185

    /*!
     * Return the size of the type of the main shape.
     * Returns 0 if there are subshapes.
     */
Scott Thornton's avatar
Scott Thornton committed
186
    std::size_t type_size() const;
Paul's avatar
Paul committed
187

Charlie Lin's avatar
Charlie Lin committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
    const std::vector<dynamic_dimension>& dyn_dims() const;

    /*!
     * Minimum lengths for dynamic shape.
     * lens() for fixed shape.
     */
    std::vector<std::size_t> min_lens() const;

    /*!
     * Maximum lengths for dynamic shape.
     * lens() for fixed shape.
     */
    std::vector<std::size_t> max_lens() const;

    /*!
     * Optimum lengths for dynamic shape.
204
     * Empty for fixed shape.
Charlie Lin's avatar
Charlie Lin committed
205
     */
206
    std::vector<std::set<std::size_t>> opt_lens() const;
Charlie Lin's avatar
Charlie Lin committed
207

Paul's avatar
Paul committed
208
    /// Map multiple indices to space index
Paul's avatar
Paul committed
209
    std::size_t index(std::initializer_list<std::size_t> l) const;
Paul's avatar
Paul committed
210
    /// Map multiple indices to space index
Paul's avatar
Paul committed
211
    std::size_t index(const std::vector<std::size_t>& l) const;
Paul's avatar
Paul committed
212

Paul's avatar
Paul committed
213
    /// Map multiple indices from a range of iterator to a space index
Paul's avatar
Paul committed
214
    template <class Iterator>
Paul's avatar
Paul committed
215
216
217
218
    std::size_t index(Iterator start, Iterator last) const
    {
        assert(std::distance(start, last) <= this->lens().size());
        assert(this->lens().size() == this->strides().size());
Paul Fultz II's avatar
Paul Fultz II committed
219
        return std::inner_product(start, last, this->strides().begin(), std::size_t{0}); // NOLINT
Paul's avatar
Paul committed
220
    }
Paul's avatar
Paul committed
221

Paul's avatar
Paul committed
222
    /// Map element index to space index
Paul's avatar
Paul committed
223
224
    std::size_t index(std::size_t i) const;

225
    std::vector<std::size_t> multi(std::size_t i) const;
226
    void multi_copy(std::size_t i, std::size_t* start, const std::size_t* end) const;
227

Charlie Lin's avatar
Charlie Lin committed
228
229
    /// Returns true if the shape is packed (number of elements and buffer size the same) with no
    /// padding
Paul's avatar
Paul committed
230
    bool packed() const;
Charlie Lin's avatar
Charlie Lin committed
231

Paul's avatar
Paul committed
232
233
    /// Returns true is the shape has been transposed. That is the strides are not in descending
    /// order
Paul's avatar
Paul committed
234
    bool transposed() const;
Charlie Lin's avatar
Charlie Lin committed
235

Paul's avatar
Paul committed
236
    /// Returns true if the shape is broadcasting a dimension. That is, one of the strides are zero
Paul's avatar
Paul committed
237
    bool broadcasted() const;
Charlie Lin's avatar
Charlie Lin committed
238

Paul's avatar
Paul committed
239
240
    /// Returns true if the shape is in its standard format. That is, the shape is both packed and
    /// not transposed.
Paul's avatar
Paul committed
241
    bool standard() const;
Charlie Lin's avatar
Charlie Lin committed
242

Khalique's avatar
Khalique committed
243
244
    /// Returns true if all strides are equal to 0 (scalar tensor)
    bool scalar() const;
Paul's avatar
Paul committed
245

Charlie Lin's avatar
Charlie Lin committed
246
247
248
    /// Return true if the shape is dynamic
    bool dynamic() const;

Charlie Lin's avatar
Charlie Lin committed
249
250
251
    /// Return true if this shape or any of the sub_shapes are dynamic
    bool any_of_dynamic() const;

252
253
    shape normalize_standard() const;

254
255
256
    shape with_lens(type_t t, const std::vector<std::size_t>& l) const;
    shape with_lens(const std::vector<std::size_t>& l) const;

257
258
    shape with_type(type_t t) const;

259
    // convert the shape to an equivalent dynamic shape with empty optimals
260
261
    shape to_dynamic() const;

Paul's avatar
Paul committed
262
263
    friend bool operator==(const shape& x, const shape& y);
    friend bool operator!=(const shape& x, const shape& y);
Paul's avatar
Paul committed
264
    friend std::ostream& operator<<(std::ostream& os, const shape& x);
Paul's avatar
Paul committed
265

Paul's avatar
Paul committed
266
    template <class T>
Paul's avatar
Paul committed
267
268
    struct as
    {
269
        using type = std::conditional_t<std::is_same<T, bool>{}, int8_t, T>;
Paul's avatar
Paul committed
270

271
272
273
274
        type max() const { return std::numeric_limits<type>::max(); }

        type min() const { return std::numeric_limits<type>::lowest(); }

Paul's avatar
Paul committed
275
        template <class U>
276
        type operator()(U u) const
Paul's avatar
Paul committed
277
        {
278
            return type(u);
Paul's avatar
Paul committed
279
280
        }

Paul's avatar
Paul committed
281
        template <class U>
282
        type* operator()(U* u) const
Paul's avatar
Paul committed
283
        {
284
            return static_cast<type*>(u);
Paul's avatar
Paul committed
285
286
        }

Paul's avatar
Paul committed
287
        template <class U>
288
        const type* operator()(const U* u) const
Paul's avatar
Paul committed
289
        {
290
            return static_cast<type*>(u);
Paul's avatar
Paul committed
291
292
        }

293
        type operator()() const { return {}; }
Paul's avatar
Paul committed
294

295
        std::size_t size(std::size_t n = 1) const { return sizeof(type) * n; }
Paul's avatar
Paul committed
296

Paul Fultz II's avatar
Paul Fultz II committed
297
298
299
300
        auto is_integral() const { return std::is_integral<type>{}; }
        auto is_signed() const { return std::is_signed<type>{}; }
        auto is_unsigned() const { return std::is_unsigned<type>{}; }

Paul's avatar
Paul committed
301
        template <class U>
302
        type* from(U* buffer, std::size_t n = 0) const
Paul's avatar
Paul committed
303
        {
304
            return reinterpret_cast<type*>(buffer) + n;
Paul's avatar
Paul committed
305
        }
Paul's avatar
Paul committed
306

Paul's avatar
Paul committed
307
        template <class U>
308
        const type* from(const U* buffer, std::size_t n = 0) const
Paul's avatar
Paul committed
309
        {
310
            return reinterpret_cast<const type*>(buffer) + n;
Paul's avatar
Paul committed
311
        }
Paul's avatar
Paul committed
312

313
        type_t type_enum() const { return get_type<type>{}; }
Paul's avatar
Paul committed
314
315
    };

Paul Fultz II's avatar
Paul Fultz II committed
316
317
    template <class Visitor, class TupleVisitor>
    static void visit(type_t t, Visitor v, TupleVisitor tv)
Paul's avatar
Paul committed
318
    {
319
        switch(t)
Paul's avatar
Paul committed
320
        {
bpickrel's avatar
bpickrel committed
321
        case tuple_type: {
Paul Fultz II's avatar
Paul Fultz II committed
322
323
324
            tv();
            return;
        }
Paul's avatar
Paul committed
325
#define MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE(x, t) \
Paul's avatar
Paul committed
326
    case x: v(as<t>()); return;
Paul's avatar
Paul committed
327
328
            MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE)
#undef MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE
Paul's avatar
Paul committed
329
        }
Paul's avatar
Paul committed
330
        MIGRAPHX_THROW("Unknown type");
Paul's avatar
Paul committed
331
    }
Paul's avatar
Paul committed
332

333
    template <class Visitor>
Paul Fultz II's avatar
Paul Fultz II committed
334
    static void visit(type_t t, Visitor v)
335
    {
Paul Fultz II's avatar
Paul Fultz II committed
336
337
338
339
340
341
342
        return visit(t, v, [] { MIGRAPHX_THROW("Tuple cannot be visited."); });
    }

    template <class... Visitors>
    void visit_type(Visitors... vs) const
    {
        visit(this->type(), vs...);
343
344
    }

Paul's avatar
Paul committed
345
346
347
    template <class Visitor>
    static void visit_types(Visitor v)
    {
Paul's avatar
Paul committed
348
#define MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL(x, t) v(as<t>());
Paul's avatar
Paul committed
349
350
351
352
        MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL)
#undef MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL
    }

353
    std::string type_string() const;
354
    static type_t parse_type(const std::string& s);
355

Paul Fultz II's avatar
Paul Fultz II committed
356
357
    const std::vector<shape>& sub_shapes() const;

Charlie Lin's avatar
Charlie Lin committed
358
359
360
361
362
    /*!
     * Returns the number of elements in the data buffer.
     * For a dynamic shape, returns the maximum number of elements of the data buffer and assumes it
     * is packed.
     */
363
364
    std::size_t element_space() const;

Paul's avatar
Paul committed
365
    private:
366
    shape(std::shared_ptr<shape_impl> pimpl);
Paul's avatar
Paul committed
367
    std::shared_ptr<const shape_impl> impl;
Paul's avatar
Paul committed
368
369
};

370
371
372
void migraphx_to_value(value& v, const shape& s);
void migraphx_from_value(const value& v, shape& s);

Paul's avatar
Paul committed
373
} // namespace MIGRAPHX_INLINE_NS
Paul's avatar
Paul committed
374
} // namespace migraphx
Paul's avatar
Paul committed
375
376

#endif