from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import unittest

from hypothesis import given
import numpy as np

from caffe2.proto import caffe2_pb2
from caffe2.python import core, workspace
import caffe2.python.hypothesis_test_util as hu
import caffe2.python.serialized_test.serialized_test_util as serial


# TODO(jiayq): make them hypothesis tests for better coverage.
class TestElementwiseBroadcast(serial.SerializedTestCase):
    @given(**hu.gcs)
    def test_broadcast_Add(self, gc, dc):
        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(4, 5).astype(np.float32)
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X + Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(3, 4).astype(np.float32)
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X + Y[:, :, np.newaxis])
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

        # broadcasting the first dimension
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(2).astype(np.float32)
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1, axis=0)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X + Y[:, np.newaxis, np.newaxis, np.newaxis])
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

        # broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(1, 4, 1).astype(np.float32)
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X + Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

    @given(**hu.gcs)
    def test_broadcast_Mul(self, gc, dc):
        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(4, 5).astype(np.float32)
        op = core.CreateOperator("Mul", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X * Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(3, 4).astype(np.float32)
        op = core.CreateOperator("Mul", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X * Y[:, :, np.newaxis])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting the first dimension
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(2).astype(np.float32)
        op = core.CreateOperator("Mul", ["X", "Y"], "out", broadcast=1, axis=0)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X * Y[:, np.newaxis, np.newaxis, np.newaxis])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(1, 4, 1).astype(np.float32)
        op = core.CreateOperator("Mul", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X * Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

    @given(**hu.gcs)
    def test_broadcast_Sub(self, gc, dc):
        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(4, 5).astype(np.float32)
        op = core.CreateOperator("Sub", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X - Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(3, 4).astype(np.float32)
        op = core.CreateOperator("Sub", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X - Y[:, :, np.newaxis])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting the first dimension
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(2).astype(np.float32)
        op = core.CreateOperator("Sub", ["X", "Y"], "out", broadcast=1, axis=0)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X - Y[:, np.newaxis, np.newaxis, np.newaxis])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(1, 4, 1).astype(np.float32)
        op = core.CreateOperator("Sub", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X - Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])
        self.assertGradientChecks(gc, op, [X, Y], 1, [0])

    @serial.given(**hu.gcs)
    def test_broadcast_powt(self, gc, dc):
        np.random.seed(101)

        #operator
        def powt_op(X, Y):
            return [np.power(X, Y)]

        #two gradients Y*X^(Y-1) and X^Y * ln(X)
        def powt_grad(g_out, outputs, fwd_inputs):
            [X, Y] = fwd_inputs
            Z = outputs[0]
            return ([Y * np.power(X, Y - 1), Z * np.log(X)] * g_out)

        #1. Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32) + 1.0
        Y = np.random.rand(4, 5).astype(np.float32) + 2.0

        #two gradients Y*X^(Y-1) and X^Y * ln(X)
        #latter gradient is sumed over 1 and 0 dims to account for broadcast
        def powt_grad_broadcast(g_out, outputs, fwd_inputs):
            [GX, GY] = powt_grad(g_out, outputs, fwd_inputs)
            return ([GX, np.sum(np.sum(GY, 1), 0)])

        op = core.CreateOperator("Pow", ["X", "Y"], "Z", broadcast=1)
        self.assertReferenceChecks(device_option=gc,
                                   op=op,
                                   inputs=[X, Y],
                                   reference=powt_op,
                                   output_to_grad="Z",
                                   grad_reference=powt_grad_broadcast)

        #2. broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float32) + 1.0
        Y = np.random.rand(3, 4).astype(np.float32) + 2.0

        #pow op with the latter array increased by one dim
        def powt_op_axis1(X, Y):
            return powt_op(X, Y[:, :, np.newaxis])

        #two gradients Y*X^(Y-1) and X^Y * ln(X)
        #latter gradient is sumed over 3 and 0 dims to account for broadcast
        def powt_grad_axis1(g_out, outputs, fwd_inputs):
            [X, Y] = fwd_inputs
            [GX, GY] = powt_grad(g_out, outputs, [X, Y[:, :, np.newaxis]])
            return ([GX, np.sum(np.sum(GY, 3), 0)])

        op = core.CreateOperator("Pow", ["X", "Y"], "Z", broadcast=1, axis=1)
        self.assertReferenceChecks(device_option=gc,
                                   op=op,
                                   inputs=[X, Y],
                                   reference=powt_op_axis1,
                                   output_to_grad="Z",
                                   grad_reference=powt_grad_axis1)

        #3. broadcasting the first dimension
        X = np.random.rand(2, 3, 4, 5).astype(np.float32) + 1.0
        Y = np.random.rand(2).astype(np.float32) + 2.0

        #pow op with the latter array increased by one dim
        def powt_op_axis0(X, Y):
            return powt_op(X, Y[:, np.newaxis, np.newaxis, np.newaxis])

        #two gradients Y*X^(Y-1) and X^Y * ln(X)
        #latter gradient is sumed over 3, 2 and 1 dims to account for broadcast
        def powt_grad_axis0(g_out, outputs, fwd_inputs):
            [X, Y] = fwd_inputs
            [GX, GY] = powt_grad(g_out,
                                 outputs,
                                 [X, Y[:, np.newaxis, np.newaxis, np.newaxis]])
            return ([GX, np.sum(np.sum(np.sum(GY, 3), 2), 1)])

        op = core.CreateOperator("Pow", ["X", "Y"], "Z", broadcast=1, axis=0)
        self.assertReferenceChecks(device_option=gc,
                                   op=op,
                                   inputs=[X, Y],
                                   reference=powt_op_axis0,
                                   output_to_grad="Z",
                                   grad_reference=powt_grad_axis0)

        #4. broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float32) + 1.0
        Y = np.random.rand(1, 4, 1).astype(np.float32) + 2.0

        #pow op with the latter array increased by one dim
        def powt_op_mixed(X, Y):
            return powt_op(X, Y[np.newaxis, :, :, :])

        #two gradients Y*X^(Y-1) and X^Y * ln(X)
        #latter gradient is sumed over 0 and 1 dims to account for broadcast
        def powt_grad_mixed(g_out, outputs, fwd_inputs):
            [X, Y] = fwd_inputs
            [GX, GY] = powt_grad(g_out, outputs, [X, Y[np.newaxis, :, :, :]])
            return ([GX, np.reshape(np.sum(np.sum(np.sum(GY, 3), 1), 0),
                                    (1, 4, 1))])

        op = core.CreateOperator("Pow", ["X", "Y"], "Z", broadcast=1, axis=1)
        self.assertReferenceChecks(device_option=gc,
                                   op=op,
                                   inputs=[X, Y],
                                   reference=powt_op_mixed,
                                   output_to_grad="Z",
                                   grad_reference=powt_grad_mixed)

    @given(**hu.gcs)
    def test_broadcast_scalar(self, gc, dc):
        # broadcasting constant
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(1).astype(np.float32)
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X + Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting scalar
        X = np.random.rand(1).astype(np.float32)
        Y = np.random.rand(1).astype(np.float32).reshape([])
        op = core.CreateOperator("Add", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X + Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

    @given(**hu.gcs)
    def test_semantic_broadcast(self, gc, dc):
        # NCHW as default
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(3).astype(np.float32)
        op = core.CreateOperator(
            "Add", ["X", "Y"], "out", broadcast=1, axis_str="C")
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(
            out, X + Y[:, np.newaxis, np.newaxis])
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # NHWC
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(5).astype(np.float32)
        op = core.CreateOperator(
            "Add", ["X", "Y"], "out", broadcast=1, axis_str="C", order="NHWC")
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        np.testing.assert_array_almost_equal(out, X + Y)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

    @given(**hu.gcs)
    def test_sum_reduce_empty_blob(self, gc, dc):
        net = core.Net('test')

        with core.DeviceScope(gc):
            net.GivenTensorFill([], ["X"], values=[], shape=[2, 0, 5])
            net.GivenTensorFill([], ["Y"], values=[], shape=[2, 0])
            net.SumReduceLike(["X", "Y"], "out", axis=0)
            workspace.RunNetOnce(net)

    @given(**hu.gcs)
    def test_sum_reduce(self, gc, dc):
        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(4, 5).astype(np.float32)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        res = np.sum(X, axis=0)
        res = np.sum(res, axis=0)
        np.testing.assert_array_almost_equal(out, res)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(2, 3).astype(np.float32)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1, axis=0)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        res = np.sum(X, axis=3)
        res = np.sum(res, axis=2)
        np.testing.assert_array_almost_equal(out, res, decimal=3)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(3, 4).astype(np.float32)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1, axis=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        res = np.sum(X, axis=0)
        res = np.sum(res, axis=2)
        np.testing.assert_array_almost_equal(out, res)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 500).astype(np.float64)
        Y = np.random.rand(1).astype(np.float64)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        res = np.array(np.sum(X))
        np.testing.assert_array_almost_equal(out, res, decimal=0)

        # broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float32)
        Y = np.random.rand(1, 3, 4, 1).astype(np.float32)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1)
        workspace.FeedBlob("X", X)
        workspace.FeedBlob("Y", Y)
        workspace.RunOperatorOnce(op)
        out = workspace.FetchBlob("out")
        res = np.sum(X, axis=0)
        res = np.sum(res, axis=2).reshape(Y.shape)
        np.testing.assert_array_almost_equal(out, res)
        self.assertDeviceChecks(dc, op, [X, Y], [0])

        # fp64 is not supported with the CUDA op
        dc_cpu_only = [d for d in dc if d.device_type != caffe2_pb2.CUDA]
        self.assertDeviceChecks(dc_cpu_only, op, [X, Y], [0])

    @unittest.skipIf(not workspace.has_gpu_support, "No gpu support")
    @given(**hu.gcs_gpu_only)
    def test_sum_reduce_fp16(self, gc, dc):
        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float16)
        Y = np.random.rand(4, 5).astype(np.float16)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1, device_option=gc)

        def ref_op(X, Y):
            res = np.sum(X, axis=0)
            res = np.sum(res, axis=0)
            return [res]

        self.assertReferenceChecks(
            device_option=gc,
            op=op,
            inputs=[X, Y],
            reference=ref_op,
            threshold=1e-3)

        # Set broadcast and no axis, i.e. broadcasting last dimensions.
        X = np.random.rand(2, 3, 4, 5).astype(np.float16)
        Y = np.random.rand(2, 3).astype(np.float16)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1, axis=0)

        def ref_op(X, Y):
            res = np.sum(X, axis=3)
            res = np.sum(res, axis=2)
            return [res]

        self.assertReferenceChecks(
            device_option=gc,
            op=op,
            inputs=[X, Y],
            reference=ref_op,
            threshold=1e-3)

        # broadcasting intermediate dimensions
        X = np.random.rand(2, 3, 4, 5).astype(np.float16)
        Y = np.random.rand(3, 4).astype(np.float16)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1, axis=1)

        def ref_op(X, Y):
            res = np.sum(X, axis=0)
            res = np.sum(res, axis=2)
            return [res]

        self.assertReferenceChecks(
            device_option=gc,
            op=op,
            inputs=[X, Y],
            reference=ref_op,
            threshold=1e-3)

        # broadcasting with single elem dimensions at both ends
        X = np.random.rand(2, 3, 4, 5).astype(np.float16)
        Y = np.random.rand(1, 3, 4, 1).astype(np.float16)
        op = core.CreateOperator(
            "SumReduceLike", ["X", "Y"], "out", broadcast=1)

        def ref_op(X, Y):
            res = np.sum(X, axis=0)
            res = np.sum(res, axis=2)
            return [res.reshape(Y.shape)]

        self.assertReferenceChecks(
            device_option=gc,
            op=op,
            inputs=[X, Y],
            reference=ref_op,
            threshold=1e-3)

if __name__ == "__main__":
    unittest.main()

[(19, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (70, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (121, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (172, 'caffe2.python.serialized_test.serialized_test_util.given', 'serial.given', True, 'import caffe2.python.serialized_test.serialized_test_util as serial\n'), (276, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (302, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (329, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (339, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (413, 'unittest.skipIf', 'unittest.skipIf', False, 'import unittest\n'), (414, 'hypothesis.given', 'given', False, 'from hypothesis import given\n'), (489, 'unittest.main', 'unittest.main', False, 'import unittest\n'), (24, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (25, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (26, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (27, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (28, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (29, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (36, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (37, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (38, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (39, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (40, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (41, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (48, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (49, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (50, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (51, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (52, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (53, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (61, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (62, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (63, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (64, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (65, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (66, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (75, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (76, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (77, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (78, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (79, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (80, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (87, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (88, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (89, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (90, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (91, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (92, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (99, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (100, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (101, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (102, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (103, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (104, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (112, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (113, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (114, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (115, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (116, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (117, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (126, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (127, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (128, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (129, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (130, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (131, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (138, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (139, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (140, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (141, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (142, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (143, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (150, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (151, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (152, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (153, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (154, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (155, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (163, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (164, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (165, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (166, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (167, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (168, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (174, 'numpy.random.seed', 'np.random.seed', True, 'import numpy as np\n'), (196, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (219, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (244, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (268, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (281, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (282, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (283, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (284, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (285, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (286, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (293, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (294, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (295, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (296, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (297, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (298, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (307, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (309, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (310, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (311, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (312, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (313, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (320, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (322, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (323, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (324, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (325, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (326, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (331, 'caffe2.python.core.Net', 'core.Net', False, 'from caffe2.python import core, workspace\n'), (344, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (346, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (347, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (348, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (349, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (350, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (351, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (352, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (358, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (360, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (361, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (362, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (363, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (364, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (365, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (366, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (372, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (374, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (375, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (376, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (377, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (378, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (379, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (380, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (386, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (388, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (389, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (390, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (391, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (393, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (398, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (400, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (401, 'caffe2.python.workspace.FeedBlob', 'workspace.FeedBlob', False, 'from caffe2.python import core, workspace\n'), (402, 'caffe2.python.workspace.RunOperatorOnce', 'workspace.RunOperatorOnce', False, 'from caffe2.python import core, workspace\n'), (403, 'caffe2.python.workspace.FetchBlob', 'workspace.FetchBlob', False, 'from caffe2.python import core, workspace\n'), (404, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (406, 'numpy.testing.assert_array_almost_equal', 'np.testing.assert_array_almost_equal', True, 'import numpy as np\n'), (419, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (437, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (455, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (473, 'caffe2.python.core.CreateOperator', 'core.CreateOperator', False, 'from caffe2.python import core, workspace\n'), (333, 'caffe2.python.core.DeviceScope', 'core.DeviceScope', False, 'from caffe2.python import core, workspace\n'), (337, 'caffe2.python.workspace.RunNetOnce', 'workspace.RunNetOnce', False, 'from caffe2.python import core, workspace\n'), (392, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (423, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (424, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (441, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (442, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (459, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (460, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (477, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (478, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (22, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (23, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (34, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (35, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (46, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (47, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (59, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (60, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (73, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (74, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (85, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (86, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (97, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (98, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (110, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (111, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (124, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (125, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (136, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (137, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (148, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (149, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (161, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (162, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (178, 'numpy.power', 'np.power', True, 'import numpy as np\n'), (279, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (280, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (291, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (305, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (306, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (318, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (319, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (342, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (343, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (356, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (357, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (370, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (371, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (384, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (385, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (396, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (397, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (405, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (417, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (418, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (435, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (436, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (453, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (454, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (471, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (472, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (187, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (188, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (194, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (205, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (206, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (217, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (228, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (229, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (253, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (254, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (184, 'numpy.power', 'np.power', True, 'import numpy as np\n'), (184, 'numpy.log', 'np.log', True, 'import numpy as np\n'), (242, 'numpy.sum', 'np.sum', True, 'import numpy as np\n'), (292, 'numpy.random.rand', 'np.random.rand', True, 'import numpy as np\n'), (265, 'numpy.sum', 'np.sum', True, 'import numpy as np\n')]