// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

///////////////////////////////////////////////////////////////////////////////////////////////////

#include "test_utils.h"

#include <intel_gpu/primitives/input_layout.hpp>
#include <intel_gpu/primitives/strided_slice.hpp>
#include <intel_gpu/primitives/data.hpp>

using namespace cldnn;
using namespace ::tests;

TEST(strided_slice_gpu_f32_i32, test_2x2x2x2_full) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values(begin, {
            0, 0, 0, 0
    });
    set_values(end, {
            2, 2, 2, 2
    });
    set_values(strides, {
            1, 1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x2_full) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values<int64_t>(begin, {
            0, 0, 0, 0
    });
    set_values<int64_t>(end, {
            2, 2, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x2_ignore) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 1x1x1x1
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values(begin, {
            1, 1, 1, 1
    });
    set_values(end, {
            2, 2, 2, 2
    });
    set_values(strides, {
            1, 1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0, 0, 0, 0}, {0, 0, 0, 0}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
        0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
        9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x2_ignore) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 1x1x1x1
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values<int64_t>(begin, {
            1, 1, 1, 1
    });
    set_values<int64_t>(end, {
            2, 2, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0, 0, 0, 0}, {0, 0, 0, 0}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
        0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
        9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x2_single) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 1x1x1x1
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
               });
    set_values(begin, {
            1, 1, 1, 1
               });
    set_values(end, {
            2, 2, 2, 2
               });
    set_values(strides, {
            1, 1, 1, 1
               });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = { 15.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x2_single) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 1x1x1x1
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): 1x1x1x1
    // Output (BFYX): 1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
               });
    set_values<int64_t>(begin, {
            1, 1, 1, 1
               });
    set_values<int64_t>(end, {
            2, 2, 2, 2
               });
    set_values<int64_t>(strides, {
            1, 1, 1, 1
               });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = { 15.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x4x3_stride) {
    // Input (BFYX): 2x2x4x3
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x4x3
    // Stride (BFYX): 1x1x2x1
    // Output (BFYX): 2x2x2x3

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 3, 4 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
            9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f, 17.f,
            18.f, 19.f, 20.f, 21.f, 22.f, 23.f, 24.f, 25.f, 26.f,
            27.f, 28.f, 29.f, 30.f, 31.f, 32.f, 33.f, 34.f, 35.f,
            36.f, 37.f, 38.f, 39.f, 40.f, 41.f, 42.f, 43.f, 44.f,
            45.f, 46.f, 47.f
    });
    set_values(begin, {
            0, 0, 0, 0
    });
    set_values(end, {
            2, 2, 4, 3
    });
    set_values(strides, {
            1, 1, 2, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0, 0, 0, 0}, {0, 0, 0, 0}, {}, {}, tensor{2, 2, 3, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.f, 1.f, 2.f, 6.f, 7.f, 8.f, 12.f, 13.f, 14.f, 18.f, 19.f, 20.f,
            24.f, 25.f, 26.f, 30.f, 31.f, 32.f, 36.f, 37.f, 38.f, 42.f, 43.f, 44.f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x4x3_stride) {
    // Input (BFYX): 2x2x4x3
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x4x3
    // Stride (BFYX): 1x1x2x1
    // Output (BFYX): 2x2x2x3

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 3, 4 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
            9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f, 17.f,
            18.f, 19.f, 20.f, 21.f, 22.f, 23.f, 24.f, 25.f, 26.f,
            27.f, 28.f, 29.f, 30.f, 31.f, 32.f, 33.f, 34.f, 35.f,
            36.f, 37.f, 38.f, 39.f, 40.f, 41.f, 42.f, 43.f, 44.f,
            45.f, 46.f, 47.f
    });
    set_values<int64_t>(begin, {
            0, 0, 0, 0
    });
    set_values<int64_t>(end, {
            2, 2, 4, 3
    });
    set_values<int64_t>(strides, {
            1, 1, 2, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0, 0, 0, 0}, {0, 0, 0, 0}, {}, {}, tensor{2, 2, 3, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.f, 1.f, 2.f, 6.f, 7.f, 8.f, 12.f, 13.f, 14.f, 18.f, 19.f, 20.f,
            24.f, 25.f, 26.f, 30.f, 31.f, 32.f, 36.f, 37.f, 38.f, 42.f, 43.f, 44.f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x4x4_part_stride) {
    // Input (BFYX): 2x2x4x4
    // Begin (BFYX): 1x0x0x1
    // End (BFYX): 2x2x4x4
    // Stride (BFYX): 1x1x1x2
    // Output (BFYX): 1x2x4x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 4, 4 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f,
            4.0f, 5.0f, 6.0f, 7.0f,
            8.0f, 9.0f, 10.0f, 11.0f,
            12.0f, 13.0f, 14.0f, 15.0f,

            16.0f, 17.0f, 18.0f, 19.0f,
            20.0f, 21.0f, 22.0f, 23.0f,
            24.0f, 25.0f, 26.0f, 27.0f,
            28.0f, 29.0f, 30.0f, 31.0f,

            32.0f, 33.0f, 34.0f, 35.0f,
            36.0f, 37.0f, 38.0f, 39.0f,
            40.0f, 41.0f, 42.0f, 43.0f,
            44.0f, 45.0f, 46.0f, 47.0f,

            48.0f, 49.0f, 50.0f, 51.0f,
            52.0f, 53.0f, 54.0f, 55.0f,
            56.0f, 57.0f, 58.0f, 59.0f,
            60.0f, 61.0f, 62.0f, 63.0f
    });
    set_values(begin, {
            1, 0, 0, 1
    });
    set_values(end, {
            2, 2, 4, 4
    });
    set_values(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {1, 0, 0, 1}, {}, {}, {}, tensor{1, 2, 2, 4}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            33.0f, 35.0f,
            37.0f, 39.0f,
            41.0f, 43.0f,
            45.0f, 47.0f,

            49.0f, 51.0f,
            53.0f, 55.0f,
            57.0f, 59.0f,
            61.0f, 63.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x4x4_part_stride) {
    // Input (BFYX): 2x2x4x4
    // Begin (BFYX): 1x0x0x1
    // End (BFYX): 2x2x4x4
    // Stride (BFYX): 1x1x1x2
    // Output (BFYX): 1x2x4x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 4, 4 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f,
            4.0f, 5.0f, 6.0f, 7.0f,
            8.0f, 9.0f, 10.0f, 11.0f,
            12.0f, 13.0f, 14.0f, 15.0f,

            16.0f, 17.0f, 18.0f, 19.0f,
            20.0f, 21.0f, 22.0f, 23.0f,
            24.0f, 25.0f, 26.0f, 27.0f,
            28.0f, 29.0f, 30.0f, 31.0f,

            32.0f, 33.0f, 34.0f, 35.0f,
            36.0f, 37.0f, 38.0f, 39.0f,
            40.0f, 41.0f, 42.0f, 43.0f,
            44.0f, 45.0f, 46.0f, 47.0f,

            48.0f, 49.0f, 50.0f, 51.0f,
            52.0f, 53.0f, 54.0f, 55.0f,
            56.0f, 57.0f, 58.0f, 59.0f,
            60.0f, 61.0f, 62.0f, 63.0f
    });
    set_values<int64_t>(begin, {
            1, 0, 0, 1
    });
    set_values<int64_t>(end, {
            2, 2, 4, 4
    });
    set_values<int64_t>(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {1, 0, 0, 1}, {}, {}, {}, tensor{1, 2, 2, 4}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            33.0f, 35.0f,
            37.0f, 39.0f,
            41.0f, 43.0f,
            45.0f, 47.0f,

            49.0f, 51.0f,
            53.0f, 55.0f,
            57.0f, 59.0f,
            61.0f, 63.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x4x1_new_axis_mask) {
    // Input (BFYX): 2x2x4x1
    // New_axis_mask: 1
    // Output (BFYX): 1x2x2x4

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 4 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
            10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values(begin, {
            1, 0, 1, 0
    });
    set_values(end, {
            2, 2, 4, 4
    });
    set_values(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, { 1 }, {}, tensor{2, 2, 1, 4}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
            10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x4x1_new_axis_mask) {
    // Input (BFYX): 2x2x4x1
    // New_axis_mask: 1
    // Output (BFYX): 1x2x2x4

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 4 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
            10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values<int64_t>(begin, {
            1, 0, 1, 0
    });
    set_values<int64_t>(end, {
            2, 2, 4, 4
    });
    set_values<int64_t>(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, { 1 }, {}, tensor{2, 2, 1, 4}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f,
            10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x1x1_new_axis_mask_2) {
    // Input (BFYX): 2x2x1x1
    // New_axis_mask: 101
    // Output (BFYX): 1x2x1x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 1 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f
    });
    set_values(begin, {
            1, 0, 1, 0
    });
    set_values(end, {
            2, 2, 4, 4
    });
    set_values(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, { 1, 0, 1 }, {}, tensor{2, 2, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x1x1_new_axis_mask_2) {
    // Input (BFYX): 2x2x1x1
    // New_axis_mask: 101
    // Output (BFYX): 1x2x1x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 1 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f
    });
    set_values<int64_t>(begin, {
            1, 0, 1, 0
    });
    set_values<int64_t>(end, {
            2, 2, 4, 4
    });
    set_values<int64_t>(strides, {
            1, 1, 1, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, { 1, 0, 1 }, {}, tensor{2, 2, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x1x1) {
    // Input (BFYX): 2x2x1x1
    // Output (BFYX): 2x2x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 1 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 2, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 2, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 2, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f
    });
    set_values(begin, {
            0, 0
    });
    set_values(end, {
            2, 2
    });
    set_values(strides, {
            1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0,1}, {}, {}, {}, tensor{2, 2, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x1x1) {
    // Input (BFYX): 2x2x1x1
    // Output (BFYX): 2x2x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 1, 1 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 2, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 2, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 2, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f
    });
    set_values<int64_t>(begin, {
            0, 0
    });
    set_values<int64_t>(end, {
            2, 2
    });
    set_values<int64_t>(strides, {
            1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {0,1}, {}, {}, {}, tensor{2, 2, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x1x1) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 1x2x2x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values(begin, {
            0, 0, 0
    });
    set_values(end, {
            1, 2, 2
    });
    set_values(strides, {
            1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{1, 2, 1, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x1x1) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 1x2x2x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values<int64_t>(begin, {
            0, 0, 0
    });
    set_values<int64_t>(end, {
            1, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{1, 2, 1, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 1.0f, 2.0f, 3.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}


TEST(strided_slice_gpu_i8_i64, test_2x2x2x1x1) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 1x2x2x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::i8, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });

    set_values<int8_t>(input, {
            0, 1, 2, 3, 4, 5, 6, 7
    });
    set_values<int64_t>(begin, {
            0, 0, 0
    });
    set_values<int64_t>(end, {
            1, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{1, 2, 1, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<int8_t> answers = {
            0, 1, 2, 3
    };

    cldnn::mem_lock<int8_t> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i) {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x1x1_2) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 2x1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values(begin, {
            0, 0, 0
    });
    set_values(end, {
            2, 2, 2
    });
    set_values(strides, {
            1, 2, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 1, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 4.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x1x1_2) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 2x1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values<int64_t>(begin, {
            0, 0, 0
    });
    set_values<int64_t>(end, {
            2, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 2, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 1, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 4.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x2_full_negative_stride) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): -1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values(begin, {
            0, 0, 0, 0
    });
    set_values(end, {
            2, 2, 2, 2
    });
    set_values(strides, {
            -1, -1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            12.f, 13.f, 14.f, 15.f, 8.f, 9.f, 10.f, 11.f, 4.f, 5.f, 6.f, 7.f, 0.f, 1.f, 2.f, 3.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x2_full_negative_stride) {
    // Input (BFYX): 2x2x2x2
    // Begin (BFYX): 0x0x0x0
    // End (BFYX): 2x2x2x2
    // Stride (BFYX): -1x1x1x1
    // Output (BFYX): 2x2x2x2

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfyx, { 2, 2, 2, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 4, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
            9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f
    });
    set_values<int64_t>(begin, {
            0, 0, 0, 0
    });
    set_values<int64_t>(end, {
            2, 2, 2, 2
    });
    set_values<int64_t>(strides, {
            -1, -1, 1, 1
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 2, 2, 2}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            12.f, 13.f, 14.f, 15.f, 8.f, 9.f, 10.f, 11.f, 4.f, 5.f, 6.f, 7.f, 0.f, 1.f, 2.f, 3.f };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    ASSERT_EQ(output_ptr.size(), answers.size());
    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i32, test_2x2x2x1x1_2_negative_all) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 2x1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i32, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values(begin, {
            0, 0, 0
    });
    set_values(end, {
            2, 2, 2
    });
    set_values(strides, {
            1, 2, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 1, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 4.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}

TEST(strided_slice_gpu_f32_i64, test_2x2x2x1x1_2_negative_all) {
    // Input (BFZYX): 2x2x2x1x1
    // Output (BFZYX): 2x1x1x1x1

    auto& engine = get_test_engine();
    auto input = engine.allocate_memory({ data_types::f32, format::bfzyx, { 2, 2, 1, 1, 2 } });
    auto begin = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto end = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });
    auto strides = engine.allocate_memory({ data_types::i64, format::bfyx, { 3, 1, 1, 1 } });

    set_values(input, {
            0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f
    });
    set_values<int64_t>(begin, {
            0, 0, 0
    });
    set_values<int64_t>(end, {
            2, 2, 2
    });
    set_values<int64_t>(strides, {
            1, 2, 2
    });

    topology topology;
    topology.add(input_layout("input", input->get_layout()));
    topology.add(data("input2", begin));
    topology.add(data("input3", end));
    topology.add(data("input4", strides));
    topology.add(strided_slice("strided_slice", "input", "input2", "input3", "input4", {}, {}, {}, {}, tensor{2, 1, 1, 1}));

    network network(engine, topology);

    network.set_input_data("input", input);

    auto outputs = network.execute();

    EXPECT_EQ(outputs.size(), size_t(1));
    EXPECT_EQ(outputs.begin()->first, "strided_slice");

    auto output = outputs.at("strided_slice").get_memory();

    std::vector<float> answers = {
            0.0f, 4.0f
    };

    cldnn::mem_lock<float> output_ptr(output, get_test_stream());

    for (size_t i = 0; i < answers.size(); ++i)
    {
        EXPECT_TRUE(are_equal(answers[i], output_ptr[i]));
    }
}
