matMulGradient :: Test
matMulGradient = testCase "matMulGradients" $ do

  let dfBuild = do
        x <- TF.render $ TF.zeros $ TF.Shape [3, 1 :: Int64]
        w <- TF.zeroInitializedVariable $ TF.Shape [1, 2 :: Int64]
        let f = x `TF.matMul` TF.readValue w :: TF.Tensor TF.Build Float
        dfs <- TF.gradients f [x]
        return (x, dfs)

  (xShape, dxShape) <- TF.runSession $ do
    (x, [dx]) <- TF.build dfBuild
    TF.run (TF.shape x, TF.shape dx)

  assertEqual "Shape of gradient must match shape of input" xShape (dxShape :: V.Vector Int32)


-- test that gradient of matMul can be taken gradient of
matMulGradient :: Test
matMulGradient = testCase "matMulGradients" $ do

  let dfBuild = do
        x <- TF.render $ TF.zeros $ TF.Shape [3, 1 :: Int64]
        w <- TF.zeroInitializedVariable $ TF.Shape [1, 2 :: Int64]
        let f = x `TF.matMul` TF.readValue w :: TF.Tensor TF.Build Float
        dfs <- TF.gradients f [x]
        return (x, dfs)

  (xShape, dxShape) <- TF.runSession $ do
    (x, [dx]) <- TF.build dfBuild
    TF.run (TF.shape x, TF.shape dx)

  assertEqual "Shape of gradient must match shape of input" xShape (dxShape :: V.Vector Int32)


-- test that gradient of matMul can be taken gradient of
matMulGradient = testCase "matMulGradients" $ do

  let dfBuild = do
        x <- TF.render $ TF.zeros $ TF.Shape [3, 1 :: Int64]
        w <- TF.zeroInitializedVariable $ TF.Shape [1, 2 :: Int64]
        let f = x `TF.matMul` TF.readValue w :: TF.Tensor TF.Build Float
        dfs <- TF.gradients f [x]
        return (x, dfs)

  (xShape, dxShape) <- TF.runSession $ do
    (x, [dx]) <- TF.build dfBuild
    TF.run (TF.shape x, TF.shape dx)

  assertEqual "Shape of gradient must match shape of input" xShape (dxShape :: V.Vector Int32)


-- test that gradient of matMul can be taken gradient of