<commit_before>/**
 * @file
 */
#include "Compiler.hpp"

#include "bi/birch.hpp"
#include "bi/lexer.hpp"
#include "bi/visitor/all.hpp"
#include "bi/io/bih_ostream.hpp"
#include "bi/io/cpp/CppBaseGenerator.hpp"
#include "bi/io/cpp/CppPackageGenerator.hpp"

bi::Compiler* compiler = nullptr;
std::stringstream raw;

bi::Compiler::Compiler(Package* package, const std::string& mode,
    const std::string& unit) :
    scope(new Scope(GLOBAL_SCOPE)),
    package(package),
    mode(mode),
    unit(unit) {
  //
}

void bi::Compiler::parse(bool includeHeaders) {
  compiler = this;  // set global variable needed by parser for callbacks
  auto files = package->sources;
  if (includeHeaders) {
    files = package->files;
  }
  for (auto file : files) {
    raw.str("");
    auto fd = fopen(file->path.c_str(), "r");
    if (!fd) {
      throw FileNotFoundException(file->path);
    }
    this->file = file;  // member variable needed by GNU Bison parser
    yyrestart(fd);
    yyreset();
    try {
      yyparse();
    } catch (bi::Exception& e) {
      yyerror(e.msg.c_str());
    }
    yylex_destroy();
    fclose(fd);
    this->file = nullptr;
  }
  compiler = nullptr;
}

void bi::Compiler::resolve() {
  Spinner spinner;
  package->accept(&spinner);

  Transformer transformer;
  package->accept(&transformer);

  Checker checker;
  package->accept(&checker);

  Scoper scoper;
  package->accept(&scoper);

  Baser baser;
  package->accept(&baser);

  Resolver resolver;
  package->accept(&resolver);
}

void bi::Compiler::gen() {
  std::stringstream stream;
  std::string internalName = tarname(package->name);
  fs::path path = fs::path("src") / ("birch_" + internalName);

  bih_ostream bihOutput(stream);
  CppPackageGenerator hppOutput(stream, 0, true, mode == "test");
  CppBaseGenerator cppOutput(stream, 0, false, false, mode == "test");

  /* single *.bih header for whole package */
  stream.str("");
  bihOutput << package;
  path.replace_extension(".bih");
  write_all_if_different(path, stream.str());

  /* single *.hpp header for whole package */
  stream.str("");
  hppOutput << package;
  path.replace_extension(".hpp");
  write_all_if_different(path, stream.str());

  if (unit == "unity") {
    /* sources go into one *.cpp file for the whole package */
    stream.str("");
    for (auto file : package->sources) {
      cppOutput << file;
    }
    path.replace_extension(".cpp");
    write_all_if_different(path, stream.str());
  } else if (unit == "file") {
    /* sources go into one *.cpp file for each *.bi file */
    for (auto file : package->sources) {
      stream.str("");
      cppOutput << file;
      path = fs::path("src") / file->path;
      path.replace_extension(".cpp");
      write_all_if_different(path, stream.str());
    }
  } else {
    /* sources go into one *.cpp file for each directory */
    std::unordered_map<std::string,std::string> sources;
    for (auto file : package->sources) {
      auto dir = fs::path(file->path).parent_path().string();
      auto iter = sources.find(dir);
      if (iter == sources.end()) {
        iter = sources.insert(std::make_pair(dir, std::string(""))).first;
      }
      stream.str("");
      cppOutput << file;
      iter->second += stream.str();
    }
    for (auto pair : sources) {
      path = fs::path("src") / pair.first / ("birch_" + internalName);
      path.replace_extension(".cpp");
      write_all_if_different(path, pair.second);
    }
  }
}

void bi::Compiler::setRoot(Statement* root) {
  this->file->root = root;
}
<commit_msg>Standardized tar name.<commit_after>/**
 * @file
 */
#include "Compiler.hpp"

#include "bi/birch.hpp"
#include "bi/lexer.hpp"
#include "bi/visitor/all.hpp"
#include "bi/io/bih_ostream.hpp"
#include "bi/io/cpp/CppBaseGenerator.hpp"
#include "bi/io/cpp/CppPackageGenerator.hpp"

bi::Compiler* compiler = nullptr;
std::stringstream raw;

bi::Compiler::Compiler(Package* package, const std::string& mode,
    const std::string& unit) :
    scope(new Scope(GLOBAL_SCOPE)),
    package(package),
    mode(mode),
    unit(unit) {
  //
}

void bi::Compiler::parse(bool includeHeaders) {
  compiler = this;  // set global variable needed by parser for callbacks
  auto files = package->sources;
  if (includeHeaders) {
    files = package->files;
  }
  for (auto file : files) {
    raw.str("");
    auto fd = fopen(file->path.c_str(), "r");
    if (!fd) {
      throw FileNotFoundException(file->path);
    }
    this->file = file;  // member variable needed by GNU Bison parser
    yyrestart(fd);
    yyreset();
    try {
      yyparse();
    } catch (bi::Exception& e) {
      yyerror(e.msg.c_str());
    }
    yylex_destroy();
    fclose(fd);
    this->file = nullptr;
  }
  compiler = nullptr;
}

void bi::Compiler::resolve() {
  Spinner spinner;
  package->accept(&spinner);

  Transformer transformer;
  package->accept(&transformer);

  Checker checker;
  package->accept(&checker);

  Scoper scoper;
  package->accept(&scoper);

  Baser baser;
  package->accept(&baser);

  Resolver resolver;
  package->accept(&resolver);
}

void bi::Compiler::gen() {
  std::stringstream stream;
  std::string internalName = tarname(package->name);
  fs::path path = fs::path("src") / internalName;

  bih_ostream bihOutput(stream);
  CppPackageGenerator hppOutput(stream, 0, true, mode == "test");
  CppBaseGenerator cppOutput(stream, 0, false, false, mode == "test");

  /* single *.bih header for whole package */
  stream.str("");
  bihOutput << package;
  path.replace_extension(".bih");
  write_all_if_different(path, stream.str());

  /* single *.hpp header for whole package */
  stream.str("");
  hppOutput << package;
  path.replace_extension(".hpp");
  write_all_if_different(path, stream.str());

  if (unit == "unity") {
    /* sources go into one *.cpp file for the whole package */
    stream.str("");
    for (auto file : package->sources) {
      cppOutput << file;
    }
    path.replace_extension(".cpp");
    write_all_if_different(path, stream.str());
  } else if (unit == "file") {
    /* sources go into one *.cpp file for each *.bi file */
    for (auto file : package->sources) {
      stream.str("");
      cppOutput << file;
      path = fs::path("src") / file->path;
      path.replace_extension(".cpp");
      write_all_if_different(path, stream.str());
    }
  } else {
    /* sources go into one *.cpp file for each directory */
    std::unordered_map<std::string,std::string> sources;
    for (auto file : package->sources) {
      auto dir = fs::path(file->path).parent_path().string();
      auto iter = sources.find(dir);
      if (iter == sources.end()) {
        iter = sources.insert(std::make_pair(dir, std::string(""))).first;
      }
      stream.str("");
      cppOutput << file;
      iter->second += stream.str();
    }
    for (auto pair : sources) {
      path = fs::path("src") / pair.first / internalName;
      path.replace_extension(".cpp");
      write_all_if_different(path, pair.second);
    }
  }
}

void bi::Compiler::setRoot(Statement* root) {
  this->file->root = root;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 1999-2011 Insight Software Consortium
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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
 * limitations under the License.
 */

#include <iostream>

#include "otbStandardWriterWatcher.h"
#include "otbStopwatch.h"
#include "otbSystem.h"

namespace otb
{

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process,
                        const char *comment)
  : WriterWatcherBase(process, comment)
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process, itk::ProcessObject * source,
                        const char *comment)
  : WriterWatcherBase(process, source, comment)
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process,
                        const std::string& comment)
  : WriterWatcherBase(process, comment.c_str())
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process, itk::ProcessObject * source,
                        const std::string& comment)
  : WriterWatcherBase(process, source, comment.c_str())
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(const StandardWriterWatcher& watch)
  : WriterWatcherBase(watch)
  , m_StarsCount(watch.m_StarsCount)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

void
StandardWriterWatcher
::operator =(const StandardWriterWatcher& watch)
{
  // Initialize state
  WriterWatcherBase::operator=(watch);
  m_StarsCount = watch.m_StarsCount;
}

void
StandardWriterWatcher
::ShowWriterProgress()
{
  this->ShowProgress();
}

void
StandardWriterWatcher
::ShowFilterProgress()
{
  this->ShowProgress();
}

void
StandardWriterWatcher
::ShowProgress()
{
  std::ostringstream oss;
  oss.str("");
  oss << "\r";

  if (m_SourceProcess)
    {
    double      progress = m_SourceProcess->GetProgress();
    int         progressPercent = static_cast<int>(progress * 100);
    unsigned int nbStars = static_cast<int>(progress * m_StarsCount);
    if(nbStars>m_StarsCount)
      {
      nbStars = m_StarsCount;
      }

    std::string stars(nbStars, '*');
    std::string blanks(m_StarsCount - nbStars, ' ');
    oss << "Current Tile: ";
    if (progressPercent < 10)
      {
      oss << " ";
      }
    if (progressPercent < 100)
      {
      oss << " ";
      }
    oss << progressPercent << "% [" << stars << blanks << "]  ";
    }

  if (m_Process)
    {
    double      progress = m_Process->GetProgress();
    int         progressPercent = static_cast<int>(progress * 100);
    unsigned int nbStars = static_cast<int>(progress * m_StarsCount);
    if(nbStars>m_StarsCount)
      {
      nbStars = m_StarsCount;
      }
    std::string stars(nbStars, '*');
    std::string blanks(m_StarsCount - nbStars, ' ');
    oss << "Writing: ";
    if (progressPercent < 10)
      {
      oss << " ";
      }
    if (progressPercent < 100)
      {
      oss << " ";
      }
    oss << progressPercent << "% [" << stars << blanks << "]";
    }

  if (m_CoutIsConsole)
    {
    std::cout << "\r" << oss.str() << std::flush;
    }
  else
    {
    m_Buffer = oss.str();
    }
}

void
StandardWriterWatcher
::StartWriter()
{
  m_Stopwatch.Start();
  std::cout << "Writing task: " << " \"" << m_Comment << "\" " << std::endl;
  std::cout << "Writer type: " << (m_Process.GetPointer() ? m_Process->GetNameOfClass() : "None") << std::endl;
  std::cout << "Filter type: " << (m_SourceProcess.GetPointer() ? m_SourceProcess->GetNameOfClass() : "None") <<
  std::endl;
}

void
StandardWriterWatcher
::EndWriter()
{
  m_Stopwatch.Stop();
  if (!m_CoutIsConsole)
    {
    std::cout << m_Buffer;
    m_Buffer = std::string("");
    }
  std::cout << std::endl << "Writing task took ";
  m_Stopwatch.GetElapsedHumanReadableTime(std::cout);
  std::cout << std::endl;
}

} // end namespace otb
<commit_msg>BUG: remove carriage return, added later<commit_after>/*
 * Copyright (C) 1999-2011 Insight Software Consortium
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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
 * limitations under the License.
 */

#include <iostream>

#include "otbStandardWriterWatcher.h"
#include "otbStopwatch.h"
#include "otbSystem.h"

namespace otb
{

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process,
                        const char *comment)
  : WriterWatcherBase(process, comment)
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process, itk::ProcessObject * source,
                        const char *comment)
  : WriterWatcherBase(process, source, comment)
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process,
                        const std::string& comment)
  : WriterWatcherBase(process, comment.c_str())
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(itk::ProcessObject* process, itk::ProcessObject * source,
                        const std::string& comment)
  : WriterWatcherBase(process, source, comment.c_str())
  , m_StarsCount(50)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

StandardWriterWatcher
::StandardWriterWatcher(const StandardWriterWatcher& watch)
  : WriterWatcherBase(watch)
  , m_StarsCount(watch.m_StarsCount)
  , m_CoutIsConsole( System::IsInteractive(1) )
{
}

void
StandardWriterWatcher
::operator =(const StandardWriterWatcher& watch)
{
  // Initialize state
  WriterWatcherBase::operator=(watch);
  m_StarsCount = watch.m_StarsCount;
}

void
StandardWriterWatcher
::ShowWriterProgress()
{
  this->ShowProgress();
}

void
StandardWriterWatcher
::ShowFilterProgress()
{
  this->ShowProgress();
}

void
StandardWriterWatcher
::ShowProgress()
{
  std::ostringstream oss;
  oss.str("");

  if (m_SourceProcess)
    {
    double      progress = m_SourceProcess->GetProgress();
    int         progressPercent = static_cast<int>(progress * 100);
    unsigned int nbStars = static_cast<int>(progress * m_StarsCount);
    if(nbStars>m_StarsCount)
      {
      nbStars = m_StarsCount;
      }

    std::string stars(nbStars, '*');
    std::string blanks(m_StarsCount - nbStars, ' ');
    oss << "Current Tile: ";
    if (progressPercent < 10)
      {
      oss << " ";
      }
    if (progressPercent < 100)
      {
      oss << " ";
      }
    oss << progressPercent << "% [" << stars << blanks << "]  ";
    }

  if (m_Process)
    {
    double      progress = m_Process->GetProgress();
    int         progressPercent = static_cast<int>(progress * 100);
    unsigned int nbStars = static_cast<int>(progress * m_StarsCount);
    if(nbStars>m_StarsCount)
      {
      nbStars = m_StarsCount;
      }
    std::string stars(nbStars, '*');
    std::string blanks(m_StarsCount - nbStars, ' ');
    oss << "Writing: ";
    if (progressPercent < 10)
      {
      oss << " ";
      }
    if (progressPercent < 100)
      {
      oss << " ";
      }
    oss << progressPercent << "% [" << stars << blanks << "]";
    }

  if (m_CoutIsConsole)
    {
    std::cout << "\r" << oss.str() << std::flush;
    }
  else
    {
    m_Buffer = oss.str();
    }
}

void
StandardWriterWatcher
::StartWriter()
{
  m_Stopwatch.Start();
  std::cout << "Writing task: " << " \"" << m_Comment << "\" " << std::endl;
  std::cout << "Writer type: " << (m_Process.GetPointer() ? m_Process->GetNameOfClass() : "None") << std::endl;
  std::cout << "Filter type: " << (m_SourceProcess.GetPointer() ? m_SourceProcess->GetNameOfClass() : "None") <<
  std::endl;
}

void
StandardWriterWatcher
::EndWriter()
{
  m_Stopwatch.Stop();
  if (!m_CoutIsConsole)
    {
    std::cout << m_Buffer;
    m_Buffer = std::string("");
    }
  std::cout << std::endl << "Writing task took ";
  m_Stopwatch.GetElapsedHumanReadableTime(std::cout);
  std::cout << std::endl;
}

} // end namespace otb
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_SYSTEM_HH
#define DUNE_GDT_ASSEMBLER_SYSTEM_HH

#include <type_traits>
#include <memory>

#include <dune/common/version.hh>

#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/common/parallel/helper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "wrapper.hh"

namespace Dune {
namespace GDT {

template <class TestSpaceImp, class GridViewImp = typename TestSpaceImp::GridViewType,
          class AnsatzSpaceImp                  = TestSpaceImp>
class SystemAssembler : public DSG::Walker<GridViewImp>
{
  static_assert(std::is_base_of<SpaceInterface<typename TestSpaceImp::Traits>, TestSpaceImp>::value,
                "TestSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename AnsatzSpaceImp::Traits>, AnsatzSpaceImp>::value,
                "AnsatzSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_same<typename TestSpaceImp::RangeFieldType, typename AnsatzSpaceImp::RangeFieldType>::value,
                "Types do not match!");
  typedef DSG::Walker<GridViewImp> BaseType;
  typedef SystemAssembler<TestSpaceImp, GridViewImp, AnsatzSpaceImp> ThisType;

public:
  typedef TestSpaceImp TestSpaceType;
  typedef AnsatzSpaceImp AnsatzSpaceType;
  typedef typename TestSpaceType::RangeFieldType RangeFieldType;

  typedef typename BaseType::GridViewType GridViewType;
  typedef typename BaseType::EntityType EntityType;
  typedef typename BaseType::IntersectionType IntersectionType;

  typedef DSG::ApplyOn::WhichEntity<GridViewType> ApplyOnWhichEntity;
  typedef DSG::ApplyOn::WhichIntersection<GridViewType> ApplyOnWhichIntersection;

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(ansatz)
  {
  }

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(ansatz)
  {
  }

  explicit SystemAssembler(TestSpaceType test)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(test)
  {
  }

  SystemAssembler(TestSpaceType test, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(test_space_)
  {
  }

  const TestSpaceType& test_space() const
  {
    return *test_space_;
  }

  const AnsatzSpaceType& ansatz_space() const
  {
    return *ansatz_space_;
  }

  using BaseType::add;

  template <class C, class M>
  void add(Spaces::ConstraintsInterface<C, RangeFieldType>& constraints,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalMatrixConstraintsWrapper<TestSpaceType,
                                                    AnsatzSpaceType,
                                                    GridViewType,
                                                    typename C::derived_type,
                                                    typename M::derived_type> WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, constraints.as_imp(), matrix.as_imp()));
  } // ... add(...)

  /** \todo Investigate why the ConstraintsInterface is not used here! */
  template <class ConstraintsType, class V>
  void add(ConstraintsType& constraints, Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVectorConstraintsWrapper<ThisType, ConstraintsType, VectorType> WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, constraints, vector_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim0Matrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim0Matrix<L>, MatrixType>
        WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class Codim0Assembler, class M>
  void add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper<ThisType, Codim0Assembler, MatrixType> WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class Codim0Assembler, class V>
  void add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper<ThisType, Codim0Assembler, VectorType> WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim1CouplingMatrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim1CouplingMatrix<L>, MatrixType>
        WrapperType;
    this->codim1_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim1BoundaryMatrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim1BoundaryMatrix<L>, MatrixType>
        WrapperType;
    this->codim1_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class L, class V>
  void add(const LocalAssembler::Codim0Vector<L>& local_assembler,
           Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper<ThisType, LocalAssembler::Codim0Vector<L>, VectorType>
        WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template <class L, class V>
  void add(const LocalAssembler::Codim1Vector<L>& local_assembler,
           Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = static_cast<VectorType&>(vector);
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalFaceVectorAssemblerWrapper<ThisType, LocalAssembler::Codim1Vector<L>, VectorType>
        WrapperType;
    this->codim1_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  void assemble(const bool use_tbb = false)
  {
    this->walk(use_tbb);
  }

private:
  const DS::PerThreadValue<const TestSpaceType> test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType> ansatz_space_;
}; // class SystemAssembler

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_SYSTEM_HH
<commit_msg>[assembler] fixes system ctor trying to copy a per thread value<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_SYSTEM_HH
#define DUNE_GDT_ASSEMBLER_SYSTEM_HH

#include <type_traits>
#include <memory>

#include <dune/common/version.hh>

#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/common/parallel/helper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "wrapper.hh"

namespace Dune {
namespace GDT {

template <class TestSpaceImp, class GridViewImp = typename TestSpaceImp::GridViewType,
          class AnsatzSpaceImp                  = TestSpaceImp>
class SystemAssembler : public DSG::Walker<GridViewImp>
{
  static_assert(std::is_base_of<SpaceInterface<typename TestSpaceImp::Traits>, TestSpaceImp>::value,
                "TestSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_base_of<SpaceInterface<typename AnsatzSpaceImp::Traits>, AnsatzSpaceImp>::value,
                "AnsatzSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_same<typename TestSpaceImp::RangeFieldType, typename AnsatzSpaceImp::RangeFieldType>::value,
                "Types do not match!");
  typedef DSG::Walker<GridViewImp> BaseType;
  typedef SystemAssembler<TestSpaceImp, GridViewImp, AnsatzSpaceImp> ThisType;

public:
  typedef TestSpaceImp TestSpaceType;
  typedef AnsatzSpaceImp AnsatzSpaceType;
  typedef typename TestSpaceType::RangeFieldType RangeFieldType;

  typedef typename BaseType::GridViewType GridViewType;
  typedef typename BaseType::EntityType EntityType;
  typedef typename BaseType::IntersectionType IntersectionType;

  typedef DSG::ApplyOn::WhichEntity<GridViewType> ApplyOnWhichEntity;
  typedef DSG::ApplyOn::WhichIntersection<GridViewType> ApplyOnWhichIntersection;

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(ansatz)
  {
  }

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(ansatz)
  {
  }

  explicit SystemAssembler(TestSpaceType test)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(test)
  {
  }

  SystemAssembler(TestSpaceType test, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(test)
  {
  }

  const TestSpaceType& test_space() const
  {
    return *test_space_;
  }

  const AnsatzSpaceType& ansatz_space() const
  {
    return *ansatz_space_;
  }

  using BaseType::add;

  template <class C, class M>
  void add(Spaces::ConstraintsInterface<C, RangeFieldType>& constraints,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalMatrixConstraintsWrapper<TestSpaceType,
                                                    AnsatzSpaceType,
                                                    GridViewType,
                                                    typename C::derived_type,
                                                    typename M::derived_type> WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, constraints.as_imp(), matrix.as_imp()));
  } // ... add(...)

  /** \todo Investigate why the ConstraintsInterface is not used here! */
  template <class ConstraintsType, class V>
  void add(ConstraintsType& constraints, Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVectorConstraintsWrapper<ThisType, ConstraintsType, VectorType> WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, constraints, vector_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim0Matrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim0Matrix<L>, MatrixType>
        WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class Codim0Assembler, class M>
  void add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper<ThisType, Codim0Assembler, MatrixType> WrapperType;
    this->codim0_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class Codim0Assembler, class V>
  void add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper<ThisType, Codim0Assembler, VectorType> WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim1CouplingMatrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim1CouplingMatrix<L>, MatrixType>
        WrapperType;
    this->codim1_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class L, class M>
  void add(const LocalAssembler::Codim1BoundaryMatrix<L>& local_assembler,
           Stuff::LA::MatrixInterface<M, RangeFieldType>& matrix,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper<ThisType, LocalAssembler::Codim1BoundaryMatrix<L>, MatrixType>
        WrapperType;
    this->codim1_functors_.emplace_back(
        new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template <class L, class V>
  void add(const LocalAssembler::Codim0Vector<L>& local_assembler,
           Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper<ThisType, LocalAssembler::Codim0Vector<L>, VectorType>
        WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template <class L, class V>
  void add(const LocalAssembler::Codim1Vector<L>& local_assembler,
           Stuff::LA::VectorInterface<V, RangeFieldType>& vector,
           const ApplyOnWhichIntersection* where = new DSG::ApplyOn::AllIntersections<GridViewType>())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = static_cast<VectorType&>(vector);
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalFaceVectorAssemblerWrapper<ThisType, LocalAssembler::Codim1Vector<L>, VectorType>
        WrapperType;
    this->codim1_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  void assemble(const bool use_tbb = false)
  {
    this->walk(use_tbb);
  }

private:
  const DS::PerThreadValue<const TestSpaceType> test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType> ansatz_space_;
}; // class SystemAssembler

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_SYSTEM_HH
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_dot_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/mixed_inner_product_function.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>

#include <vespa/log/log.h>
LOG_SETUP("mixed_inner_product_function_test");

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;

const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();

struct MyVecSeq : Sequence {
    double bias;
    double operator[](size_t i) const override { return (i + bias); }
    MyVecSeq(double cellBias) : bias(cellBias) {}
};

std::function<double(size_t)> my_vec_gen(double cellBias) {
    return [=] (size_t i) { return i + cellBias; };
}

//-----------------------------------------------------------------------------

EvalFixture::ParamRepo make_params() {
    return EvalFixture::ParamRepo()
        .add_vector("x", 3, my_vec_gen(2.0))
        .add_vector("x", 3, my_vec_gen(13.25))
        .add_vector("y", 3, my_vec_gen(4.0))
        .add_vector("z", 3, my_vec_gen(0.25))
        .add_matrix("x", 3, "y", 1, my_vec_gen(5.0))
        .add_matrix("x", 1, "y", 3, my_vec_gen(6.0))
        .add_matrix("x", 3, "y", 3, my_vec_gen(1.5))
        .add_matrix("x", 3, "z", 3, my_vec_gen(2.5))
        .add_cube("x", 3, "y", 3, "z", 3, my_vec_gen(-4.0))
        .add("mix_x3zm", spec({x(3),z({"c","d"})}, MyVecSeq(0.5)))
        .add("mix_y3zm", spec({y(3),z({"c","d"})}, MyVecSeq(3.5)))
        .add("mix_x3zm_f", spec(float_cells({x(3),z({"c","d"})}), MyVecSeq(0.5)))
        .add("mix_y3zm_f", spec(float_cells({y(3),z({"c","d"})}), MyVecSeq(3.5)))
        .add("mix_x3y3zm", spec({x(3),y(3),z({"c","d"})}, MyVecSeq(0.0)))
        ;

}
EvalFixture::ParamRepo param_repo = make_params();

void assert_mixed_optimized(const vespalib::string &expr) {
    EvalFixture fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
}

void assert_not_mixed_optimized(const vespalib::string &expr) {
    EvalFixture fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
}

void assert_dense_optimized(const vespalib::string &expr) {
    EvalFixture fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
    auto info2 = fixture.find_all<DenseDotProductFunction>();
    auto info3 = fixture.find_all<DenseMatMulFunction>();
    auto info4 = fixture.find_all<DenseMultiMatMulFunction>();
    auto info5 = fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQ(info2.size() + info3.size() + info4.size() + info5.size(), 1u);
}

//-----------------------------------------------------------------------------

TEST(MixedInnerProduct, use_dense_optimizers_when_possible) {
    // actually, all these trigger DenseXWProduct
    assert_dense_optimized("reduce(x3 * x3y1,sum,x)");
    assert_dense_optimized("reduce(y3 * x1y3,sum,y)");
    assert_dense_optimized("reduce(y3 * x3y3,sum,y)");
    assert_dense_optimized("reduce(x1y3 * y3,sum,y)");
    assert_dense_optimized("reduce(x3y3 * y3,sum,y)");
}

TEST(MixedInnerProduct, trigger_optimizer_when_possible) {
    assert_mixed_optimized("reduce(x3 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3 * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(mix_x3zm * x3,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3f,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1f,sum,x)");
    assert_mixed_optimized("reduce(mix_y3zm * y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * y3f,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3f,sum,y)");
}

TEST(MixedInnerProduct, should_not_trigger_optimizer_for_other_cases) {
    assert_not_mixed_optimized("reduce(x3y3z3 * x3,sum,x)");
    assert_not_mixed_optimized("reduce(x3y3z3 * y3,sum,y)");
    assert_not_mixed_optimized("reduce(x3y3z3 * x3y3,sum,x,y)");
    assert_not_mixed_optimized("reduce(x3y3 * mix_y3zm,sum,y)");
    assert_not_mixed_optimized("reduce(mix_y3zm * x3,sum,x,y)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,y,z)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,x,y)");
}

TEST(MixedInnerProduct, check_compatibility_with_complex_types) {
    ValueType vec_type = ValueType::from_spec("tensor<float>(f[1],g[2],i[1],x[3],y[1])");
    ValueType mix_type = ValueType::from_spec("tensor<double>(cat{},g[2],host{},k[1],x[3],z{})");
    ValueType res_type = ValueType::join(vec_type,mix_type).reduce({"g","k","i","x"});
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, mix_type, vec_type), true);
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, vec_type, mix_type), false);
}

//-----------------------------------------------------------------------------

GTEST_MAIN_RUN_ALL_TESTS()
<commit_msg>also test without optimization<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_dot_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/mixed_inner_product_function.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>

#include <vespa/log/log.h>
LOG_SETUP("mixed_inner_product_function_test");

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;

const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();

struct MyVecSeq : Sequence {
    double bias;
    double operator[](size_t i) const override { return (i + bias); }
    MyVecSeq(double cellBias) : bias(cellBias) {}
};

std::function<double(size_t)> my_vec_gen(double cellBias) {
    return [=] (size_t i) { return i + cellBias; };
}

//-----------------------------------------------------------------------------

EvalFixture::ParamRepo make_params() {
    return EvalFixture::ParamRepo()
        .add_vector("x", 3, my_vec_gen(2.0))
        .add_vector("x", 3, my_vec_gen(13.25))
        .add_vector("y", 3, my_vec_gen(4.0))
        .add_vector("z", 3, my_vec_gen(0.25))
        .add_matrix("x", 3, "y", 1, my_vec_gen(5.0))
        .add_matrix("x", 1, "y", 3, my_vec_gen(6.0))
        .add_matrix("x", 3, "y", 3, my_vec_gen(1.5))
        .add_matrix("x", 3, "z", 3, my_vec_gen(2.5))
        .add_cube("x", 3, "y", 3, "z", 3, my_vec_gen(-4.0))
        .add("mix_x3zm", spec({x(3),z({"c","d"})}, MyVecSeq(0.5)))
        .add("mix_y3zm", spec({y(3),z({"c","d"})}, MyVecSeq(3.5)))
        .add("mix_x3zm_f", spec(float_cells({x(3),z({"c","d"})}), MyVecSeq(0.5)))
        .add("mix_y3zm_f", spec(float_cells({y(3),z({"c","d"})}), MyVecSeq(3.5)))
        .add("mix_x3y3zm", spec({x(3),y(3),z({"c","d"})}, MyVecSeq(0.0)))
        ;

}
EvalFixture::ParamRepo param_repo = make_params();

void assert_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
}

void assert_not_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
}

void assert_dense_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
    auto info2 = fast_fixture.find_all<DenseDotProductFunction>();
    auto info3 = fast_fixture.find_all<DenseMatMulFunction>();
    auto info4 = fast_fixture.find_all<DenseMultiMatMulFunction>();
    auto info5 = fast_fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQ(info2.size() + info3.size() + info4.size() + info5.size(), 1u);
}

//-----------------------------------------------------------------------------

TEST(MixedInnerProduct, use_dense_optimizers_when_possible) {
    // actually, all these trigger DenseXWProduct
    assert_dense_optimized("reduce(x3 * x3y1,sum,x)");
    assert_dense_optimized("reduce(y3 * x1y3,sum,y)");
    assert_dense_optimized("reduce(y3 * x3y3,sum,y)");
    assert_dense_optimized("reduce(x1y3 * y3,sum,y)");
    assert_dense_optimized("reduce(x3y3 * y3,sum,y)");
}

TEST(MixedInnerProduct, trigger_optimizer_when_possible) {
    assert_mixed_optimized("reduce(x3 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3 * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(mix_x3zm * x3,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3f,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1f,sum,x)");
    assert_mixed_optimized("reduce(mix_y3zm * y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * y3f,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3f,sum,y)");
}

TEST(MixedInnerProduct, should_not_trigger_optimizer_for_other_cases) {
    assert_not_mixed_optimized("reduce(x3y3z3 * x3,sum,x)");
    assert_not_mixed_optimized("reduce(x3y3z3 * y3,sum,y)");
    assert_not_mixed_optimized("reduce(x3y3z3 * x3y3,sum,x,y)");
    assert_not_mixed_optimized("reduce(x3y3 * mix_y3zm,sum,y)");
    assert_not_mixed_optimized("reduce(mix_y3zm * x3,sum,x,y)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,y,z)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,x,y)");
}

TEST(MixedInnerProduct, check_compatibility_with_complex_types) {
    ValueType vec_type = ValueType::from_spec("tensor<float>(f[1],g[2],i[1],x[3],y[1])");
    ValueType mix_type = ValueType::from_spec("tensor<double>(cat{},g[2],host{},k[1],x[3],z{})");
    ValueType res_type = ValueType::join(vec_type,mix_type).reduce({"g","k","i","x"});
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, mix_type, vec_type), true);
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, vec_type, mix_type), false);
}

//-----------------------------------------------------------------------------

GTEST_MAIN_RUN_ALL_TESTS()
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_SYSTEM_HH
#define DUNE_GDT_ASSEMBLER_SYSTEM_HH

#include <type_traits>
#include <memory>

#include <dune/common/deprecated.hh>
#include <dune/common/version.hh>

#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/common/parallel/helper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "wrapper.hh"

namespace Dune {
namespace GDT {

template< class TestSpaceImp,
          class GridViewImp = typename TestSpaceImp::GridViewType,
          class AnsatzSpaceImp = TestSpaceImp >
class SystemAssembler
  : public DSG::Walker< GridViewImp >
{
  static_assert(GDT::is_space< TestSpaceImp >::value,   "TestSpaceImp has to be derived from SpaceInterface!");
  static_assert(GDT::is_space< AnsatzSpaceImp >::value, "AnsatzSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_same< typename TestSpaceImp::RangeFieldType, typename AnsatzSpaceImp::RangeFieldType >::value,
                "Types do not match!");
  typedef DSG::Walker< GridViewImp >                                  BaseType;
  typedef SystemAssembler<TestSpaceImp, GridViewImp, AnsatzSpaceImp > ThisType;
public:
  typedef TestSpaceImp                           TestSpaceType;
  typedef AnsatzSpaceImp                         AnsatzSpaceType;
  typedef typename TestSpaceType::RangeFieldType RangeFieldType;

  typedef typename BaseType::GridViewType     GridViewType;
  typedef typename BaseType::EntityType       EntityType;
  typedef typename BaseType::IntersectionType IntersectionType;

  typedef DSG::ApplyOn::WhichEntity< GridViewType >       ApplyOnWhichEntity;
  typedef DSG::ApplyOn::WhichIntersection< GridViewType > ApplyOnWhichIntersection;

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(ansatz)
  {}

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(ansatz)
  {}

  explicit SystemAssembler(TestSpaceType test)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(test)
  {}

  SystemAssembler(TestSpaceType test, GridViewType grid_view_in)
    : BaseType(grid_view_in)
    , test_space_(test)
    , ansatz_space_(test)
  {}

  const TestSpaceType& test_space() const
  {
    return *test_space_;
  }

  const AnsatzSpaceType& ansatz_space() const
  {
    return *ansatz_space_;
  }

  using BaseType::add;

  template< class C, class M >
  void add(Spaces::ConstraintsInterface< C, RangeFieldType >& constraints,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalMatrixConstraintsWrapper< TestSpaceType,
                                                     AnsatzSpaceType,
                                                     GridViewType,
                                                     typename C::derived_type,
                                                     typename M::derived_type > WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_,
                                                        ansatz_space_,
                                                        where,
                                                        constraints.as_imp(),
                                                        matrix.as_imp()));
  } // ... add(...)

  template< class C, class V >
  void add(Spaces::ConstraintsInterface< C, RangeFieldType >& constraints,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVectorConstraintsWrapper< ThisType, ConstraintsType, VectorType > WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, constraints, vector_imp));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim0Matrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim0Matrix< L >, MatrixType >
        WrapperType;
    this->codim0_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template< class Codim0Assembler, class M >
  void
    DUNE_DEPRECATED_MSG("Will be removed or first argument has to be replaced by an interface (04.02.2015)!")
        add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper< ThisType, Codim0Assembler, MatrixType > WrapperType;
    this->codim0_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template< class Codim0Assembler, class V >
  void
    DUNE_DEPRECATED_MSG("Will be removed or first argument has to be replaced by an interface (04.02.2015)!")
       add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper< ThisType, Codim0Assembler, VectorType > WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim1CouplingMatrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim1CouplingMatrix< L >, MatrixType >
        WrapperType;
    this->codim1_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim1BoundaryMatrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    typedef typename M::derived_type MatrixType;
    MatrixType& matrix_imp = matrix.as_imp();
    assert(matrix_imp.rows() == test_space_->mapper().size());
    assert(matrix_imp.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim1BoundaryMatrix< L >, MatrixType >
        WrapperType;
    this->codim1_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix_imp));
  } // ... add(...)

  template< class L, class V >
  void add(const LocalAssembler::Codim0Vector< L >& local_assembler,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichEntity* where
              = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = vector.as_imp();
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper< ThisType, LocalAssembler::Codim0Vector< L >, VectorType >
        WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  template< class L, class V >
  void add(const LocalAssembler::Codim1Vector< L >& local_assembler,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    typedef typename V::derived_type VectorType;
    VectorType& vector_imp = static_cast< VectorType& >(vector);
    assert(vector_imp.size() == test_space_->mapper().size());
    typedef internal::LocalFaceVectorAssemblerWrapper< ThisType, LocalAssembler::Codim1Vector< L >, VectorType >
        WrapperType;
    this->codim1_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector_imp));
  } // ... add(...)

  void assemble(const bool use_tbb = false)
  {
    this->walk(use_tbb);
  }

  template <class Partitioning>
  void assemble(const Partitioning& partitioning)
  {
    this->walk(partitioning);
  }

private:
  const DS::PerThreadValue<const TestSpaceType> test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType> ansatz_space_;
}; // class SystemAssembler

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_SYSTEM_HH
<commit_msg>[assemlber.system] modernize<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_SYSTEM_HH
#define DUNE_GDT_ASSEMBLER_SYSTEM_HH

#include <type_traits>
#include <memory>

#include <dune/common/deprecated.hh>
#include <dune/common/version.hh>

#include <dune/stuff/grid/walker.hh>
#include <dune/stuff/common/parallel/helper.hh>

#include <dune/gdt/spaces/interface.hh>
#include <dune/gdt/spaces/constraints.hh>

#include "local/codim0.hh"
#include "local/codim1.hh"
#include "wrapper.hh"

namespace Dune {
namespace GDT {

template< class TestSpaceImp,
          class GridViewImp = typename TestSpaceImp::GridViewType,
          class AnsatzSpaceImp = TestSpaceImp >
class SystemAssembler
  : public DSG::Walker< GridViewImp >
{
  static_assert(GDT::is_space< TestSpaceImp >::value,   "TestSpaceImp has to be derived from SpaceInterface!");
  static_assert(GDT::is_space< AnsatzSpaceImp >::value, "AnsatzSpaceImp has to be derived from SpaceInterface!");
  static_assert(std::is_same< typename TestSpaceImp::RangeFieldType, typename AnsatzSpaceImp::RangeFieldType >::value,
                "Types do not match!");
  typedef DSG::Walker< GridViewImp >                                  BaseType;
  typedef SystemAssembler<TestSpaceImp, GridViewImp, AnsatzSpaceImp > ThisType;
public:
  typedef TestSpaceImp                           TestSpaceType;
  typedef AnsatzSpaceImp                         AnsatzSpaceType;
  typedef typename TestSpaceType::RangeFieldType RangeFieldType;

  typedef typename BaseType::GridViewType     GridViewType;
  typedef typename BaseType::EntityType       EntityType;
  typedef typename BaseType::IntersectionType IntersectionType;

  typedef DSG::ApplyOn::WhichEntity< GridViewType >       ApplyOnWhichEntity;
  typedef DSG::ApplyOn::WhichIntersection< GridViewType > ApplyOnWhichIntersection;

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz, GridViewType grid_view)
    : BaseType(grid_view)
    , test_space_(test)
    , ansatz_space_(ansatz)
  {}

  SystemAssembler(TestSpaceType test, AnsatzSpaceType ansatz)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(ansatz)
  {}

  explicit SystemAssembler(TestSpaceType test)
    : BaseType(test.grid_view())
    , test_space_(test)
    , ansatz_space_(test)
  {}

  SystemAssembler(TestSpaceType test, GridViewType grid_view_in)
    : BaseType(grid_view_in)
    , test_space_(test)
    , ansatz_space_(test)
  {}

  const TestSpaceType& test_space() const
  {
    return *test_space_;
  }

  const AnsatzSpaceType& ansatz_space() const
  {
    return *ansatz_space_;
  }

  using BaseType::add;

  template< class C, class M >
  void add(Spaces::ConstraintsInterface< C, RangeFieldType >& constraints,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalMatrixConstraintsWrapper< TestSpaceType,
                                                     AnsatzSpaceType,
                                                     GridViewType,
                                                     typename C::derived_type,
                                                     typename M::derived_type > WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_,
                                                        ansatz_space_,
                                                        where,
                                                        constraints.as_imp(),
                                                        matrix.as_imp()));
  } // ... add(...)

  template< class C, class V >
  void add(Spaces::ConstraintsInterface< C, RangeFieldType >& constraints,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(vector.size() == test_space_->mapper().size());
    typedef internal::LocalVectorConstraintsWrapper< ThisType, typename C::derived_type, typename V::derived_type >
        WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, constraints.as_imp(), vector.as_imp()));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim0Matrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim0Matrix< L >,
                                                         typename M::derived_type >                   WrapperType;
    this->codim0_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix.as_imp()));
  } // ... add(...)

  template< class Codim0Assembler, class M >
  void
    DUNE_DEPRECATED_MSG("Will be removed or first argument has to be replaced by an interface (04.02.2015)!")
        add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalVolumeMatrixAssemblerWrapper< ThisType, Codim0Assembler, typename M::derived_type >
        WrapperType;
    this->codim0_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix.as_imp()));
  } // ... add(...)

  template< class Codim0Assembler, class V >
  void
    DUNE_DEPRECATED_MSG("Will be removed or first argument has to be replaced by an interface (04.02.2015)!")
       add_codim0_assembler(const Codim0Assembler& local_assembler,
                            Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
                            const ApplyOnWhichEntity* where = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(vector.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper< ThisType, Codim0Assembler, typename V::derived_type >
        WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector.as_imp()));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim1CouplingMatrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim1CouplingMatrix< L >,
                                                       typename M::derived_type >                           WrapperType;
    this->codim1_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix.as_imp()));
  } // ... add(...)

  template< class L, class M >
  void add(const LocalAssembler::Codim1BoundaryMatrix< L >& local_assembler,
           Stuff::LA::MatrixInterface< M, RangeFieldType >& matrix,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    assert(matrix.rows() == test_space_->mapper().size());
    assert(matrix.cols() == ansatz_space_->mapper().size());
    typedef internal::LocalFaceMatrixAssemblerWrapper< ThisType, LocalAssembler::Codim1BoundaryMatrix< L >,
                                                       typename M::derived_type >                           WrapperType;
    this->codim1_functors_.emplace_back(
          new WrapperType(test_space_, ansatz_space_, where, local_assembler, matrix.as_imp()));
  } // ... add(...)

  template< class L, class V >
  void add(const LocalAssembler::Codim0Vector< L >& local_assembler,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichEntity* where
              = new DSG::ApplyOn::AllEntities< GridViewType >())
  {
    assert(vector.size() == test_space_->mapper().size());
    typedef internal::LocalVolumeVectorAssemblerWrapper< ThisType, LocalAssembler::Codim0Vector< L >,
                                                         typename V::derived_type >                   WrapperType;
    this->codim0_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector.as_imp()));
  } // ... add(...)

  template< class L, class V >
  void add(const LocalAssembler::Codim1Vector< L >& local_assembler,
           Stuff::LA::VectorInterface< V, RangeFieldType >& vector,
           const ApplyOnWhichIntersection* where
              = new DSG::ApplyOn::AllIntersections< GridViewType >())
  {
    assert(vector.size() == test_space_->mapper().size());
    typedef internal::LocalFaceVectorAssemblerWrapper< ThisType, LocalAssembler::Codim1Vector< L >,
                                                       typename V::derived_type >                   WrapperType;
    this->codim1_functors_.emplace_back(new WrapperType(test_space_, where, local_assembler, vector.as_imp()));
  } // ... add(...)

  void assemble(const bool use_tbb = false)
  {
    this->walk(use_tbb);
  }

  template <class Partitioning>
  void assemble(const Partitioning& partitioning)
  {
    this->walk(partitioning);
  }

private:
  const DS::PerThreadValue<const TestSpaceType> test_space_;
  const DS::PerThreadValue<const AnsatzSpaceType> ansatz_space_;
}; // class SystemAssembler

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_SYSTEM_HH
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_dot_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/mixed_inner_product_function.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>

#include <vespa/log/log.h>
LOG_SETUP("mixed_inner_product_function_test");

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;

const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();

struct MyVecSeq : Sequence {
    double bias;
    double operator[](size_t i) const override { return (i + bias); }
    MyVecSeq(double cellBias) : bias(cellBias) {}
};

std::function<double(size_t)> my_vec_gen(double cellBias) {
    return [=] (size_t i) { return i + cellBias; };
}

//-----------------------------------------------------------------------------

EvalFixture::ParamRepo make_params() {
    return EvalFixture::ParamRepo()
        .add_vector("x", 3, my_vec_gen(2.0))
        .add_vector("x", 3, my_vec_gen(13.25))
        .add_vector("y", 3, my_vec_gen(4.0))
        .add_vector("z", 3, my_vec_gen(0.25))
        .add_matrix("x", 3, "y", 1, my_vec_gen(5.0))
        .add_matrix("x", 1, "y", 3, my_vec_gen(6.0))
        .add_matrix("x", 3, "y", 3, my_vec_gen(1.5))
        .add_matrix("x", 3, "z", 3, my_vec_gen(2.5))
        .add_cube("x", 3, "y", 3, "z", 3, my_vec_gen(-4.0))
        .add("mix_x3zm", spec({x(3),z({"c","d"})}, MyVecSeq(0.5)))
        .add("mix_y3zm", spec({y(3),z({"c","d"})}, MyVecSeq(3.5)))
        .add("mix_x3zm_f", spec(float_cells({x(3),z({"c","d"})}), MyVecSeq(0.5)))
        .add("mix_y3zm_f", spec(float_cells({y(3),z({"c","d"})}), MyVecSeq(3.5)))
        .add("mix_x3y3zm", spec({x(3),y(3),z({"c","d"})}, MyVecSeq(0.0)))
        ;

}
EvalFixture::ParamRepo param_repo = make_params();

void assert_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
}

void assert_not_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
}

void assert_dense_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
    auto info2 = fast_fixture.find_all<DenseDotProductFunction>();
    auto info3 = fast_fixture.find_all<DenseMatMulFunction>();
    auto info4 = fast_fixture.find_all<DenseMultiMatMulFunction>();
    auto info5 = fast_fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQ(info2.size() + info3.size() + info4.size() + info5.size(), 1u);
}

//-----------------------------------------------------------------------------

TEST(MixedInnerProduct, use_dense_optimizers_when_possible) {
    // actually, all these trigger DenseXWProduct
    assert_dense_optimized("reduce(x3 * x3y1,sum,x)");
    assert_dense_optimized("reduce(y3 * x1y3,sum,y)");
    assert_dense_optimized("reduce(y3 * x3y3,sum,y)");
    assert_dense_optimized("reduce(x1y3 * y3,sum,y)");
    assert_dense_optimized("reduce(x3y3 * y3,sum,y)");
}

TEST(MixedInnerProduct, trigger_optimizer_when_possible) {
    assert_mixed_optimized("reduce(x3 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3 * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(mix_x3zm * x3,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3f,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1f,sum,x)");
    assert_mixed_optimized("reduce(mix_y3zm * y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * y3f,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3f,sum,y)");
}

TEST(MixedInnerProduct, should_not_trigger_optimizer_for_other_cases) {
    assert_not_mixed_optimized("reduce(x3y3z3 * x3,sum,x)");
    assert_not_mixed_optimized("reduce(x3y3z3 * y3,sum,y)");
    assert_not_mixed_optimized("reduce(x3y3z3 * x3y3,sum,x,y)");
    assert_not_mixed_optimized("reduce(x3y3 * mix_y3zm,sum,y)");
    assert_not_mixed_optimized("reduce(mix_y3zm * x3,sum,x,y)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,y,z)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,x,y)");
}

TEST(MixedInnerProduct, check_compatibility_with_complex_types) {
    ValueType vec_type = ValueType::from_spec("tensor<float>(f[1],g[2],i[1],x[3],y[1])");
    ValueType mix_type = ValueType::from_spec("tensor<double>(cat{},g[2],host{},k[1],x[3],z{})");
    ValueType res_type = ValueType::join(vec_type,mix_type).reduce({"g","k","i","x"});
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, mix_type, vec_type), true);
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, vec_type, mix_type), false);
}

//-----------------------------------------------------------------------------

GTEST_MAIN_RUN_ALL_TESTS()
<commit_msg>Use noexcept for simple lambda.<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/eval/eval/fast_value.h>
#include <vespa/eval/eval/tensor_function.h>
#include <vespa/eval/eval/test/eval_fixture.h>
#include <vespa/eval/eval/test/tensor_model.hpp>
#include <vespa/eval/instruction/dense_dot_product_function.h>
#include <vespa/eval/instruction/dense_matmul_function.h>
#include <vespa/eval/instruction/dense_multi_matmul_function.h>
#include <vespa/eval/instruction/dense_xw_product_function.h>
#include <vespa/eval/instruction/mixed_inner_product_function.h>
#include <vespa/vespalib/util/stash.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/gtest/gtest.h>

#include <vespa/log/log.h>
LOG_SETUP("mixed_inner_product_function_test");

using namespace vespalib;
using namespace vespalib::eval;
using namespace vespalib::eval::test;

const ValueBuilderFactory &prod_factory = FastValueBuilderFactory::get();

struct MyVecSeq : Sequence {
    double bias;
    double operator[](size_t i) const override { return (i + bias); }
    MyVecSeq(double cellBias) : bias(cellBias) {}
};

std::function<double(size_t)> my_vec_gen(double cellBias) {
    return [=] (size_t i) noexcept { return i + cellBias; };
}

//-----------------------------------------------------------------------------

EvalFixture::ParamRepo make_params() {
    return EvalFixture::ParamRepo()
        .add_vector("x", 3, my_vec_gen(2.0))
        .add_vector("x", 3, my_vec_gen(13.25))
        .add_vector("y", 3, my_vec_gen(4.0))
        .add_vector("z", 3, my_vec_gen(0.25))
        .add_matrix("x", 3, "y", 1, my_vec_gen(5.0))
        .add_matrix("x", 1, "y", 3, my_vec_gen(6.0))
        .add_matrix("x", 3, "y", 3, my_vec_gen(1.5))
        .add_matrix("x", 3, "z", 3, my_vec_gen(2.5))
        .add_cube("x", 3, "y", 3, "z", 3, my_vec_gen(-4.0))
        .add("mix_x3zm", spec({x(3),z({"c","d"})}, MyVecSeq(0.5)))
        .add("mix_y3zm", spec({y(3),z({"c","d"})}, MyVecSeq(3.5)))
        .add("mix_x3zm_f", spec(float_cells({x(3),z({"c","d"})}), MyVecSeq(0.5)))
        .add("mix_y3zm_f", spec(float_cells({y(3),z({"c","d"})}), MyVecSeq(3.5)))
        .add("mix_x3y3zm", spec({x(3),y(3),z({"c","d"})}, MyVecSeq(0.0)))
        ;

}
EvalFixture::ParamRepo param_repo = make_params();

void assert_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 1u);
    EXPECT_TRUE(info[0]->result_is_mutable());
}

void assert_not_mixed_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
}

void assert_dense_optimized(const vespalib::string &expr) {
    EvalFixture slow_fixture(prod_factory, expr, param_repo, false);
    EvalFixture fast_fixture(prod_factory, expr, param_repo, true);
    EXPECT_EQ(slow_fixture.result(), EvalFixture::ref(expr, param_repo));
    EXPECT_EQ(fast_fixture.result(), EvalFixture::ref(expr, param_repo));
    auto info = fast_fixture.find_all<MixedInnerProductFunction>();
    ASSERT_EQ(info.size(), 0u);
    auto info2 = fast_fixture.find_all<DenseDotProductFunction>();
    auto info3 = fast_fixture.find_all<DenseMatMulFunction>();
    auto info4 = fast_fixture.find_all<DenseMultiMatMulFunction>();
    auto info5 = fast_fixture.find_all<DenseXWProductFunction>();
    ASSERT_EQ(info2.size() + info3.size() + info4.size() + info5.size(), 1u);
}

//-----------------------------------------------------------------------------

TEST(MixedInnerProduct, use_dense_optimizers_when_possible) {
    // actually, all these trigger DenseXWProduct
    assert_dense_optimized("reduce(x3 * x3y1,sum,x)");
    assert_dense_optimized("reduce(y3 * x1y3,sum,y)");
    assert_dense_optimized("reduce(y3 * x3y3,sum,y)");
    assert_dense_optimized("reduce(x1y3 * y3,sum,y)");
    assert_dense_optimized("reduce(x3y3 * y3,sum,y)");
}

TEST(MixedInnerProduct, trigger_optimizer_when_possible) {
    assert_mixed_optimized("reduce(x3 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3 * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3f * mix_x3zm_f,sum,x)");
    assert_mixed_optimized("reduce(x3$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3f$2 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(y3 * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(y3f * mix_y3zm_f,sum,y)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x)");
    assert_mixed_optimized("reduce(x3y1 * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x3y1f * mix_x3zm,sum,x,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * x1y3f,sum,y)");
    assert_mixed_optimized("reduce(x1y3 * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(x1y3f * mix_y3zm,sum,y)");
    assert_mixed_optimized("reduce(mix_x3zm * x3,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3f,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1,sum,x)");
    assert_mixed_optimized("reduce(mix_x3zm * x3y1f,sum,x)");
    assert_mixed_optimized("reduce(mix_y3zm * y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * y3f,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3,sum,y)");
    assert_mixed_optimized("reduce(mix_y3zm * x1y3f,sum,y)");
}

TEST(MixedInnerProduct, should_not_trigger_optimizer_for_other_cases) {
    assert_not_mixed_optimized("reduce(x3y3z3 * x3,sum,x)");
    assert_not_mixed_optimized("reduce(x3y3z3 * y3,sum,y)");
    assert_not_mixed_optimized("reduce(x3y3z3 * x3y3,sum,x,y)");
    assert_not_mixed_optimized("reduce(x3y3 * mix_y3zm,sum,y)");
    assert_not_mixed_optimized("reduce(mix_y3zm * x3,sum,x,y)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,y,z)");
    assert_not_mixed_optimized("reduce(mix_x3y3zm * y3,sum,x,y)");
}

TEST(MixedInnerProduct, check_compatibility_with_complex_types) {
    ValueType vec_type = ValueType::from_spec("tensor<float>(f[1],g[2],i[1],x[3],y[1])");
    ValueType mix_type = ValueType::from_spec("tensor<double>(cat{},g[2],host{},k[1],x[3],z{})");
    ValueType res_type = ValueType::join(vec_type,mix_type).reduce({"g","k","i","x"});
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, mix_type, vec_type), true);
    EXPECT_EQ(MixedInnerProductFunction::compatible_types(res_type, vec_type, mix_type), false);
}

//-----------------------------------------------------------------------------

GTEST_MAIN_RUN_ALL_TESTS()
<|endoftext|>