dimension.hpp
1 // Copyright (C) 2018-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 #pragma once
6 
7 #include <limits>
8 #include <stddef.h>
9 #include <stdexcept>
10 
11 #include "ngraph/deprecated.hpp"
12 #include "ngraph/interval.hpp"
13 #include "ngraph/ngraph_visibility.hpp"
14 
15 namespace ngraph
16 {
17  /// \brief Class representing a dimension, which may be dynamic (undetermined until runtime),
18  /// in a shape or shape-like object.
19  ///
20  /// Static dimensions may be implicitly converted from value_type. A dynamic dimension is
21  /// constructed with Dimension() or Dimension::dynamic().
22  class NGRAPH_API Dimension
23  {
24  public:
25  using value_type = int64_t;
26 
27  /// \brief Construct a static dimension.
28  /// \param dimension Value of the dimension.
29  Dimension(value_type dimension);
30 
31  /// \brief Construct a dynamic dimension with bounded range
32  /// \param min_dimension The lower inclusive limit for the dimension
33  /// \param mas_dimension The upper inclusive limit for the dimension
34  Dimension(value_type min_dimension, value_type max_dimension);
35 
36  /// \brief Construct a dynamic dimension with range [0, ...]
37  Dimension() = default;
38 
39  bool operator==(const Dimension& dimension) const
40  {
41  return m_dimension == dimension.m_dimension;
42  }
43  bool operator!=(const Dimension& dimension) const
44  {
45  return m_dimension != dimension.m_dimension;
46  }
47  /// \brief Check whether this dimension is static.
48  /// \return `true` if the dimension is static, else `false`.
49  bool is_static() const { return m_dimension.size() == 1; }
50  /// \brief Check whether this dimension is dynamic.
51  /// \return `false` if the dimension is static, else `true`.
52  bool is_dynamic() const { return m_dimension.size() != 1; }
53  /// \brief Convert this dimension to `value_type`. This dimension must be static and
54  /// non-negative.
55  /// \throws std::invalid_argument If this dimension is dynamic or negative.
56  value_type get_length() const;
57 
58  value_type get_min_length() const;
59  value_type get_max_length() const;
60 
61  /// \brief Return the interval of valid lengths
62  const Interval& get_interval() const { return m_dimension; }
63  Interval& get_interval() { return m_dimension; }
64  /// \brief Check whether this dimension represents the same scheme as the argument (both
65  /// dynamic, or equal).
66  /// \param dim The other dimension to compare this dimension to.
67  /// \return `true` if this dimension and `dim` are both dynamic, or if they are both
68  /// static and equal; otherwise, `false`.
69  bool same_scheme(const Dimension& dim) const;
70  /// \brief Try to merge two Dimension objects together.
71  /// \param[out] dst Reference to write the merged Dimension into.
72  /// \param d1 First dimension to merge.
73  /// \param d2 Second dimension to merge.
74  /// \return `true` if merging succeeds, else `false`.
75  ///
76  /// \li If `d1` is dynamic, writes `d2` to `dst` and returns `true`.
77  /// \li If `d2` is dynamic, writes `d1` to `dst` and returns `true`.
78  /// \li If `d1` and `d2` are static and equal, writes `d1` to `dst` and returns `true`.
79  /// \li If `d1` and `d2` are both static and unequal, leaves `dst` unchanged and
80  /// returns `false`.
81  static bool merge(Dimension& dst, const Dimension d1, const Dimension d2);
82 
83  /// \brief Try to merge two Dimension objects together with implicit broadcasting
84  /// of unit-sized dimension to non unit-sized dimension
85  static bool broadcast_merge(Dimension& dst, const Dimension d1, const Dimension d2);
86 
87  /// \brief Check whether this dimension is capable of being merged with the argument
88  /// dimension.
89  /// \param d The dimension to compare this dimension with.
90  /// \return `true` if this dimension is compatible with `d`, else `false`.
91  ///
92  /// Two dimensions are considered compatible if it is possible to merge them. (See
93  /// Dimension::merge.)
94  bool compatible(const Dimension& d) const;
95 
96  /// \brief Check whether this dimension is a relaxation of the argument.
97  /// \param d The dimension to compare this dimension with.
98  /// \return `true` if this dimension relaxes `d`, else `false`.
99  ///
100  /// A dimension `d1` _relaxes_ (or _is a relaxation of_) `d2` if `d1` and `d2` are static
101  /// and equal, or `d1` is dynamic.
102  ///
103  /// `d1.relaxes(d2)` is equivalent to `d2.refines(d1)`.
104  bool relaxes(const Dimension& d) const;
105 
106  /// \brief Check whether this dimension is a refinement of the argument.
107  /// \param d The dimension to compare this dimension with.
108  /// \return `true` if this dimension relaxes `d`, else `false`.
109  ///
110  /// A dimension `d2` _refines_ (or _is a refinement of_) `d1` if `d1` and `d2` are static
111  /// and equal, or `d2` is dynamic.
112  ///
113  /// `d1.refines(d2)` is equivalent to `d2.relaxes(d1)`.
114  bool refines(const Dimension& d) const;
115 
116  /// \brief Create a dynamic dimension.
117  /// \return A dynamic dimension.
118  static Dimension dynamic() { return Dimension(); }
119  /// \brief Addition operator for Dimension.
120  /// \param dim Right operand for addition.
121  /// \return Smallest interval dimension enclosing inputs
122  Dimension operator+(const Dimension& dim) const;
123 
124  /// \brief Subtraction operator for Dimension.
125  /// \param dim Right operand for subtraction.
126  /// \return Smallest interval dimension enclosing inputs
127  Dimension operator-(const Dimension& dim) const;
128 
129  /// \brief Multiplication operator for Dimension.
130  /// \param dim Right operand for multiplicaiton.
131  /// \return Smallest interval containing all "produces" which are 0 if either of `this` or
132  /// `dim` has length `0`, else unbounded if either is unbounded, else product of lengths.
133  Dimension operator*(const Dimension& dim) const;
134 
135  /// \brief Add-into operator for Dimension.
136  /// \param dim Right operand for addition.
137  /// \return A reference to `*this`, after updating `*this` to the value `*this + dim`.
138  Dimension& operator+=(const Dimension& dim) { return (*this = *this + dim); }
139  /// \brief Multiply-into operator for Dimension.
140  /// \param dim Right operand for multiplication.
141  /// \return A reference to `*this`, after updating `*this` to the value `*this * dim`.
142  Dimension& operator*=(const Dimension& dim) { return (*this = *this * dim); }
143  /// \brief Intersection of dimensions
144  Dimension operator&(const Dimension& dim) const;
145  /// \brief Intersection of dimensions
147 
148  private:
149  Dimension(const Interval& interval)
150  : m_dimension(interval)
151  {
152  }
153 
154  // The actual numerical value of the dimension.
155  Interval m_dimension{};
156  };
157 
158  /// \brief Insert a human-readable representation of a dimension into an output stream.
159  /// \param str The output stream targeted for insertion.
160  /// \param dimension The dimension to be inserted into `str`.
161  /// \return A reference to `str` after insertion.
162  ///
163  /// Inserts the string `?` if `dimension` is dynamic; else inserts `dimension.get_length()`.
164  NGRAPH_API
165  std::ostream& operator<<(std::ostream& str, const Dimension& dimension);
166 } // namespace ngraph
Class representing a dimension, which may be dynamic (undetermined until runtime),...
Definition: dimension.hpp:23
Dimension & operator*=(const Dimension &dim)
Multiply-into operator for Dimension.
Definition: dimension.hpp:142
Dimension & operator+=(const Dimension &dim)
Add-into operator for Dimension.
Definition: dimension.hpp:138
Dimension(value_type dimension)
Construct a static dimension.
const Interval & get_interval() const
Return the interval of valid lengths.
Definition: dimension.hpp:62
static Dimension dynamic()
Create a dynamic dimension.
Definition: dimension.hpp:118
Dimension operator*(const Dimension &dim) const
Multiplication operator for Dimension.
static bool merge(Dimension &dst, const Dimension d1, const Dimension d2)
Try to merge two Dimension objects together.
Dimension()=default
Construct a dynamic dimension with range [0, ...].
Dimension operator-(const Dimension &dim) const
Subtraction operator for Dimension.
bool refines(const Dimension &d) const
Check whether this dimension is a refinement of the argument.
static bool broadcast_merge(Dimension &dst, const Dimension d1, const Dimension d2)
Try to merge two Dimension objects together with implicit broadcasting of unit-sized dimension to non...
Dimension & operator&=(const Dimension &dim)
Intersection of dimensions.
bool same_scheme(const Dimension &dim) const
Check whether this dimension represents the same scheme as the argument (both dynamic,...
bool is_dynamic() const
Check whether this dimension is dynamic.
Definition: dimension.hpp:52
Dimension operator&(const Dimension &dim) const
Intersection of dimensions.
Dimension operator+(const Dimension &dim) const
Addition operator for Dimension.
value_type get_length() const
Convert this dimension to value_type. This dimension must be static and non-negative.
bool is_static() const
Check whether this dimension is static.
Definition: dimension.hpp:49
Dimension(value_type min_dimension, value_type max_dimension)
Construct a dynamic dimension with bounded range.
bool compatible(const Dimension &d) const
Check whether this dimension is capable of being merged with the argument dimension.
bool relaxes(const Dimension &d) const
Check whether this dimension is a relaxation of the argument.
Interval arithmetic.
Definition: interval.hpp:25
The Intel nGraph C++ API.
Definition: attribute_adapter.hpp:16