TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL(
  Kokkos_View_Fad, MultiplyMixed, FadType, Layout, Device )
{
  typedef typename ApplyView<FadType*,Layout,Device>::type ViewType;
  typedef typename ViewType::size_type size_type;
  typedef typename ViewType::HostMirror host_view_type;

  const size_type num_rows = 2;
  const size_type fad_size = global_fad_size;

  // Create and fill views -- do everything on the host for this test
  FadType f0 = generate_fad<FadType>(
    num_rows, size_type(2), fad_size, size_type(0), size_type(0));
  FadType f1 = generate_fad<FadType>(
    num_rows, size_type(2), fad_size, size_type(1), size_type(0));
  host_view_type h_v("view1", num_rows, fad_size+1);
  h_v(0) = f0;
  h_v(1) = f1;

  FadType f2 = f0 * h_v(1);

  // Check
  FadType f3 = f0 * f1;
  success = checkFads(f3, f2, out);
}
bool
checkConstantVectorView(const ViewType& v,
                        const typename ViewType::value_type& v_expected,
                        Teuchos::FancyOStream& out) {
  typedef ViewType view_type;
  typedef typename view_type::size_type size_type;
  typedef typename view_type::HostMirror host_view_type;
  typedef typename host_view_type::array_type::value_type scalar_type;

  // Copy to host
  host_view_type h_v = Kokkos::create_mirror_view(v);
  Kokkos::deep_copy(h_v, v);

  const size_type num_rows = h_v.dimension_0();
  const size_type num_cols = Kokkos::dimension_scalar(h_v);
  bool success = true;
  for (size_type i=0; i<num_rows; ++i) {
    for (size_type j=0; j<num_cols; ++j) {
      scalar_type val = h_v(i).fastAccessCoeff(j);
      scalar_type val_expected = v_expected.fastAccessCoeff(j);
      TEUCHOS_TEST_EQUALITY(val, val_expected, out, success);
    }
  }

  return success;
}
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL(
  Kokkos_View_Fad, DeepCopy, FadType, Layout, Device )
{
  typedef typename ApplyView<FadType**,Layout,Device>::type ViewType;
  typedef typename ViewType::size_type size_type;
  typedef typename ViewType::HostMirror host_view_type;

  const size_type num_rows = global_num_rows;
  const size_type num_cols = global_num_cols;
  const size_type fad_size = global_fad_size;

  // Create and fill view
  ViewType v("view", num_rows, num_cols, fad_size+1);
  host_view_type h_v = Kokkos::create_mirror_view(v);
  for (size_type i=0; i<num_rows; ++i)
    for (size_type j=0; j<num_cols; ++j)
      h_v(i,j) = generate_fad<FadType>(num_rows, num_cols, fad_size, i, j);
  Kokkos::deep_copy(v, h_v);

  // Copy back
  host_view_type h_v2 = Kokkos::create_mirror_view(v);
  Kokkos::deep_copy(h_v2, v);

  // Check
  success = true;
  for (size_type i=0; i<num_rows; ++i) {
    for (size_type j=0; j<num_cols; ++j) {
      FadType f = generate_fad<FadType>(num_rows, num_cols, fad_size, i, j);
      success = success && checkFads(f, h_v2(i,j), out);
    }
  }
}
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL(
  Kokkos_View_Fad, UnmanagedConst, FadType, Layout, Device )
{
  typedef typename FadType::value_type scalar_type;
  typedef typename ApplyView<scalar_type***,Layout,Device>::type ViewType;
  typedef typename ApplyView<const scalar_type***,Layout,Device>::type ConstViewType;
  typedef typename ApplyView<FadType**,Layout,Device,Kokkos::MemoryUnmanaged>::type FadViewType;
  typedef typename ApplyView<const FadType**,Layout,Device,Kokkos::MemoryUnmanaged>::type ConstFadViewType;
  typedef typename ViewType::size_type size_type;
  typedef typename ViewType::HostMirror host_view_type;
  typedef typename FadViewType::HostMirror fad_host_view_type;

  const size_type num_rows = global_num_rows;
  const size_type num_cols = global_num_cols;
  const size_type fad_size = global_fad_size;

  // Create and fill view
  ViewType v("view", num_rows, num_cols, fad_size+1);
  host_view_type h_v = Kokkos::create_mirror_view(v);
  for (size_type i=0; i<num_rows; ++i) {
    for (size_type j=0; j<num_cols; ++j) {
      FadType f = generate_fad<FadType>(num_rows, num_cols, fad_size, i, j);
      for (size_type k=0; k<fad_size; k++)
        h_v(i,j,k) = f.dx(k);
      h_v(i,j,fad_size) = f.val();
    }
  }
  Kokkos::deep_copy(v, h_v);
  ConstViewType v_const = v;

  // Create unmanaged view
  ConstFadViewType v_fad(
    v_const.ptr_on_device(), num_rows, num_cols, fad_size+1);

  // Copy back -- can't use create_mirror_view() because v_fad is unmanaged
  fad_host_view_type h_v_fad("host_view_fad", num_rows, num_cols, fad_size+1);
  Kokkos::deep_copy(h_v_fad, v_fad);

  // Check
  success = true;
  for (size_type i=0; i<num_rows; ++i) {
    for (size_type j=0; j<num_cols; ++j) {
      FadType f = generate_fad<FadType>(num_rows, num_cols, fad_size, i, j);
      success = success && checkFads(f, h_v_fad(i,j), out);
    }
  }
}
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL(
  Kokkos_View_Fad, Rank8, FadType, Layout, Device )
{
  typedef typename ApplyView<FadType*******,Layout,Device>::type ViewType;
  typedef typename ViewType::size_type size_type;
  typedef typename ViewType::HostMirror host_view_type;

  const size_type fad_size = global_fad_size;

  // Create and fill view
  ViewType v("view", 100, 1, 2, 3, 4, 5, 6, fad_size+1);
  host_view_type h_v = Kokkos::create_mirror_view(v);
  typename host_view_type::array_type h_a = h_v;
  Kokkos::deep_copy(h_a, 1.0);

  FadType f1 = FadType(fad_size, 2.0);
  h_v(99,0,1,2,3,4,5) = f1;
  FadType f2 = h_v(99,0,1,2,3,4,5);

  // Check
  success = checkFads(f1, f2, out);
}
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL(
  Kokkos_View_Fad, Subview, FadType, Layout, Device )
{
  typedef typename ApplyView<FadType**,Layout,Device>::type ViewType;
  typedef typename ViewType::size_type size_type;
  typedef typename ViewType::HostMirror host_view_type;

  const size_type num_rows = global_num_rows;
  const size_type num_cols = global_num_cols;
  const size_type fad_size = global_fad_size;

  // Create and fill view
  ViewType v("view", num_rows, num_cols, fad_size+1);
  host_view_type h_v = Kokkos::create_mirror_view(v);
  for (size_type i=0; i<num_rows; ++i) {
    for (size_type j=0; j<num_cols; ++j) {
      FadType f = generate_fad<FadType>(num_rows, num_cols, fad_size, i, j);
      h_v(i,j) = f;
    }
  }
  Kokkos::deep_copy(v, h_v);

  // Create subview of first column
  size_type col = 1;
  auto s = Kokkos::subview(v, Kokkos::ALL(), col);

  // Copy back
  typedef decltype(s) SubviewType;
  typedef typename SubviewType::HostMirror HostSubviewType;
  HostSubviewType h_s = Kokkos::create_mirror_view(s);
  Kokkos::deep_copy(h_s, s);

  // Check
  success = true;
#if defined(HAVE_SACADO_VIEW_SPEC) && !defined(SACADO_DISABLE_FAD_VIEW_SPEC)
  TEUCHOS_TEST_EQUALITY(Kokkos::dimension_scalar(s), fad_size+1, out, success);
  TEUCHOS_TEST_EQUALITY(Kokkos::dimension_scalar(h_s), fad_size+1, out, success);
#endif
  for (size_type i=0; i<num_rows; ++i) {
    FadType f = generate_fad<FadType>(num_rows, num_cols, fad_size, i, col);
    success = success && checkFads(f, h_s(i), out);
  }
}
TEST_P(BroxOpticalFlow, Regression)
{
    cv::Mat frame0 = readImageType("opticalflow/frame0.png", CV_32FC1);
    ASSERT_FALSE(frame0.empty());

    cv::Mat frame1 = readImageType("opticalflow/frame1.png", CV_32FC1);
    ASSERT_FALSE(frame1.empty());

    cv::gpu::BroxOpticalFlow brox(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/,
                                  10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/);

    cv::gpu::GpuMat u;
    cv::gpu::GpuMat v;
    brox(loadMat(frame0), loadMat(frame1), u, v);

#ifndef DUMP
    std::string fname(cvtest::TS::ptr()->get_data_path());
    if (devInfo.majorVersion() >= 2)
        fname += BROX_OPTICAL_FLOW_DUMP_FILE_CC20;
    else
        fname += BROX_OPTICAL_FLOW_DUMP_FILE;

    std::ifstream f(fname.c_str(), std::ios_base::binary);

    int rows, cols;

    f.read((char*)&rows, sizeof(rows));
    f.read((char*)&cols, sizeof(cols));

    cv::Mat u_gold(rows, cols, CV_32FC1);

    for (int i = 0; i < u_gold.rows; ++i)
        f.read(u_gold.ptr<char>(i), u_gold.cols * sizeof(float));

    cv::Mat v_gold(rows, cols, CV_32FC1);

    for (int i = 0; i < v_gold.rows; ++i)
        f.read(v_gold.ptr<char>(i), v_gold.cols * sizeof(float));

    EXPECT_MAT_NEAR(u_gold, u, 0);
    EXPECT_MAT_NEAR(v_gold, v, 0);
#else
    std::string fname(cvtest::TS::ptr()->get_data_path());
    if (devInfo.majorVersion() >= 2)
        fname += BROX_OPTICAL_FLOW_DUMP_FILE_CC20;
    else
        fname += BROX_OPTICAL_FLOW_DUMP_FILE;

    std::ofstream f(fname.c_str(), std::ios_base::binary);

    f.write((char*)&u.rows, sizeof(u.rows));
    f.write((char*)&u.cols, sizeof(u.cols));

    cv::Mat h_u(u);
    cv::Mat h_v(v);

    for (int i = 0; i < u.rows; ++i)
        f.write(h_u.ptr<char>(i), u.cols * sizeof(float));

    for (int i = 0; i < v.rows; ++i)
        f.write(h_v.ptr<char>(i), v.cols * sizeof(float));

#endif
}