util.cpp 10.2 KB
Newer Older
Robert Kimball's avatar
Robert Kimball committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// ----------------------------------------------------------------------------

#include <sstream>
16 17
#include <string>
#include <vector>
Robert Kimball's avatar
Robert Kimball committed
18 19 20

#include "gtest/gtest.h"

Robert Kimball's avatar
Robert Kimball committed
21
#include "ngraph/function.hpp"
varun-intel's avatar
varun-intel committed
22
#include "ngraph/graph_util.hpp"
23
#include "ngraph/ngraph.hpp"
24
#include "util/all_close.hpp"
25
#include "util/ndarray.hpp"
Robert Kimball's avatar
Robert Kimball committed
26 27

using namespace std;
28
using namespace ngraph;
Robert Kimball's avatar
Robert Kimball committed
29 30 31 32 33

TEST(util, split)
{
    {
        string s1 = "this,is,a,test";
34
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
35 36 37 38 39 40 41 42 43
        ASSERT_EQ(4, r1.size());
        EXPECT_STRCASEEQ("this", r1[0].c_str());
        EXPECT_STRCASEEQ("is", r1[1].c_str());
        EXPECT_STRCASEEQ("a", r1[2].c_str());
        EXPECT_STRCASEEQ("test", r1[3].c_str());
    }

    {
        string s1 = "this,is,a,test,";
44
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
45 46 47 48 49 50 51 52 53 54
        ASSERT_EQ(5, r1.size());
        EXPECT_STRCASEEQ("this", r1[0].c_str());
        EXPECT_STRCASEEQ("is", r1[1].c_str());
        EXPECT_STRCASEEQ("a", r1[2].c_str());
        EXPECT_STRCASEEQ("test", r1[3].c_str());
        EXPECT_STRCASEEQ("", r1[4].c_str());
    }

    {
        string s1 = ",this,is,a,test";
55
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
56 57 58 59 60 61 62 63 64 65
        ASSERT_EQ(5, r1.size());
        EXPECT_STRCASEEQ("", r1[0].c_str());
        EXPECT_STRCASEEQ("this", r1[1].c_str());
        EXPECT_STRCASEEQ("is", r1[2].c_str());
        EXPECT_STRCASEEQ("a", r1[3].c_str());
        EXPECT_STRCASEEQ("test", r1[4].c_str());
    }

    {
        string s1 = "this,,is,a,test";
66
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
67 68 69 70 71 72 73 74 75 76
        ASSERT_EQ(5, r1.size());
        EXPECT_STRCASEEQ("this", r1[0].c_str());
        EXPECT_STRCASEEQ("", r1[1].c_str());
        EXPECT_STRCASEEQ("is", r1[2].c_str());
        EXPECT_STRCASEEQ("a", r1[3].c_str());
        EXPECT_STRCASEEQ("test", r1[4].c_str());
    }

    {
        string s1 = "this";
77
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
78 79 80 81 82 83
        ASSERT_EQ(1, r1.size());
        EXPECT_STRCASEEQ("this", r1[0].c_str());
    }

    {
        string s1 = "";
84
        auto r1 = split(s1, ',');
Robert Kimball's avatar
Robert Kimball committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        ASSERT_EQ(1, r1.size());
        EXPECT_STRCASEEQ("", r1[0].c_str());
    }
}

TEST(DISABLED_util, dump)
{
    string text = "this is a text string used to test the dump function.";

    dump(cout, text.data(), text.size());
}

TEST(util, stopwatch)
{
    stopwatch t1;

    t1.start();
    usleep(1000);
    t1.stop();

    t1.start();
    usleep(1000);
    t1.stop();

    t1.start();
    usleep(1000);
    t1.stop();

    EXPECT_EQ(3, t1.get_call_count());

    EXPECT_GT(t1.get_total_microseconds(), t1.get_microseconds());
}

TEST(util, trim)
{
    EXPECT_STREQ("test", trim("test").c_str());
    EXPECT_STREQ("test", trim(" test").c_str());
    EXPECT_STREQ("test", trim("test ").c_str());
    EXPECT_STREQ("test", trim(" test ").c_str());
    EXPECT_STREQ("test", trim("           test            ").c_str());
    EXPECT_STREQ("test", trim("\ttest").c_str());
    EXPECT_STREQ("test", trim("test\t").c_str());
    EXPECT_STREQ("test", trim("\ttest\t").c_str());
    EXPECT_STREQ("test", trim(" \t test \t ").c_str());
}

TEST(util, contains)
{
    vector<int> v1 = {1, 2, 3, 4, 5, 6};

    EXPECT_TRUE(contains(v1, 1));
    EXPECT_TRUE(contains(v1, 4));
    EXPECT_TRUE(contains(v1, 6));
    EXPECT_FALSE(contains(v1, 8));
}

141 142 143
TEST(util, remove_from)
{
}
Robert Kimball's avatar
Robert Kimball committed
144 145 146 147 148

TEST(util, reduce)
{
    {
        std::vector<size_t> x = {};
149
        size_t actual =
Robert Kimball's avatar
Robert Kimball committed
150 151 152 153 154
            ngraph::reduce(x.begin(), x.end(), [](size_t a, size_t b) { return a + b; });
        EXPECT_EQ(actual, 0);
    }
    {
        std::vector<size_t> x = {10};
155
        size_t actual =
Robert Kimball's avatar
Robert Kimball committed
156 157 158 159 160
            ngraph::reduce(x.begin(), x.end(), [](size_t a, size_t b) { return a + b; });
        EXPECT_EQ(actual, 10);
    }
    {
        std::vector<size_t> x = {1, 2, 3, 4, 5, 6};
161
        size_t actual =
Robert Kimball's avatar
Robert Kimball committed
162 163 164 165
            ngraph::reduce(x.begin(), x.end(), [](size_t a, size_t b) { return a + b; });
        EXPECT_EQ(actual, 21);
    }
    {
166 167
        std::vector<size_t> x = {1, 2, 3, 4, 5, 6};
        size_t actual = ngraph::reduce(x.begin(), x.end(), ngraph::plus<size_t>);
Robert Kimball's avatar
Robert Kimball committed
168 169 170
        EXPECT_EQ(actual, 21);
    }
    {
171 172
        std::vector<size_t> x = {1, 2, 3, 4, 5, 6};
        size_t actual = ngraph::reduce(x.begin(), x.end(), ngraph::mul<size_t>);
Robert Kimball's avatar
Robert Kimball committed
173 174 175
        EXPECT_EQ(actual, 720);
    }
}
176 177 178

TEST(util, all_close)
{
179
    auto manager = runtime::Manager::get("INTERPRETER");
180 181 182
    auto backend = manager->allocate_backend();

    // Create some tensors for input/output
183 184
    auto a = backend->make_primary_tensor_view(element::f32, Shape{2, 3});
    auto b = backend->make_primary_tensor_view(element::f32, Shape{2, 3});
Robert Kimball's avatar
Robert Kimball committed
185

186 187
    copy_data(a, test::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}).get_vector());
    copy_data(b, test::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}).get_vector());
188

189
    EXPECT_TRUE(ngraph::test::all_close<float>(a, b));
190

191
    auto c = backend->make_primary_tensor_view(element::f32, Shape{2, 3});
192
    copy_data(c, test::NDArray<float, 2>({{1.1f, 2, 3}, {3, 4, 5}}).get_vector());
Robert Kimball's avatar
Robert Kimball committed
193

194 195
    EXPECT_FALSE(ngraph::test::all_close<float>(c, a, 0, .05f));
    EXPECT_TRUE(ngraph::test::all_close<float>(c, a, 0, .11f));
196

197 198
    EXPECT_FALSE(ngraph::test::all_close<float>(c, a, .05f, 0));
    EXPECT_TRUE(ngraph::test::all_close<float>(c, a, .11f, 0));
199
}
Robert Kimball's avatar
Robert Kimball committed
200 201 202 203 204

TEST(util, traverse_functions)
{
    // First create "f(A,B,C) = (A+B)*C".
    auto shape = Shape{2, 2};
205 206 207
    auto A = make_shared<op::Parameter>(element::f32, shape);
    auto B = make_shared<op::Parameter>(element::f32, shape);
    auto C = make_shared<op::Parameter>(element::f32, shape);
208
    auto f = make_shared<Function>((A + B) * C, op::Parameters{A, B, C}, "f");
Robert Kimball's avatar
Robert Kimball committed
209 210

    // Now make "g(X,Y,Z) = f(X,Y,Z) + f(X,Y,Z)"
211 212 213
    auto X = make_shared<op::Parameter>(element::f32, shape);
    auto Y = make_shared<op::Parameter>(element::f32, shape);
    auto Z = make_shared<op::Parameter>(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
214 215 216 217 218 219
    auto g = make_shared<Function>(make_shared<op::FunctionCall>(f, Nodes{X, Y, Z}) +
                                       make_shared<op::FunctionCall>(f, Nodes{X, Y, Z}),
                                   op::Parameters{X, Y, Z},
                                   "g");

    // Now make "h(X,Y,Z) = g(X,Y,Z) + g(X,Y,Z)"
220 221 222
    auto X1 = make_shared<op::Parameter>(element::f32, shape);
    auto Y1 = make_shared<op::Parameter>(element::f32, shape);
    auto Z1 = make_shared<op::Parameter>(element::f32, shape);
Robert Kimball's avatar
Robert Kimball committed
223 224 225 226 227 228 229 230 231
    auto h = make_shared<Function>(make_shared<op::FunctionCall>(g, Nodes{X1, Y1, Z1}) +
                                       make_shared<op::FunctionCall>(g, Nodes{X1, Y1, Z1}),
                                   op::Parameters{X1, Y1, Z1},
                                   "h");

    vector<Function*> functions;
    traverse_functions(h, [&](shared_ptr<Function> fp) { functions.push_back(fp.get()); });
    ASSERT_EQ(3, functions.size());
}
232 233 234 235 236 237

class CloneTest : public ::testing::Test
{
public:
    // (A + B) * C
    Shape shape = Shape{2, 2};
238 239 240
    std::shared_ptr<op::Parameter> A = make_shared<op::Parameter>(element::f32, shape);
    std::shared_ptr<op::Parameter> B = make_shared<op::Parameter>(element::f32, shape);
    std::shared_ptr<op::Parameter> C = make_shared<op::Parameter>(element::f32, shape);
241 242 243 244 245 246
    std::shared_ptr<Node> AplusB = A + B;
    std::shared_ptr<Node> AplusBtimesC = AplusB * C;

    NodeMap node_map;
    std::list<std::shared_ptr<ngraph::Node>> nodes;
    std::shared_ptr<Function> func =
247
        make_shared<Function>(AplusBtimesC, op::Parameters{A, B, C}, "f");
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

    void SetUp()
    {
        nodes.push_back(AplusBtimesC);
        nodes.push_back(AplusB);
        nodes.push_back(A);
        nodes.push_back(B);
        nodes.push_back(C);
    }

    bool CompareNodes(const std::list<std::shared_ptr<ngraph::Node>>& orig,
                      const std::list<std::shared_ptr<ngraph::Node>>& clone,
                      const NodeMap& nm)
    {
        if (orig.size() != clone.size())
        {
            return false;
        }
        auto origit = orig.begin();
        auto cloneit = clone.begin();
        while (origit != orig.end() && cloneit != clone.end())
        {
varun-intel's avatar
varun-intel committed
270
            if (*cloneit != nm.get_node_map().at(*origit))
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
            {
                return false;
            }
            ++origit;
            ++cloneit;
        }
        return true;
    }
};

TEST_F(CloneTest, clone_nodes_full)
{
    auto cloned_nodes = clone_nodes(nodes, node_map);
    ASSERT_TRUE(CompareNodes(nodes, cloned_nodes, node_map));

varun-intel's avatar
varun-intel committed
286 287 288 289 290
    ASSERT_NE(nullptr, std::dynamic_pointer_cast<op::Parameter>(node_map.get(A)));
    ASSERT_NE(nullptr, std::dynamic_pointer_cast<op::Parameter>(node_map.get(B)));
    ASSERT_NE(nullptr, std::dynamic_pointer_cast<op::Parameter>(node_map.get(C)));
    ASSERT_NE(nullptr, std::dynamic_pointer_cast<op::Add>(node_map.get(AplusB)));
    ASSERT_NE(nullptr, std::dynamic_pointer_cast<op::Multiply>(node_map.get(AplusBtimesC)));
291 292 293 294 295 296 297 298 299

    auto sorted_nodes = topological_sort(nodes);
    auto sorted_cloned_nodes = topological_sort(cloned_nodes);
    ASSERT_TRUE(CompareNodes(sorted_nodes, sorted_cloned_nodes, node_map));
}

TEST_F(CloneTest, clone_nodes_partial)
{
    // map A -> A' prior to clone
300
    auto Aprime = make_shared<op::Parameter>(element::f32, shape);
varun-intel's avatar
varun-intel committed
301
    node_map.add(A, Aprime);
302 303 304 305 306

    auto cloned_nodes = clone_nodes(nodes, node_map);
    ASSERT_TRUE(CompareNodes(nodes, cloned_nodes, node_map));

    // ensure A -> A' after clone
varun-intel's avatar
varun-intel committed
307
    ASSERT_EQ(Aprime, node_map.get(A));
308 309 310 311 312 313 314
}

TEST_F(CloneTest, clone_function_full)
{
    auto cloned_func = clone_function(func, node_map);
    ASSERT_TRUE(CompareNodes(func->get_ops(), cloned_func->get_ops(), node_map));
}
315 316 317 318 319 320 321 322 323 324

TEST(util, round_up)
{
    EXPECT_EQ(0, round_up(0, 4));
    EXPECT_EQ(4, round_up(1, 4));
    EXPECT_EQ(4, round_up(2, 4));
    EXPECT_EQ(4, round_up(3, 4));
    EXPECT_EQ(4, round_up(4, 4));
    EXPECT_EQ(8, round_up(5, 4));
}