constant.hpp
1 // Copyright (C) 2018-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 
5 #pragma once
6 
7 #include <cmath>
8 #include <cstring>
9 
10 #include "ngraph/coordinate_diff.hpp"
11 #include "ngraph/node.hpp"
12 #include "ngraph/runtime/aligned_buffer.hpp"
13 #include "ngraph/runtime/host_tensor.hpp"
14 #include "ngraph/runtime/shared_buffer.hpp"
15 #include "ngraph/type/element_type.hpp"
16 #include "ngraph/type/element_type_traits.hpp"
17 #include "ngraph/util.hpp"
18 
19 namespace ngraph
20 {
21  namespace op
22  {
23  namespace v0
24  {
25  /// \brief Class for constants.
26  class NGRAPH_API Constant : public Op
27  {
28  public:
29  static constexpr NodeTypeInfo type_info{"Constant", 0};
30  const NodeTypeInfo& get_type_info() const override { return type_info; }
31  Constant() = default;
32 
33  /// \brief Initialize a constant from tensor
34  /// \param tensor The tensor with data
35  Constant(const std::shared_ptr<runtime::Tensor>& tensor);
36 
37  /// \brief Constructs a tensor constant.
38  ///
39  /// \param type The element type of the tensor constant.
40  /// \param shape The shape of the tensor constant.
41  /// \param values A vector of literals for initializing the tensor constant. The
42  /// size of values must match the size of the shape.
43  template <typename T>
44  Constant(const element::Type& type,
45  const Shape& shape,
46  const std::vector<T>& values)
47  : Constant(type, shape)
48  {
49  NODE_VALIDATION_CHECK(
50  this,
51  values.size() == 1 || values.size() == shape_size(m_shape),
52  "Did not get the expected number of literals for a constant of shape ",
53  m_shape,
54  " (got ",
55  values.size(),
56  ", expected ",
57  (shape_size(m_shape) == 1 ? "" : "1 or "),
58  shape_size(m_shape),
59  ").");
60 
61  if (values.size() == 1)
62  {
63  fill_data(type, values.front());
64  }
65  else
66  {
67  write_values(values);
68  }
69  m_all_elements_bitwise_identical = are_all_data_elements_bitwise_identical();
70  }
71 
72  /// \brief Create uninitialized constant
73  Constant(const element::Type& type, const Shape& shape);
74  /// \brief Constructs a uniform tensor constant.
75  ///
76  /// \param type The element type of the tensor constant.
77  /// \param shape The shape of the tensor constant.
78  /// \param value A scalar for initializing the uniform tensor constant. The
79  /// value is broadcast to the specified shape.
80  template <class T,
81  class = typename std::enable_if<std::is_fundamental<T>::value>::type>
82  Constant(const element::Type& type, const Shape& shape, T value)
83  : Constant(type, shape)
84  {
85  fill_data(type, value);
86  m_all_elements_bitwise_identical = true;
87  }
88 
89  template <typename T>
90  void fill_data(const element::Type& type, T value)
91  {
92  using Type_t = element::Type_t;
93 #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8)
94 #pragma GCC diagnostic push
95 #pragma GCC diagnostic error "-Wswitch"
96 #pragma GCC diagnostic error "-Wswitch-enum"
97 #endif
98  switch (type)
99  {
100  case Type_t::boolean: fill_data<Type_t::boolean>(value); break;
101  case Type_t::bf16: fill_data<Type_t::bf16>(value); break;
102  case Type_t::f16: fill_data<Type_t::f16>(value); break;
103  case Type_t::f32: fill_data<Type_t::f32>(value); break;
104  case Type_t::f64: fill_data<Type_t::f64>(value); break;
105  case Type_t::i4: fill_data<Type_t::i4>(value); break;
106  case Type_t::i8: fill_data<Type_t::i8>(value); break;
107  case Type_t::i16: fill_data<Type_t::i16>(value); break;
108  case Type_t::i32: fill_data<Type_t::i32>(value); break;
109  case Type_t::i64: fill_data<Type_t::i64>(value); break;
110  case Type_t::u1: fill_data<Type_t::u1>(value); break;
111  case Type_t::u4: fill_data<Type_t::u4>(value); break;
112  case Type_t::u8: fill_data<Type_t::u8>(value); break;
113  case Type_t::u16: fill_data<Type_t::u16>(value); break;
114  case Type_t::u32: fill_data<Type_t::u32>(value); break;
115  case Type_t::u64: fill_data<Type_t::u64>(value); break;
116  case Type_t::undefined:
117  case Type_t::dynamic: throw std::runtime_error("unsupported type");
118  }
119 #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8)
120 #pragma GCC diagnostic pop
121 #endif
122  }
123 
124  /// \brief Constructs a tensor constant
125  /// This constructor is mainly to support deserialization of constants.
126  ///
127  /// \param type The element type of the tensor constant.
128  /// \param shape The shape of the tensor constant.
129  /// \param values A list of string values to use as the constant data.
130  Constant(const element::Type& type,
131  const Shape& shape,
132  const std::vector<std::string>& values);
133 
134  /// \brief Constructs a tensor constant with the supplied data
135  ///
136  /// \param type The element type of the tensor constant.
137  /// \param shape The shape of the tensor constant.
138  /// \param data A void* to constant data.
139  Constant(const element::Type& type, const Shape& shape, const void* data);
140 
141  /// \brief Constructs a tensor constant with the supplied data
142  ///
143  /// \param type The element type of the tensor constant.
144  /// \param shape The shape of the tensor constant.
145  /// \param data A pointer to pre-allocated shared data.
146  template <typename T>
147  Constant(const element::Type& type,
148  const Shape& shape,
149  std::shared_ptr<runtime::SharedBuffer<T>> data)
150  : m_element_type(type)
151  , m_shape(shape)
152  {
153  m_data = data;
154  constructor_validate_and_infer_types();
155  }
156 
157  Constant(const Constant& other);
158  Constant& operator=(const Constant&) = delete;
159 
160  virtual ~Constant() override;
161 
162  void validate_and_infer_types() override
163  {
164  infer_element_type();
165  set_output_type(0, m_element_type, m_shape);
166  }
167 
168  bool visit_attributes(AttributeVisitor& visitor) override;
169 
170  bool evaluate(const HostTensorVector& outputs,
171  const HostTensorVector& inputs) const override;
172  bool has_evaluate() const override;
173  bool evaluate_lower(const HostTensorVector& outputs) const override;
174  bool evaluate_upper(const HostTensorVector& outputs) const override;
175 
176  // Don't constant fold a constant; it would make a copy
177  bool constant_fold(OutputVector& outputs, const OutputVector& inputs) override
178  {
179  return false;
180  }
181 
182  /// \brief Returns the value of the constant node as a Shape object
183  /// Can only be used on element::i64 nodes and interprets
184  /// negative values as zeros.
186  /// \brief Returns the value of the constant node as a Strides
187  /// object
188  /// Can only be used on element::i64 nodes and interprets
189  /// negative values as zeros.
191  /// \brief Returns the value of the constant node as a Coordinate
192  /// object
193  /// Can only be used on element::i64 nodes and interprets
194  /// negative values as zeros.
196  /// \brief Returns the value of the constant node as a
197  /// CoordinateDiff object
198  /// Can only be used on element::i64 nodes.
200  /// \brief Returns the value of the constant node as an AxisVector
201  /// object
202  /// Can only be used on element::i64 nodes and interprets
203  /// negative values as zeros.
205  /// \brief Returns the value of the constant node as an AxisSet
206  /// object
207  /// Can only be used on element::i64 nodes and interprets
208  /// negative values as zeros.
209  /// Repeated values are allowed.
211 
212  /// \brief Update Constant shape. New shape size must equal to the data elements
213  /// count
214  ///
215  /// \param shape The shape of the tensor constant.
216  void set_data_shape(const Shape& shape);
217 
218  /// \brief Wrapper around constructing a shared_ptr of a Constant
219  ///
220  /// \param type The element type of the tensor constant.
221  /// \param shape The shape of the tensor constant.
222  /// \param values A vector of values to use as the constant data.
223  template <typename T>
224  static std::shared_ptr<Constant> create(const element::Type& type,
225  const Shape& shape,
226  const std::vector<T>& values)
227  {
228  return std::make_shared<Constant>(type, shape, values);
229  }
230 
231  /// \brief Wrapper around constructing a shared_ptr of a Constant
232  ///
233  /// \param type The element type of the tensor constant.
234  /// \param shape The shape of the tensor constant.
235  /// \param values An initializer_list of values to use as the constant data.
236  template <typename T>
237  static std::shared_ptr<Constant> create(const element::Type& type,
238  const Shape& shape,
239  std::initializer_list<T> values)
240  {
241  return std::make_shared<Constant>(type, shape, std::vector<T>{values});
242  }
243 
244  /// \brief Wrapper around constructing a shared_ptr of a Constant
245  ///
246  /// \param type The element type of the tensor constant.
247  /// \param shape The shape of the tensor constant.
248  /// \param memory An continues memory chunk which contains the constant data.
249  static std::shared_ptr<Constant>
250  create(const element::Type& type, const Shape& shape, const void* memory)
251  {
252  return std::make_shared<Constant>(type, shape, memory);
253  }
254 
255  virtual std::shared_ptr<Node>
256  clone_with_new_inputs(const OutputVector& new_args) const override;
257 
258  /// \return The initialization literals for the tensor constant.
259  std::vector<std::string> get_value_strings() const;
260 
261  template <typename T>
262  std::vector<T> get_vector() const
263  {
264  const T* p = get_data_ptr<T>();
265  if (p == nullptr)
266  throw std::runtime_error("Cannot create vector! Buffer is not allocated.");
267  return std::vector<T>(p, p + shape_size(m_shape));
268  }
269 
270  /// \brief Return the Constant's value as a vector cast to type T
271  ///
272  /// \tparam T Type to which data vector's entries will be cast.
273  /// \return Constant's data vector.
274  template <typename T>
275  std::vector<T> cast_vector() const
276  {
277  auto source_type = get_element_type();
278  std::vector<T> rc;
279  using Type_t = element::Type_t;
280 #if defined(_MSC_VER)
281 #pragma warning(push)
282 #pragma warning(disable : 4244)
283 #endif
284  switch (source_type)
285  {
286  case Type_t::boolean: cast_vector<Type_t::boolean>(rc); break;
287  case Type_t::bf16: cast_vector<Type_t::bf16>(rc); break;
288  case Type_t::f16: cast_vector<Type_t::f16>(rc); break;
289  case Type_t::f32: cast_vector<Type_t::f32>(rc); break;
290  case Type_t::f64: cast_vector<Type_t::f64>(rc); break;
291  case Type_t::i4: cast_vector<Type_t::i4>(rc); break;
292  case Type_t::i8: cast_vector<Type_t::i8>(rc); break;
293  case Type_t::i16: cast_vector<Type_t::i16>(rc); break;
294  case Type_t::i32: cast_vector<Type_t::i32>(rc); break;
295  case Type_t::i64: cast_vector<Type_t::i64>(rc); break;
296  case Type_t::u1: cast_vector<Type_t::u1>(rc); break;
297  case Type_t::u4: cast_vector<Type_t::u4>(rc); break;
298  case Type_t::u8: cast_vector<Type_t::u8>(rc); break;
299  case Type_t::u16: cast_vector<Type_t::u16>(rc); break;
300  case Type_t::u32: cast_vector<Type_t::u32>(rc); break;
301  case Type_t::u64: cast_vector<Type_t::u64>(rc); break;
302  default: throw std::runtime_error("unsupported type");
303  }
304 #if defined(_MSC_VER)
305 #pragma warning(pop)
306 #endif
307  return rc;
308  }
309 
310  const void* get_data_ptr() const { return (m_data ? m_data->get_ptr() : nullptr); }
311  template <typename T>
312  const T* get_data_ptr() const
313  {
314  if (sizeof(T) > m_element_type.size() && shape_size(m_shape) > 0)
315  {
316  throw ngraph_error("Buffer over-read");
317  }
318 
319  return static_cast<const T*>(get_data_ptr());
320  }
321 
322  template <element::Type_t ET>
323  const typename element_type_traits<ET>::value_type* get_data_ptr() const
324  {
325  NGRAPH_CHECK(ET == get_element_type(),
326  "get_data_ptr() called for incorrect element type.");
327  return static_cast<const typename element_type_traits<ET>::value_type*>(
328  get_data_ptr());
329  }
330 
331  bool get_all_data_elements_bitwise_identical() const
332  {
333  return m_all_elements_bitwise_identical;
334  }
335  std::string convert_value_to_string(size_t index) const;
336 
337  /**
338  * \brief Allows to avoid buffer allocation on the visit_attributes call
339  */
341  {
342  m_alloc_buffer_on_visit_attributes = val;
343  }
344 
345  private:
346  template <element::Type_t Type,
347  typename StorageDataType = fundamental_type_for<Type>,
348  typename std::enable_if<Type != element::Type_t::u1 &&
349  Type != element::Type_t::u4 &&
350  Type != element::Type_t::i4,
351  bool>::type = true>
352  StorageDataType get_element_value(size_t index) const
353  {
354  return get_data_ptr<Type>()[index];
355  }
356 
357  template <element::Type_t Type,
358  typename StorageDataType = fundamental_type_for<Type>,
359  typename std::enable_if<Type == element::Type_t::u1, bool>::type = true>
360  StorageDataType get_element_value(size_t index) const
361  {
362  return (get_data_ptr<uint8_t>()[index / 8] >> (7 - (index % 8))) & 1;
363  }
364 
365  template <element::Type_t Type,
366  typename StorageDataType = fundamental_type_for<Type>,
367  typename std::enable_if<Type == element::Type_t::u4, bool>::type = true>
368  StorageDataType get_element_value(size_t index) const
369  {
370  return (get_data_ptr<uint8_t>()[index / 2] >> (index % 2 ? 0 : 4)) & 0x0F;
371  }
372 
373  template <element::Type_t Type,
374  typename StorageDataType = fundamental_type_for<Type>,
375  typename std::enable_if<Type == element::Type_t::i4, bool>::type = true>
376  StorageDataType get_element_value(size_t index) const
377  {
378  const uint8_t i4data =
379  (get_data_ptr<uint8_t>()[index / 2] >> (index % 2 ? 0 : 4)) & 0x0F;
380  const bool is_negative_number = (i4data >> 3) & 0b1;
381  const int8_t data = is_negative_number ? i4data | 0xF0 : i4data;
382  return data;
383  }
384 
385  template <element::Type_t Type,
386  typename OUT_T,
387  typename std::enable_if<Type != element::Type_t::u1 &&
388  Type != element::Type_t::u4 &&
389  Type != element::Type_t::i4,
390  bool>::type = true>
391  void cast_vector(std::vector<OUT_T>& output_vector) const
392  {
393  // this function is workaround for waring during windows building
394  // build complains for vector creation based on iterators
395  // which point on different type than destination vector::value_type
396  using IN_T = fundamental_type_for<Type>;
397  auto source_vector = get_vector<IN_T>();
398  output_vector.reserve(source_vector.size());
399 
400  std::transform(source_vector.begin(),
401  source_vector.end(),
402  std::back_inserter(output_vector),
403  [](IN_T c) { return static_cast<OUT_T>(c); });
404  }
405 
406  template <element::Type_t Type,
407  typename OUT_T,
408  typename std::enable_if<Type == element::Type_t::u1, bool>::type = true>
409  void cast_vector(std::vector<OUT_T>& output) const
410  {
411  using IN_T = fundamental_type_for<Type>;
412  const auto element_number = shape_size(m_shape);
413  const auto source_begin = get_data_ptr<uint8_t>();
414  const auto source_end = std::next(source_begin, (element_number + 7) / 8);
415  const auto round_element_no = element_number % 8
416  ? element_number - element_number % 8 + 8
417  : element_number;
418  output.reserve(round_element_no); // adds 7 more elements here?
419  std::for_each(source_begin, source_end, [&](IN_T c) {
420  for (const auto i : {7, 6, 5, 4, 3, 2, 1, 0})
421  {
422  const uint8_t data = (c >> i) & 0x01;
423  output.push_back(data);
424  }
425  });
426  output.resize(element_number);
427  }
428 
429  template <element::Type_t Type,
430  typename OUT_T,
431  typename std::enable_if<Type == element::Type_t::u4, bool>::type = true>
432  void cast_vector(std::vector<OUT_T>& output) const
433  {
434  using IN_T = fundamental_type_for<Type>;
435  const auto element_number = shape_size(m_shape);
436  const auto source_begin = get_data_ptr<uint8_t>();
437  const auto source_end = std::next(source_begin, (element_number + 1) / 2);
438  const auto round_element_no =
439  element_number % 2 ? element_number + 1 : element_number;
440  output.reserve(round_element_no); // adds 1 more elements here?
441  std::for_each(source_begin, source_end, [&](IN_T c) {
442  for (const auto i : {4, 0})
443  {
444  const uint8_t data = (c >> i) & 0x0F;
445  output.push_back(data);
446  }
447  });
448  output.resize(element_number);
449  }
450  template <element::Type_t Type,
451  typename OUT_T,
452  typename std::enable_if<Type == element::Type_t::i4, bool>::type = true>
453  void cast_vector(std::vector<OUT_T>& output) const
454  {
455  using IN_T = fundamental_type_for<Type>;
456  const auto element_number = shape_size(m_shape);
457  const auto source_begin = get_data_ptr<uint8_t>();
458  const auto source_end = std::next(source_begin, (element_number + 1) / 2);
459  const auto round_element_no =
460  element_number % 2 ? element_number + 1 : element_number;
461  output.reserve(round_element_no); // adds 1 more elements here?
462  std::for_each(source_begin, source_end, [&](IN_T c) {
463  for (const auto i : {4, 0})
464  {
465  const uint8_t i4data = (c >> i) & 0x0F;
466  const bool is_negative_number = (i4data >> 3) & 0b1;
467  const int8_t data = is_negative_number ? i4data | 0xF0 : i4data;
468  output.push_back(data);
469  }
470  });
471  output.resize(element_number);
472  }
473 
474  template <element::Type_t Type,
475  typename T,
476  typename StorageDataType = fundamental_type_for<Type>,
477  typename std::enable_if<Type != element::Type_t::u1 &&
478  Type != element::Type_t::u4 &&
479  Type != element::Type_t::i4,
480  bool>::type = true>
481  void fill_data(const T& value)
482  {
483  const auto size = shape_size(m_shape);
484  const auto v = static_cast<StorageDataType>(value);
485  std::fill_n(get_data_ptr_nc<Type>(), size, v);
486  }
487 
488  template <element::Type_t Type,
489  typename T,
490  typename StorageDataType = fundamental_type_for<Type>,
491  typename std::enable_if<Type == element::Type_t::u1, bool>::type = true>
492  void fill_data(const T& value)
493  {
494  const StorageDataType v = value ? 0xFF : 0x00;
495  std::fill_n(get_data_ptr_nc<Type>(), mem_size(), v);
496  }
497 
498  template <element::Type_t Type,
499  typename T,
500  typename StorageDataType = fundamental_type_for<Type>,
501  typename std::enable_if<Type == element::Type_t::u4 ||
502  Type == element::Type_t::i4,
503  bool>::type = true>
504  void fill_data(const T& value)
505  {
506  uint8_t v = value_in_range<Type>(value);
507  v &= 0x0F;
508  v += v << 4;
509  std::fill_n(get_data_ptr_nc<Type>(), mem_size(), v);
510  }
511 
512  void allocate_buffer();
513 
514  void* get_data_ptr_nc() { return (m_data ? m_data->get_ptr() : nullptr); }
515 
516  template <element::Type_t ET>
517  typename element_type_traits<ET>::value_type* get_data_ptr_nc()
518  {
519  NGRAPH_CHECK(ET == get_element_type(),
520  "get_data_ptr_nc() called for incorrect element type.");
521  return static_cast<typename element_type_traits<ET>::value_type*>(
522  get_data_ptr_nc());
523  }
524 
525  Constant(const OutputVector& args)
526  : Op(args)
527  , m_shape({})
528  {
529  }
530 
531  virtual void infer_element_type() {}
532  template <typename T>
533  void write_values(const std::vector<T>& values)
534  {
535  write_to_buffer(values);
536  }
537 
538  template <element::Type_t Type,
539  typename T,
540  typename StorageDataType = fundamental_type_for<Type>,
541  typename std::enable_if<Type != element::Type_t::u1 &&
542  Type != element::Type_t::u4 &&
543  Type != element::Type_t::i4,
544  bool>::type = true>
545  void write_buffer(const std::vector<T>& source)
546  {
547  auto p = get_data_ptr_nc<Type>();
548  for (size_t i = 0; i < source.size(); i++)
549  {
550  p[i] = static_cast<StorageDataType>(source[i]);
551  }
552  }
553 
554  template <element::Type_t Type,
555  typename T,
556  typename StorageDataType = fundamental_type_for<Type>,
557  typename std::enable_if<Type == element::Type_t::u4 ||
558  Type == element::Type_t::i4,
559  bool>::type = true>
560  void write_buffer(const std::vector<T>& source)
561  {
562  auto p = get_data_ptr_nc<Type>();
563  size_t i = 0;
564  for (; i < source.size() / 2; i++)
565  {
566  const auto v1 = value_in_range<Type>(source[i * 2]) & 0x0F;
567  const auto v2 = value_in_range<Type>(source[i * 2 + 1]) & 0x0F;
568  const auto v = (v1 << 4) | v2;
569  p[i] = static_cast<StorageDataType>(v);
570  }
571  if (source.size() % 2)
572  {
573  const auto v1 = value_in_range<Type>(source[i * 2]) & 0x0F;
574  const auto v = v1 << 4;
575  p[i] = static_cast<StorageDataType>(v);
576  }
577  }
578 
579  template <element::Type_t Type,
580  typename T,
581  typename StorageDataType = fundamental_type_for<Type>,
582  typename std::enable_if<Type == element::Type_t::u1, bool>::type = true>
583  void write_buffer(const std::vector<T>& source)
584  {
585  auto p = get_data_ptr_nc<Type>();
586  size_t i = 0;
587  for (; i < source.size() / 8; i++)
588  {
589  uint8_t v{};
590  for (int j = 0; j != 8; j++)
591  {
592  const uint8_t b = source[i * 8 + j] ? 0x01 << (7 - j) : 0;
593  v |= b;
594  }
595  p[i] = static_cast<StorageDataType>(v);
596  }
597  uint8_t v{};
598  for (unsigned j = 0; j != source.size() % 8; j++)
599  {
600  const uint8_t b = source[i * 8 + j] ? 0x01 << (7 - j) : 0;
601  v |= b;
602  }
603  p[i] = static_cast<StorageDataType>(v);
604  }
605 
606  template <typename T>
607  void write_to_buffer(const std::vector<T>& source)
608  {
609  const auto& target_type = m_element_type;
610  size_t target_element_count = shape_size(m_shape);
611  if (source.size() != target_element_count)
612  {
613  throw std::runtime_error("Constant initializer does not match shape");
614  }
615  using Type_t = element::Type_t;
616 #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8)
617 #pragma GCC diagnostic push
618 #pragma GCC diagnostic error "-Wswitch"
619 #pragma GCC diagnostic error "-Wswitch-enum"
620 #endif
621  switch (target_type)
622  {
623  case Type_t::boolean: write_buffer<Type_t::boolean>(source); break;
624  case Type_t::bf16: write_buffer<Type_t::bf16>(source); break;
625  case Type_t::f16: write_buffer<Type_t::f16>(source); break;
626  case Type_t::f32: write_buffer<Type_t::f32>(source); break;
627  case Type_t::f64: write_buffer<Type_t::f64>(source); break;
628  case Type_t::i4: write_buffer<Type_t::i4>(source); break;
629  case Type_t::i8: write_buffer<Type_t::i8>(source); break;
630  case Type_t::i16: write_buffer<Type_t::i16>(source); break;
631  case Type_t::i32: write_buffer<Type_t::i32>(source); break;
632  case Type_t::i64: write_buffer<Type_t::i64>(source); break;
633  case Type_t::u1: write_buffer<Type_t::u1>(source); break;
634  case Type_t::u4: write_buffer<Type_t::u4>(source); break;
635  case Type_t::u8: write_buffer<Type_t::u8>(source); break;
636  case Type_t::u16: write_buffer<Type_t::u16>(source); break;
637  case Type_t::u32: write_buffer<Type_t::u32>(source); break;
638  case Type_t::u64: write_buffer<Type_t::u64>(source); break;
639  case element::Type_t::undefined:
640  case element::Type_t::dynamic: throw std::runtime_error("unsupported type");
641  }
642 #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8)
643 #pragma GCC diagnostic pop
644 #endif
645  }
646  template <
647  ngraph::element::Type_t Type,
648  typename ValueT,
649  typename std::enable_if<Type == ngraph::element::Type_t::u4, bool>::type = true>
650  static ngraph::fundamental_type_for<Type> value_in_range(const ValueT& value)
651  {
652  const auto result = ngraph::fundamental_type_for<Type>(value);
653  NGRAPH_CHECK(0 <= result && result <= 15,
654  "assigned value out of range u4 values");
655  return result;
656  }
657 
658  template <
659  ngraph::element::Type_t Type,
660  typename ValueT,
661  typename std::enable_if<Type == ngraph::element::Type_t::i4, bool>::type = true>
662  static ngraph::fundamental_type_for<Type> value_in_range(const ValueT& value)
663  {
664  const auto result = ngraph::fundamental_type_for<Type>(value);
665  NGRAPH_CHECK(-8 <= result && result <= 7,
666  "assigned value out of range i4 values");
667  return result;
668  }
669 
670  bool are_all_data_elements_bitwise_identical() const;
671  static constexpr size_t host_alignment() { return 64; }
672 
673  size_t mem_size() const
674  {
675  const bool bitwidth_less_than_byte = m_element_type.bitwidth() < 8;
676  if (bitwidth_less_than_byte)
677  {
678  const auto size = shape_size(m_shape);
679  const auto bitwidth = size * m_element_type.bitwidth();
680  // for rounding by `(bitwidth + 7) / 8` will work for
681  // `bitwidth < numeric_limits<size_t>::max() - 7`
682  return bitwidth / 8 + (bitwidth % 8 ? 1 : 0);
683  }
684  return shape_size(m_shape) * m_element_type.size();
685  }
686 
687  element::Type m_element_type;
688  Shape m_shape{};
689  std::shared_ptr<runtime::AlignedBuffer> m_data;
690  bool m_all_elements_bitwise_identical;
691  bool m_alloc_buffer_on_visit_attributes = true;
692  };
693  } // namespace v0
694  using v0::Constant;
695  } // namespace op
696 } // namespace ngraph
Visits the attributes of a node, primarily for serialization-like tasks.
Definition: attribute_visitor.hpp:59
A set of axes.
Definition: axis_set.hpp:19
A vector of axes.
Definition: axis_vector.hpp:18
A difference (signed) of tensor element coordinates.
Definition: coordinate_diff.hpp:18
Coordinates for a tensor element.
Definition: coordinate.hpp:18
Shape for a tensor.
Definition: shape.hpp:19
Strides for a tensor.
Definition: strides.hpp:18
Definition: element_type.hpp:51
Base error for ngraph runtime errors.
Definition: except.hpp:16
Root of all actual ops.
Definition: op.hpp:17
Class for constants.
Definition: constant.hpp:27
std::vector< T > cast_vector() const
Return the Constant's value as a vector cast to type T.
Definition: constant.hpp:275
static std::shared_ptr< Constant > create(const element::Type &type, const Shape &shape, std::initializer_list< T > values)
Wrapper around constructing a shared_ptr of a Constant.
Definition: constant.hpp:237
std::vector< std::string > get_value_strings() const
bool has_evaluate() const override
Allows to get information about availability of evaluate method for the current operation.
void alloc_buffer_on_visit_attributes(bool val)
Allows to avoid buffer allocation on the visit_attributes call.
Definition: constant.hpp:340
Constant(const element::Type &type, const Shape &shape, const void *data)
Constructs a tensor constant with the supplied data.
AxisSet get_axis_set_val() const
Returns the value of the constant node as an AxisSet object Can only be used on element::i64 nodes an...
Constant(const std::shared_ptr< runtime::Tensor > &tensor)
Initialize a constant from tensor.
static std::shared_ptr< Constant > create(const element::Type &type, const Shape &shape, const std::vector< T > &values)
Wrapper around constructing a shared_ptr of a Constant.
Definition: constant.hpp:224
AxisVector get_axis_vector_val() const
Returns the value of the constant node as an AxisVector object Can only be used on element::i64 nodes...
const NodeTypeInfo & get_type_info() const override
Definition: constant.hpp:30
Constant(const element::Type &type, const Shape &shape)
Create uninitialized constant.
Constant(const element::Type &type, const Shape &shape, const std::vector< std::string > &values)
Constructs a tensor constant This constructor is mainly to support deserialization of constants.
CoordinateDiff get_coordinate_diff_val() const
Returns the value of the constant node as a CoordinateDiff object Can only be used on element::i64 no...
bool evaluate(const HostTensorVector &outputs, const HostTensorVector &inputs) const override
Evaluates the op on input_values putting results in output_values.
void set_data_shape(const Shape &shape)
Update Constant shape. New shape size must equal to the data elements count.
Strides get_strides_val() const
Returns the value of the constant node as a Strides object Can only be used on element::i64 nodes and...
Constant(const element::Type &type, const Shape &shape, T value)
Constructs a uniform tensor constant.
Definition: constant.hpp:82
static std::shared_ptr< Constant > create(const element::Type &type, const Shape &shape, const void *memory)
Wrapper around constructing a shared_ptr of a Constant.
Definition: constant.hpp:250
Constant(const element::Type &type, const Shape &shape, std::shared_ptr< runtime::SharedBuffer< T >> data)
Constructs a tensor constant with the supplied data.
Definition: constant.hpp:147
Shape get_shape_val() const
Returns the value of the constant node as a Shape object Can only be used on element::i64 nodes and i...
Coordinate get_coordinate_val() const
Returns the value of the constant node as a Coordinate object Can only be used on element::i64 nodes ...
Constant(const element::Type &type, const Shape &shape, const std::vector< T > &values)
Constructs a tensor constant.
Definition: constant.hpp:44
void validate_and_infer_types() override
Verifies that attributes and inputs are consistent and computes output shapes and element types....
Definition: constant.hpp:162
SharedBuffer class to store pointer to pre-acclocated buffer.
Definition: shared_buffer.hpp:18
The Intel nGraph C++ API.
Definition: attribute_adapter.hpp:16
size_t shape_size(const SHAPE_TYPE &shape)
Number of elements in spanned by a shape.
Definition: shape.hpp:59
Definition: type.hpp:27