@@ -586,11 +586,12 @@ TEST_F(PathValidationTest, ValidateExternalDataPathWithSymlinkOutside) {
586586 ASSERT_FALSE (utils::ValidateExternalDataPath (base_dir_, " outside_link.bin" ).IsOK ());
587587}
588588
589- template <typename T>
589+ template <typename T, typename I >
590590void TestSparseToDenseConversion (gsl::span<const int64_t > dense_shape,
591591 const std::vector<T>& values,
592- gsl::span<const int64_t > indices,
592+ gsl::span<const I > indices,
593593 gsl::span<const int64_t > indices_shape,
594+ bool raw_data_indices,
594595 const std::vector<T>& expected_dense_data) {
595596 ONNX_NAMESPACE::SparseTensorProto sparse_proto;
596597 for (auto dim : dense_shape) {
@@ -615,8 +616,42 @@ void TestSparseToDenseConversion(gsl::span<const int64_t> dense_shape,
615616 auto * indices_tensor = sparse_proto.mutable_indices ();
616617 indices_tensor->set_name (" indices" );
617618 indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT64);
618- for (int64_t idx : indices) {
619- indices_tensor->add_int64_data (idx);
619+ if constexpr (std::is_same_v<I, int8_t >) {
620+ indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT8);
621+ if (raw_data_indices) {
622+ indices_tensor->set_raw_data (indices.data (), indices.size () * sizeof (I));
623+ } else {
624+ for (auto idx : indices) {
625+ indices_tensor->add_int32_data (static_cast <int32_t >(idx)); // indices are stored in int32_data for types < int32
626+ }
627+ }
628+ } else if constexpr (std::is_same_v<I, int16_t >) {
629+ indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT16);
630+ if (raw_data_indices) {
631+ indices_tensor->set_raw_data (indices.data (), indices.size () * sizeof (I));
632+ } else {
633+ for (auto idx : indices) {
634+ indices_tensor->add_int32_data (static_cast <int32_t >(idx));
635+ }
636+ }
637+ } else if constexpr (std::is_same_v<I, int32_t >) {
638+ indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT32);
639+ if (raw_data_indices) {
640+ indices_tensor->set_raw_data (indices.data (), indices.size () * sizeof (I));
641+ } else {
642+ for (auto idx : indices) {
643+ indices_tensor->add_int32_data (idx);
644+ }
645+ }
646+ } else if constexpr (std::is_same_v<I, int64_t >) {
647+ indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT64);
648+ if (raw_data_indices) {
649+ indices_tensor->set_raw_data (indices.data (), indices.size () * sizeof (I));
650+ } else {
651+ for (auto idx : indices) {
652+ indices_tensor->add_int64_data (idx);
653+ }
654+ }
620655 }
621656 for (auto dim : indices_shape) {
622657 indices_tensor->add_dims (dim);
@@ -638,7 +673,7 @@ void TestSparseToDenseConversion(gsl::span<const int64_t> dense_shape,
638673 EXPECT_EQ (unpacked_data, expected_dense_data);
639674}
640675
641- TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices ) {
676+ TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices64 ) {
642677 // Dense Shape: [2, 2] -> 4 elements
643678 // Indices: [0, 3] (linear)
644679 // Values: [1.0, 2.0]
@@ -649,7 +684,53 @@ TEST(TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices) {
649684 std::vector<int64_t > indices_shape = {2 }; // [NNZ]
650685 std::vector<float > expected = {1 .0f , 0 .0f , 0 .0f , 2 .0f };
651686
652- TestSparseToDenseConversion<float >(dense_shape, values, indices, indices_shape, expected);
687+ TestSparseToDenseConversion<float , int64_t >(dense_shape, values, indices, indices_shape, false , expected);
688+ TestSparseToDenseConversion<float , int64_t >(dense_shape, values, indices, indices_shape, true , expected);
689+ }
690+
691+ TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices32) {
692+ // Dense Shape: [2, 2] -> 4 elements
693+ // Indices: [0, 3] (linear)
694+ // Values: [1.0, 2.0]
695+ // Expected: [1.0, 0.0, 0.0, 2.0]
696+ std::vector<int64_t > dense_shape = {2 , 2 };
697+ std::vector<float > values = {1 .0f , 2 .0f };
698+ std::vector<int32_t > indices = {0 , 3 };
699+ std::vector<int64_t > indices_shape = {2 }; // [NNZ]
700+ std::vector<float > expected = {1 .0f , 0 .0f , 0 .0f , 2 .0f };
701+
702+ TestSparseToDenseConversion<float , int32_t >(dense_shape, values, indices, indices_shape, false , expected);
703+ TestSparseToDenseConversion<float , int32_t >(dense_shape, values, indices, indices_shape, true , expected);
704+ }
705+
706+ TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices16) {
707+ // Dense Shape: [2, 2] -> 4 elements
708+ // Indices: [0, 3] (linear)
709+ // Values: [1.0, 2.0]
710+ // Expected: [1.0, 0.0, 0.0, 2.0]
711+ std::vector<int64_t > dense_shape = {2 , 2 };
712+ std::vector<float > values = {1 .0f , 2 .0f };
713+ std::vector<int16_t > indices = {0 , 3 };
714+ std::vector<int64_t > indices_shape = {2 }; // [NNZ]
715+ std::vector<float > expected = {1 .0f , 0 .0f , 0 .0f , 2 .0f };
716+
717+ TestSparseToDenseConversion<float , int16_t >(dense_shape, values, indices, indices_shape, false , expected);
718+ TestSparseToDenseConversion<float , int16_t >(dense_shape, values, indices, indices_shape, true , expected);
719+ }
720+
721+ TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank1Indices8) {
722+ // Dense Shape: [2, 2] -> 4 elements
723+ // Indices: [0, 3] (linear)
724+ // Values: [1.0, 2.0]
725+ // Expected: [1.0, 0.0, 0.0, 2.0]
726+ std::vector<int64_t > dense_shape = {2 , 2 };
727+ std::vector<float > values = {1 .0f , 2 .0f };
728+ std::vector<int8_t > indices = {0 , 3 };
729+ std::vector<int64_t > indices_shape = {2 }; // [NNZ]
730+ std::vector<float > expected = {1 .0f , 0 .0f , 0 .0f , 2 .0f };
731+
732+ TestSparseToDenseConversion<float , int8_t >(dense_shape, values, indices, indices_shape, false , expected);
733+ TestSparseToDenseConversion<float , int8_t >(dense_shape, values, indices, indices_shape, true , expected);
653734}
654735
655736TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Rank2Indices_COO) {
@@ -666,7 +747,8 @@ TEST(TensorProtoUtilsTest, SparseTensorProtoToDense_Rank2Indices_COO) {
666747 0 , 20 , 0 ,
667748 0 , 0 , 30 };
668749
669- TestSparseToDenseConversion<int32_t >(dense_shape, values, indices, indices_shape, expected);
750+ TestSparseToDenseConversion<int32_t , int64_t >(dense_shape, values, indices, indices_shape, false , expected);
751+ TestSparseToDenseConversion<int32_t , int64_t >(dense_shape, values, indices, indices_shape, true , expected);
670752}
671753
672754TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_InvalidIndicesRank) {
@@ -795,70 +877,5 @@ TEST(TensorProtoUtilsTest, SparseTensorProtoToDense_NegativeDenseShape) {
795877 EXPECT_THAT (status.ErrorMessage (), testing::HasSubstr (" Sparse tensor dense dims expected to be positive" ));
796878}
797879
798- template <typename T>
799- void TestSparseToDenseConversionWithInt8Indices (const std::vector<int64_t >& dense_shape,
800- const std::vector<T>& values,
801- const std::vector<int8_t >& indices,
802- const std::vector<int64_t >& indices_shape,
803- const std::vector<T>& expected_dense_data) {
804- ONNX_NAMESPACE::SparseTensorProto sparse_proto;
805- for (auto dim : dense_shape) {
806- sparse_proto.add_dims (dim);
807- }
808-
809- // Create values tensor
810- auto * values_tensor = sparse_proto.mutable_values ();
811- values_tensor->set_name (" values" );
812- if constexpr (std::is_same_v<T, float >) {
813- values_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_FLOAT);
814- for (float v : values) values_tensor->add_float_data (v);
815- } else if constexpr (std::is_same_v<T, int32_t >) {
816- values_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT32);
817- for (int32_t v : values) values_tensor->add_int32_data (v);
818- }
819- values_tensor->add_dims (values.size ());
820-
821- // Create indices tensor with INT8 data in raw_data
822- auto * indices_tensor = sparse_proto.mutable_indices ();
823- indices_tensor->set_name (" indices" );
824- indices_tensor->set_data_type (ONNX_NAMESPACE::TensorProto_DataType_INT8);
825-
826- std::string raw_indices_data;
827- raw_indices_data.resize (indices.size () * sizeof (int8_t ));
828- std::memcpy (raw_indices_data.data (), indices.data (), raw_indices_data.size ());
829- indices_tensor->set_raw_data (raw_indices_data);
830-
831- for (auto dim : indices_shape) {
832- indices_tensor->add_dims (dim);
833- }
834-
835- ONNX_NAMESPACE::TensorProto dense_proto;
836- std::filesystem::path model_path;
837- ASSERT_STATUS_OK (utils::SparseTensorProtoToDenseTensorProto (sparse_proto, model_path, dense_proto));
838-
839- // Verify dense proto
840- ASSERT_EQ (dense_proto.dims_size (), dense_shape.size ());
841- for (size_t i = 0 ; i < (size_t )dense_shape.size (); ++i) {
842- ASSERT_EQ (dense_proto.dims (static_cast <int >(i)), dense_shape[i]);
843- }
844-
845- std::vector<T> unpacked_data (expected_dense_data.size ());
846- ASSERT_STATUS_OK (utils::UnpackTensor (dense_proto, model_path, unpacked_data.data (), unpacked_data.size ()));
847-
848- EXPECT_EQ (unpacked_data, expected_dense_data);
849- }
850-
851- TEST (TensorProtoUtilsTest, SparseTensorProtoToDense_Int8Indices) {
852- // Dense Shape: [5], Indices: [1, 4], Values: [10, 20]
853- // Expected: [0, 10, 0, 0, 20]
854- std::vector<int64_t > dense_shape = {5 };
855- std::vector<int32_t > values = {10 , 20 };
856- std::vector<int8_t > indices = {1 , 4 };
857- std::vector<int64_t > indices_shape = {2 };
858- std::vector<int32_t > expected = {0 , 10 , 0 , 0 , 20 };
859-
860- TestSparseToDenseConversionWithInt8Indices (dense_shape, values, indices, indices_shape, expected);
861- }
862-
863880} // namespace test
864881} // namespace onnxruntime
0 commit comments