1+ #include " layers/ConcatLayer.hpp"
2+
3+ namespace it_lab_ai {
4+
5+ void ConcatLayer::run (const std::vector<Tensor>& input,
6+ std::vector<Tensor>& output) {
7+ if (input.empty ()) {
8+ throw std::runtime_error (" ConcatLayer: No input tensors provided" );
9+ }
10+
11+ if (input.size () == 1 ) {
12+ output = input;
13+ return ;
14+ }
15+
16+ this ->validate_inputs (input);
17+
18+ switch (input[0 ].get_type ()) {
19+ case Type::kFloat :
20+ this ->concatenate <float >(input, output[0 ]);
21+ break ;
22+ case Type::kInt :
23+ this ->concatenate <int >(input, output[0 ]);
24+ break ;
25+ default :
26+ throw std::runtime_error (" ConcatLayer: Unsupported input tensor type" );
27+ }
28+ }
29+
30+ void ConcatLayer::validate_inputs (const std::vector<Tensor>& inputs) const {
31+ if (inputs.empty ()) return ;
32+
33+ const Shape& first_shape = inputs[0 ].get_shape ();
34+ Type first_type = inputs[0 ].get_type ();
35+ const int64_t normalized_axis = normalize_axis (first_shape.dims ());
36+
37+ for (size_t i = 1 ; i < inputs.size (); ++i) {
38+ const Shape& shape = inputs[i].get_shape ();
39+ if (shape.dims () != first_shape.dims ()) {
40+ throw std::runtime_error (
41+ " ConcatLayer: All input tensors must have the same rank" );
42+ }
43+
44+ if (inputs[i].get_type () != first_type) {
45+ throw std::runtime_error (
46+ " ConcatLayer: All input tensors must have the same type" );
47+ }
48+
49+ for (size_t dim = 0 ; dim < shape.dims (); ++dim) {
50+ if (dim != static_cast <size_t >(normalized_axis) &&
51+ shape[dim] != first_shape[dim]) {
52+ throw std::runtime_error (
53+ " ConcatLayer: All input tensors must have the same shape except "
54+ " for the concatenation axis" );
55+ }
56+ }
57+ }
58+ }
59+
60+ int64_t ConcatLayer::normalize_axis (size_t rank) const {
61+ if (rank == 0 ) {
62+ throw std::runtime_error (" ConcatLayer: Cannot concatenate scalar tensors" );
63+ }
64+
65+ int64_t axis = axis_;
66+
67+ if (axis < 0 ) {
68+ axis += static_cast <int64_t >(rank);
69+ }
70+
71+ if (axis < 0 || axis >= static_cast <int64_t >(rank)) {
72+ throw std::runtime_error (" ConcatLayer: Axis " + std::to_string (axis_) +
73+ " out of range for tensor rank " +
74+ std::to_string (rank));
75+ }
76+
77+ return axis;
78+ }
79+
80+ std::vector<Tensor> ConcatLayer::reorderInputs (
81+ const std::vector<Tensor>& inputs) const {
82+ if (input_order_.empty () || input_order_.size () != inputs.size ()) {
83+ return inputs;
84+ }
85+
86+ std::vector<Tensor> reordered (inputs.size ());
87+ for (size_t i = 0 ; i < inputs.size (); ++i) {
88+ if (input_order_[i] >= 0 &&
89+ static_cast <size_t >(input_order_[i]) < inputs.size ()) {
90+ reordered[i] = inputs[input_order_[i]];
91+ } else {
92+ throw std::runtime_error (" ConcatLayer: Invalid input order index" );
93+ }
94+ }
95+ return reordered;
96+ }
97+
98+ Shape ConcatLayer::calculate_output_shape (
99+ const std::vector<Tensor>& inputs) const {
100+ if (inputs.empty ()) return Shape ({});
101+
102+ const Shape& first_shape = inputs[0 ].get_shape ();
103+ std::vector<size_t > output_dims (first_shape.dims ());
104+ for (size_t i = 0 ; i < first_shape.dims (); ++i) {
105+ output_dims[i] = first_shape[i];
106+ }
107+
108+ const int64_t normalized_axis = normalize_axis (first_shape.dims ());
109+ output_dims[normalized_axis] = 0 ;
110+ for (const auto & input : inputs) {
111+ output_dims[normalized_axis] += input.get_shape ()[normalized_axis];
112+ }
113+
114+ return Shape (output_dims);
115+ }
116+
117+ } // namespace it_lab_ai
0 commit comments