<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/search_engines/template_url_fetcher.h"

#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_parser.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"

// RequestDelegate ------------------------------------------------------------
class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate,
                                            public NotificationObserver {
 public:
  RequestDelegate(TemplateURLFetcher* fetcher,
                  const std::wstring& keyword,
                  const GURL& osdd_url,
                  const GURL& favicon_url,
                  TabContents* source,
                  bool autodetected)
      : ALLOW_THIS_IN_INITIALIZER_LIST(url_fetcher_(osdd_url,
                                                    URLFetcher::GET, this)),
        fetcher_(fetcher),
        keyword_(keyword),
        osdd_url_(osdd_url),
        favicon_url_(favicon_url),
        autodetected_(autodetected),
        source_(source) {
    url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext());
    url_fetcher_.Start();
    registrar_.Add(this,
                   NotificationType::TAB_CONTENTS_DESTROYED,
                   Source<TabContents>(source_));
  }

  // URLFetcher::Delegate:
  // If data contains a valid OSDD, a TemplateURL is created and added to
  // the TemplateURLModel.
  virtual void OnURLFetchComplete(const URLFetcher* source,
                                  const GURL& url,
                                  const URLRequestStatus& status,
                                  int response_code,
                                  const ResponseCookies& cookies,
                                  const std::string& data);

  // NotificationObserver:
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
    DCHECK(source == Source<TabContents>(source_));
    source_ = NULL;
  }

  // URL of the OSDD.
  const GURL& url() const { return osdd_url_; }

  // Keyword to use.
  const std::wstring keyword() const { return keyword_; }

 private:
  URLFetcher url_fetcher_;
  TemplateURLFetcher* fetcher_;
  std::wstring keyword_;
  const GURL osdd_url_;
  const GURL favicon_url_;
  bool autodetected_;

  // The TabContents where this request originated. Can be NULL if the
  // originating tab is closed. If NULL, the engine is not added.
  TabContents* source_;

  // Handles registering for our notifications.
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(RequestDelegate);
};

void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
    const URLFetcher* source,
    const GURL& url,
    const URLRequestStatus& status,
    int response_code,
    const ResponseCookies& cookies,
    const std::string& data) {
  // Make sure we can still replace the keyword.
  if (response_code != 200) {
    fetcher_->RequestCompleted(this);
    // WARNING: RequestCompleted deletes us.
    return;
  }

  scoped_ptr<TemplateURL> template_url(new TemplateURL());
  if (TemplateURLParser::Parse(
          reinterpret_cast<const unsigned char*>(data.c_str()),
                                                 data.length(),
                                                 NULL,
                                                 template_url.get()) &&
      template_url->url() && template_url->url()->SupportsReplacement()) {
    if (!autodetected_ || keyword_.empty()) {
      // Generate new keyword from URL in OSDD for none autodetected case.
      // Previous keyword was generated from URL where OSDD was placed and
      // it gives wrong result when OSDD is located on third party site that
      // has nothing in common with search engine in OSDD.
      GURL keyword_url(WideToUTF16Hack(template_url->url()->url()));
      std::wstring new_keyword = TemplateURLModel::GenerateKeyword(
          keyword_url, false);
      if (!new_keyword.empty())
        keyword_ = new_keyword;
    }
    TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
    const TemplateURL* existing_url;
    if (keyword_.empty() ||
        !model || !model->loaded() ||
        !model->CanReplaceKeyword(keyword_, template_url->url()->url(),
                                  &existing_url)) {
      // TODO(pamg): If we're coming from JS (not autodetected) and this URL
      // already exists in the model, consider bringing up the
      // EditKeywordController to edit it.  This would be helpful feedback in
      // the case of clicking a button twice, and annoying in the case of a
      // page that calls AddSearchProvider() in JS without a user action.
      fetcher_->RequestCompleted(this);
      // WARNING: RequestCompleted deletes us.
      return;
    }

    if (existing_url)
      model->Remove(existing_url);

    // The short name is what is shown to the user. We preserve original names
    // since it is better when generated keyword in many cases.
    template_url->set_keyword(keyword_);
    template_url->set_originating_url(osdd_url_);

    // The page may have specified a URL to use for favicons, if not, set it.
    if (!template_url->GetFavIconURL().is_valid())
      template_url->SetFavIconURL(favicon_url_);

    if (autodetected_) {
      // Mark the keyword as replaceable so it can be removed if necessary.
      template_url->set_safe_for_autoreplace(true);
      model->Add(template_url.release());
    } else if (source_ && source_->delegate()) {
      // Confirm addition and allow user to edit default choices. It's ironic
      // that only *non*-autodetected additions get confirmed, but the user
      // expects feedback that his action did something.
      // The source TabContents' delegate takes care of adding the URL to the
      // model, which takes ownership, or of deleting it if the add is
      // cancelled.
      source_->delegate()->ConfirmAddSearchProvider(template_url.release(),
                                                    fetcher_->profile());
    }
  }
  fetcher_->RequestCompleted(this);
  // WARNING: RequestCompleted deletes us.
}

// TemplateURLFetcher ---------------------------------------------------------

TemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) {
  DCHECK(profile_);
}

TemplateURLFetcher::~TemplateURLFetcher() {
}

void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword,
                                          const GURL& osdd_url,
                                          const GURL& favicon_url,
                                          TabContents* source,
                                          bool autodetected) {
  DCHECK(!keyword.empty() && osdd_url.is_valid());
  // Make sure we aren't already downloading this request.
  for (std::vector<RequestDelegate*>::iterator i = requests_->begin();
       i != requests_->end(); ++i) {
    if ((*i)->url() == osdd_url || (*i)->keyword() == keyword)
      return;
  }

  requests_->push_back(
      new RequestDelegate(this, keyword, osdd_url, favicon_url, source,
                          autodetected));
}

void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
  DCHECK(find(requests_->begin(), requests_->end(), request) !=
         requests_->end());
  requests_->erase(find(requests_->begin(), requests_->end(), request));
  delete request;
}
<commit_msg>Always ask the user when adding a search engine from JS.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/search_engines/template_url_fetcher.h"

#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_parser.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/common/net/url_fetcher.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"

// RequestDelegate ------------------------------------------------------------
class TemplateURLFetcher::RequestDelegate : public URLFetcher::Delegate,
                                            public NotificationObserver {
 public:
  RequestDelegate(TemplateURLFetcher* fetcher,
                  const std::wstring& keyword,
                  const GURL& osdd_url,
                  const GURL& favicon_url,
                  TabContents* source,
                  bool autodetected)
      : ALLOW_THIS_IN_INITIALIZER_LIST(url_fetcher_(osdd_url,
                                                    URLFetcher::GET, this)),
        fetcher_(fetcher),
        keyword_(keyword),
        osdd_url_(osdd_url),
        favicon_url_(favicon_url),
        autodetected_(autodetected),
        source_(source) {
    url_fetcher_.set_request_context(fetcher->profile()->GetRequestContext());
    url_fetcher_.Start();
    registrar_.Add(this,
                   NotificationType::TAB_CONTENTS_DESTROYED,
                   Source<TabContents>(source_));
  }

  // URLFetcher::Delegate:
  // If data contains a valid OSDD, a TemplateURL is created and added to
  // the TemplateURLModel.
  virtual void OnURLFetchComplete(const URLFetcher* source,
                                  const GURL& url,
                                  const URLRequestStatus& status,
                                  int response_code,
                                  const ResponseCookies& cookies,
                                  const std::string& data);

  // NotificationObserver:
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::TAB_CONTENTS_DESTROYED);
    DCHECK(source == Source<TabContents>(source_));
    source_ = NULL;
  }

  // URL of the OSDD.
  const GURL& url() const { return osdd_url_; }

  // Keyword to use.
  const std::wstring keyword() const { return keyword_; }

 private:
  URLFetcher url_fetcher_;
  TemplateURLFetcher* fetcher_;
  std::wstring keyword_;
  const GURL osdd_url_;
  const GURL favicon_url_;
  bool autodetected_;

  // The TabContents where this request originated. Can be NULL if the
  // originating tab is closed. If NULL, the engine is not added.
  TabContents* source_;

  // Handles registering for our notifications.
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(RequestDelegate);
};

void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
    const URLFetcher* source,
    const GURL& url,
    const URLRequestStatus& status,
    int response_code,
    const ResponseCookies& cookies,
    const std::string& data) {
  // Make sure we can still replace the keyword.
  if (response_code != 200) {
    fetcher_->RequestCompleted(this);
    // WARNING: RequestCompleted deletes us.
    return;
  }

  scoped_ptr<TemplateURL> template_url(new TemplateURL());
  if (TemplateURLParser::Parse(
          reinterpret_cast<const unsigned char*>(data.c_str()),
                                                 data.length(),
                                                 NULL,
                                                 template_url.get()) &&
      template_url->url() && template_url->url()->SupportsReplacement()) {
    if (!autodetected_ || keyword_.empty()) {
      // Generate new keyword from URL in OSDD for none autodetected case.
      // Previous keyword was generated from URL where OSDD was placed and
      // it gives wrong result when OSDD is located on third party site that
      // has nothing in common with search engine in OSDD.
      GURL keyword_url(WideToUTF16Hack(template_url->url()->url()));
      std::wstring new_keyword = TemplateURLModel::GenerateKeyword(
          keyword_url, false);
      if (!new_keyword.empty())
        keyword_ = new_keyword;
    }
    TemplateURLModel* model = fetcher_->profile()->GetTemplateURLModel();
    const TemplateURL* existing_url;
    if (keyword_.empty() ||
        !model || !model->loaded() ||
        !model->CanReplaceKeyword(keyword_, template_url->url()->url(),
                                  &existing_url)) {
      if (autodetected_ || !model || !model->loaded()) {
        fetcher_->RequestCompleted(this);
        // WARNING: RequestCompleted deletes us.
        return;
      }
      // If we're coming from JS (neither autodetected nor failure to load the
      // template URL model) and this URL already exists in the model, we bring
      // up the EditKeywordController to edit it.  This is helpful feedback in
      // the case of clicking a button twice, and annoying in the case of a
      // page that calls AddSearchProvider() in JS without a user action.
      keyword_.clear();
      existing_url = NULL;
    }

    if (existing_url)
      model->Remove(existing_url);

    // The short name is what is shown to the user. We preserve original names
    // since it is better when generated keyword in many cases.
    template_url->set_keyword(keyword_);
    template_url->set_originating_url(osdd_url_);

    // The page may have specified a URL to use for favicons, if not, set it.
    if (!template_url->GetFavIconURL().is_valid())
      template_url->SetFavIconURL(favicon_url_);

    if (autodetected_) {
      // Mark the keyword as replaceable so it can be removed if necessary.
      template_url->set_safe_for_autoreplace(true);
      model->Add(template_url.release());
    } else if (source_ && source_->delegate()) {
      // Confirm addition and allow user to edit default choices. It's ironic
      // that only *non*-autodetected additions get confirmed, but the user
      // expects feedback that his action did something.
      // The source TabContents' delegate takes care of adding the URL to the
      // model, which takes ownership, or of deleting it if the add is
      // cancelled.
      source_->delegate()->ConfirmAddSearchProvider(template_url.release(),
                                                    fetcher_->profile());
    }
  }
  fetcher_->RequestCompleted(this);
  // WARNING: RequestCompleted deletes us.
}

// TemplateURLFetcher ---------------------------------------------------------

TemplateURLFetcher::TemplateURLFetcher(Profile* profile) : profile_(profile) {
  DCHECK(profile_);
}

TemplateURLFetcher::~TemplateURLFetcher() {
}

void TemplateURLFetcher::ScheduleDownload(const std::wstring& keyword,
                                          const GURL& osdd_url,
                                          const GURL& favicon_url,
                                          TabContents* source,
                                          bool autodetected) {
  DCHECK(!keyword.empty() && osdd_url.is_valid());
  // Make sure we aren't already downloading this request.
  for (std::vector<RequestDelegate*>::iterator i = requests_->begin();
       i != requests_->end(); ++i) {
    if ((*i)->url() == osdd_url || (*i)->keyword() == keyword)
      return;
  }

  requests_->push_back(
      new RequestDelegate(this, keyword, osdd_url, favicon_url, source,
                          autodetected));
}

void TemplateURLFetcher::RequestCompleted(RequestDelegate* request) {
  DCHECK(find(requests_->begin(), requests_->end(), request) !=
         requests_->end());
  requests_->erase(find(requests_->begin(), requests_->end(), request));
  delete request;
}
<|endoftext|>


<commit_before>// MGenTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "MGenTest.h"
#include "../MGen/GLibrary/GLib.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object

CWinApp theApp;

using namespace std;

CString current_dir;
ofstream logfile;
int ci = 0;
int nRetCode = 0;

void Run(CString fname, CString par, int delay) {
	SHELLEXECUTEINFO sei = { 0 };
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
	sei.hwnd = NULL;
	sei.lpVerb = NULL;
	sei.lpFile = fname;
	sei.lpParameters = par;
	sei.lpDirectory = NULL;
	sei.nShow = SW_SHOWNORMAL;
	sei.hInstApp = NULL;
	ShellExecuteEx(&sei);
	WaitForSingleObject(sei.hProcess, delay);
}

void Log(CString st, int level = 0) {
	cout << st;
	logfile << st;
	if (ci && level > 0) {
		CString cat;
		if (level == 1) cat = "Information";
		if (level == 2) cat = "Warning";
		if (level == 3) cat = "Error";
		CString par = "AddMessage \"" + st + "\" -Category " + cat;
		Run("appveyor", par, 1000);
	}
}

CString file(CString fname) {
	CString st, st2;
	ifstream fs;
	// Check file exists
	if (!CGLib::fileExists(fname)) {
		cout << "Not found file " << fname << "\n";
	}
	fs.open(fname);
	char pch[2550];
	while (fs.good()) {
		// Get line
		fs.getline(pch, 2550);
		st2 = pch;
		if (st2 != "") {
			st += "- " + st2 + "\n";
		}
	}
	fs.close();
	return st;
}

void ClearBuffer() {
	fstream fs;
	fs.open("autotest\\buffer.log", ios::out);
	fs.close();
}

void PublishTest(CString tname, int result, int tpassed) {
	CString st;
	CString st2;
	st2.Format("%s: code %d in %d ms\n", tname, result, tpassed);
	if (result) {
		nRetCode = 2;
		Log(st2, 3);
	}
	else {
		Log(st2, 1);
	}

	// Show errors
	CString errors = file("autotest/buffer.log");
	cout << errors;

	if (ci) {
		CString cat = "Passed";
		if (result) cat = "Failed";
		st.Format("UpdateTest \"%s\" -Framework MSTest -FileName MGen.exe -Duration %d -Outcome %s -ErrorMessage \"%d\"", tname, tpassed, cat, result);
		Run("appveyor", st, 1000);
		// Send errors separately in case of command line overflow
		st.Format("UpdateTest \"%s\" -Framework MSTest -FileName MGen.exe -Duration %d -Outcome %s -ErrorMessage \"%d\" -ErrorStackTrace \"%s\"", tname, tpassed, cat, result, errors);
		Run("appveyor", st, 1000);
	}

}

void LoadConfig() {
	int time_start, time_stop;
	CString fname = "autotest\\test.txt";
	// Check file exists
	if (!CGLib::fileExists(fname)) {
		cout << "Not found file " << fname << "\n";
	}
	ifstream fs;
	fs.open(fname);
	DWORD ecode;
	CString st, st2;
	char pch[2550];
	int pos = 0;
	int passed;
	while (fs.good()) {
		fs.getline(pch, 2550);
		st = pch;
		pos = st.Find("#");
		if (pos != -1) st = st.Left(pos);
		st.Trim();
		if (st.GetLength()) {
			ClearBuffer();
			if (ci) Run("appveyor", "AddTest \"" + st + "\" -Framework MSTest -FileName MGen.exe -Outcome Running", 1000);
			Log("Starting test config: " + st + "\n");
			st2 = "-test " + st;
			SHELLEXECUTEINFO sei = { 0 };
			sei.cbSize = sizeof(SHELLEXECUTEINFO);
			sei.fMask = SEE_MASK_NOCLOSEPROCESS;
			sei.hwnd = NULL;
			sei.lpVerb = NULL;
			sei.lpFile = "MGen.exe";
			sei.lpParameters = st2;
			sei.lpDirectory = NULL;
			sei.nShow = SW_SHOW;
			sei.hInstApp = NULL;
			time_start = CGLib::time();
			ShellExecuteEx(&sei);
			if (WaitForSingleObject(sei.hProcess, 60000) == WAIT_TIMEOUT) {
				Log(st + ": Timeout waiting for process\n", 3);
				exit(1);
			}

			time_stop = CGLib::time();
			passed = time_stop - time_start;
			if (!(GetExitCodeProcess(sei.hProcess, &ecode))) ecode = 100;

			PublishTest(st, ecode, passed);
		}
	}
	fs.close();
}

int test() {
	if (getenv("APPVEYOR_PROJECT_NAME") != NULL) {
		ci = 1;
	}
	logfile.open("autotest\\test.log", ios_base::app);

	TCHAR buffer[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, buffer);
	current_dir = string(buffer).c_str();
	Log("Current dir: " + current_dir + "\n");

	LoadConfig();
	logfile.close();
	// Do not pause if continuous integration
	if (!ci) {
		cout << "Press any key to continue... ";
		_getch();
	}
	return 0;
}

int main()
{
    HMODULE hModule = ::GetModuleHandle(nullptr);

    if (hModule != nullptr)
    {
        // initialize MFC and print and error on failure
        if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
        {
            // TODO: change error code to suit your needs
            wprintf(L"Fatal Error: MFC initialization failed\n");
            nRetCode = 1;
        }
        else
        {
					test();
				}
    }
    else
    {
        // TODO: change error code to suit your needs
        wprintf(L"Fatal Error: GetModuleHandle failed\n");
        nRetCode = 1;
    }

    return nRetCode;
}
<commit_msg>MGenTest: Test GetExitCodeProcess<commit_after>// MGenTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "MGenTest.h"
#include "../MGen/GLibrary/GLib.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object

CWinApp theApp;

using namespace std;

CString current_dir;
ofstream logfile;
int ci = 0;
int nRetCode = 0;

void Run(CString fname, CString par, int delay) {
	SHELLEXECUTEINFO sei = { 0 };
	sei.cbSize = sizeof(SHELLEXECUTEINFO);
	sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
	sei.hwnd = NULL;
	sei.lpVerb = NULL;
	sei.lpFile = fname;
	sei.lpParameters = par;
	sei.lpDirectory = NULL;
	sei.nShow = SW_SHOWNORMAL;
	sei.hInstApp = NULL;
	ShellExecuteEx(&sei);
	WaitForSingleObject(sei.hProcess, delay);
}

void Log(CString st, int level = 0) {
	cout << st;
	logfile << st;
	if (ci && level > 0) {
		CString cat;
		if (level == 1) cat = "Information";
		if (level == 2) cat = "Warning";
		if (level == 3) cat = "Error";
		CString par = "AddMessage \"" + st + "\" -Category " + cat;
		Run("appveyor", par, 1000);
	}
}

CString file(CString fname) {
	CString st, st2;
	ifstream fs;
	// Check file exists
	if (!CGLib::fileExists(fname)) {
		cout << "Not found file " << fname << "\n";
	}
	fs.open(fname);
	char pch[2550];
	while (fs.good()) {
		// Get line
		fs.getline(pch, 2550);
		st2 = pch;
		if (st2 != "") {
			st += "- " + st2 + "\n";
		}
	}
	fs.close();
	return st;
}

void ClearBuffer() {
	fstream fs;
	fs.open("autotest\\buffer.log", ios::out);
	fs.close();
}

void PublishTest(CString tname, int result, int tpassed) {
	CString st;
	CString st2;
	st2.Format("%s: code %d in %d ms\n", tname, result, tpassed);
	if (result) {
		nRetCode = 2;
		Log(st2, 3);
	}
	else {
		Log(st2, 1);
	}

	// Show errors
	CString errors = file("autotest/buffer.log");
	cout << errors;

	if (ci) {
		CString cat = "Passed";
		if (result) cat = "Failed";
		st.Format("UpdateTest \"%s\" -Framework MSTest -FileName MGen.exe -Duration %d -Outcome %s -ErrorMessage \"%d\"", tname, tpassed, cat, result);
		Run("appveyor", st, 1000);
		// Send errors separately in case of command line overflow
		st.Format("UpdateTest \"%s\" -Framework MSTest -FileName MGen.exe -Duration %d -Outcome %s -ErrorMessage \"%d\" -ErrorStackTrace \"%s\"", tname, tpassed, cat, result, errors);
		Run("appveyor", st, 1000);
	}

}

void LoadConfig() {
	int time_start, time_stop;
	CString fname = "autotest\\test.txt";
	// Check file exists
	if (!CGLib::fileExists(fname)) {
		cout << "Not found file " << fname << "\n";
	}
	ifstream fs;
	fs.open(fname);
	DWORD ecode;
	CString st, st2;
	char pch[2550];
	int pos = 0;
	int passed;
	while (fs.good()) {
		fs.getline(pch, 2550);
		st = pch;
		pos = st.Find("#");
		if (pos != -1) st = st.Left(pos);
		st.Trim();
		if (st.GetLength()) {
			ClearBuffer();
			if (ci) Run("appveyor", "AddTest \"" + st + "\" -Framework MSTest -FileName MGen.exe -Outcome Running", 1000);
			Log("Starting test config: " + st + "\n");
			st2 = "-test " + st;
			SHELLEXECUTEINFO sei = { 0 };
			sei.cbSize = sizeof(SHELLEXECUTEINFO);
			sei.fMask = SEE_MASK_NOCLOSEPROCESS;
			sei.hwnd = NULL;
			sei.lpVerb = NULL;
			sei.lpFile = "cmd.exe";
			sei.lpParameters = "/c exit 22";
			sei.lpDirectory = NULL;
			sei.nShow = SW_SHOW;
			sei.hInstApp = NULL;
			time_start = CGLib::time();
			ShellExecuteEx(&sei);
			if (WaitForSingleObject(sei.hProcess, 60000) == WAIT_TIMEOUT) {
				Log(st + ": Timeout waiting for process\n", 3);
				exit(1);
			}

			time_stop = CGLib::time();
			passed = time_stop - time_start;
			if (!(GetExitCodeProcess(sei.hProcess, &ecode))) ecode = 100;

			PublishTest(st, ecode, passed);
		}
	}
	fs.close();
}

int test() {
	if (getenv("APPVEYOR_PROJECT_NAME") != NULL) {
		ci = 1;
	}
	logfile.open("autotest\\test.log", ios_base::app);

	TCHAR buffer[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, buffer);
	current_dir = string(buffer).c_str();
	Log("Current dir: " + current_dir + "\n");

	LoadConfig();
	logfile.close();
	// Do not pause if continuous integration
	if (!ci) {
		cout << "Press any key to continue... ";
		_getch();
	}
	return 0;
}

int main()
{
    HMODULE hModule = ::GetModuleHandle(nullptr);

    if (hModule != nullptr)
    {
        // initialize MFC and print and error on failure
        if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
        {
            // TODO: change error code to suit your needs
            wprintf(L"Fatal Error: MFC initialization failed\n");
            nRetCode = 1;
        }
        else
        {
					test();
				}
    }
    else
    {
        // TODO: change error code to suit your needs
        wprintf(L"Fatal Error: GetModuleHandle failed\n");
        nRetCode = 1;
    }

    return nRetCode;
}
<|endoftext|>


<commit_before>/*
  This is an example file shipped by 'Aleph - A Library for Exploring
  Persistent Homology'.

  This example demonstrates how to create random persistence diagrams
  that may be used to compare topological algorithms with each other,
  such as persistence indicator functions and Wasserstein distances.

  Demonstrated classes:

    - aleph::distances::Euclidean
    - aleph::geometry::BruteForce
    - aleph::PersistenceDiagram

  Demonstrated functions:

    - aleph::calculatePersistenceDiagrams
    - aleph::geometry::buildVietorisRipsComplex
    - aleph::geometry::makeSphere
    - aleph::geometry::makeTorus
    - aleph::geometry::sphereSampling
    - aleph::geometry::torusRejectionSampling

  Original author: Bastian Rieck
*/

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/SphereSampling.hh>
#include <aleph/geometry/TorusSampling.hh>
#include <aleph/geometry/VietorisRipsComplex.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
#include <random>
#include <sstream>
#include <vector>

#include <cmath>

#include <getopt.h>

// We first have to specify the data type of the persistence diagram,
// i.e. the type that is used by its individual points.
using DataType           = double;
using Distance           = aleph::geometry::distances::Euclidean<DataType>;
using PointCloud         = aleph::containers::PointCloud<DataType>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

/**
  Auxiliary function for creating a random persistence diagram. Points
  are drawn from a uniform distribution on [0,1]. The function ensures
  that all points are situated _above_ the diagonal.
*/

PersistenceDiagram createRandomPersistenceDiagram( unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<DataType> distribution( DataType(0), DataType( std::nextafter( DataType(1), std::numeric_limits<DataType>::max() ) ) );

  PersistenceDiagram D;

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );

    if( x > y )
      std::swap( x,y );

    D.add( x,y );
  }

  return D;
}

/**
  Auxiliary function for creating random persistence diagrams based on
  random samples from a box with a given length.

  Note that this function automatically handles Vietoris--Rips
  expansion.
*/

std::vector<PersistenceDiagram> createRandomBoxPersistenceDiagrams( DataType r, unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<DataType> distribution( DataType(0), DataType( std::nextafter( DataType(r), std::numeric_limits<DataType>::max() ) ) );

  PointCloud pointCloud( n, 3 );

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );
    auto z = distribution( rng );

    std::vector<DataType> p = {x,y,z};
    pointCloud.set(i, p.begin(), p.end() );
  }

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, 0.7 * r, 3 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  for( auto&& diagram : diagrams )
    diagram.removeDiagonal();

  return diagrams;
}

/**
  Auxiliary function for creating a random persistence diagram based on
  random samples from a torus. The torus is described by two radii, one
  for the outer part, the other for the inner part.

  Due to the sampling technique used, the specified number is merely an
  upper bound for the number of points that are to be sampled. Moreover
  the function will automatically handle Vietoris--Rips expansion.
*/

PersistenceDiagram createRandomTorusPersistenceDiagram( DataType R, DataType r, unsigned n )
{
  auto pointCloud = aleph::geometry::makeTorus(
    aleph::geometry::torusRejectionSampling( R, r, n ),
    R, r
  );

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, r, 2 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  diagrams.at(1).removeDiagonal();

  // We are only interested in the one-dimensional persistent homology
  // of the samples.
  return diagrams.at(1);
}

/**
  Auxiliary function for creating a random persistence diagram based on
  random samples from a sphere with a given radius.

  Note that this function automatically handles Vietoris--Rips
  expansion.
*/

PersistenceDiagram createRandomSpherePersistenceDiagram( DataType r, unsigned n )
{
  auto pointCloud = aleph::geometry::makeSphere(
    aleph::geometry::sphereSampling<DataType>( n ),
    r
  );

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, r, 2 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  diagrams.at(1).removeDiagonal();

  // We are only interested in the one-dimensional persistent homology
  // of the samples.
  return diagrams.at(1);
}

int main( int argc, char** argv )
{
  static option commandLineOptions[] = {
      { "m"     , required_argument, nullptr, 'm' },
      { "n"     , required_argument, nullptr, 'n' },
      { "R"     , required_argument, nullptr, 'R' },
      { "r"     , required_argument, nullptr, 'r' },
      { "box"   , no_argument      , nullptr, 'b' },
      { "sphere", no_argument      , nullptr, 's' },
      { "torus" , no_argument      , nullptr, 't' },
      { "output", no_argument      , nullptr, 'o' },
      { nullptr , 0                , nullptr,  0  }
  };

  unsigned m            = 50;
  unsigned n            = 50;
  DataType R            = DataType(0.25);
  DataType r            = DataType(0.50);

  bool sampleFromBox    = false;
  bool sampleFromSphere = false;
  bool sampleFromTorus  = false;

  bool output           = false;

  int option = 0;
  while( ( option = getopt_long( argc, argv, "m:n:R:r:bsto", commandLineOptions, nullptr ) ) != -1 )
  {
    switch( option )
    {
    case 'm':
      m = static_cast<unsigned>( std::stoul(optarg) );
      break;
    case 'n':
      n = static_cast<unsigned>( std::stoul(optarg) );
      break;
    case 'R':
      R = static_cast<DataType>( std::stod(optarg) );
      break;
    case 'r':
      r = static_cast<DataType>( std::stod(optarg) );
      break;
    case 'b':
      sampleFromBox    = true;
      sampleFromSphere = false;
      sampleFromTorus  = false;
      break;
    case 's':
      sampleFromBox    = false;
      sampleFromSphere = true;
      sampleFromTorus  = false;
      break;
    case 't':
      sampleFromBox    = false;
      sampleFromSphere = false;
      sampleFromTorus  = true;
      break;
    case 'o':
      output = true;
      break;
    default:
      break;
    }
  }

  std::cerr << "* Sampling " << n << " persistence diagrams\n";
  if( sampleFromBox )
    std::cerr << "* Sampling " << m << " points from a box with a=" << r << "\n";
  else if( sampleFromSphere )
    std::cerr << "* Sampling " << m << " points from a sphere with r=" << r << "\n";
  else if( sampleFromTorus )
    std::cerr << "* Sampling " << m << " points from a torus with R=" << R << " and r=" << r << "\n";
  else
    std::cerr << "* Generating " << m << " random points per diagram\n";

  for( unsigned i = 0; i < n; i++ )
  {
    std::vector<PersistenceDiagram> pds;
    PersistenceDiagram pd;

    if( sampleFromBox )
      pds = createRandomBoxPersistenceDiagrams(r,m);
    else if( sampleFromSphere )
      pd = createRandomSpherePersistenceDiagram(r, m);
    else if( sampleFromTorus )
      pd = createRandomTorusPersistenceDiagram(R, r, m);
    else
      pd = createRandomPersistenceDiagram(m);

    if( output )
    {
      if( !pds.empty() )
      {
        for( auto&& pd : pds )
        {
          std::stringstream stream;
          stream << "/tmp/";
          stream << std::setw( static_cast<int>( std::floor( std::log10(n)+1 ) ) ) << std::setfill( '0' ) << i << "_d" << pd.dimension();
          stream << ".txt";

          std::ofstream out( stream.str() );
          out << pd << "\n";
        }
      }
      else
      {
        std::stringstream stream;
        stream << "/tmp/";
        stream << std::setw( static_cast<int>( std::floor( std::log10(n)+1 ) ) ) << std::setfill( '0' ) << i;
        stream << ".txt";

        std::ofstream out( stream.str() );
        out << pd << "\n";
      }
    }
  }
}
<commit_msg>Changed default values for torus sampling<commit_after>/*
  This is an example file shipped by 'Aleph - A Library for Exploring
  Persistent Homology'.

  This example demonstrates how to create random persistence diagrams
  that may be used to compare topological algorithms with each other,
  such as persistence indicator functions and Wasserstein distances.

  Demonstrated classes:

    - aleph::distances::Euclidean
    - aleph::geometry::BruteForce
    - aleph::PersistenceDiagram

  Demonstrated functions:

    - aleph::calculatePersistenceDiagrams
    - aleph::geometry::buildVietorisRipsComplex
    - aleph::geometry::makeSphere
    - aleph::geometry::makeTorus
    - aleph::geometry::sphereSampling
    - aleph::geometry::torusRejectionSampling

  Original author: Bastian Rieck
*/

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/SphereSampling.hh>
#include <aleph/geometry/TorusSampling.hh>
#include <aleph/geometry/VietorisRipsComplex.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/persistenceDiagrams/PersistenceDiagram.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <iostream>
#include <iomanip>
#include <fstream>
#include <limits>
#include <random>
#include <sstream>
#include <vector>

#include <cmath>

#include <getopt.h>

// We first have to specify the data type of the persistence diagram,
// i.e. the type that is used by its individual points.
using DataType           = double;
using Distance           = aleph::geometry::distances::Euclidean<DataType>;
using PointCloud         = aleph::containers::PointCloud<DataType>;
using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;

/**
  Auxiliary function for creating a random persistence diagram. Points
  are drawn from a uniform distribution on [0,1]. The function ensures
  that all points are situated _above_ the diagonal.
*/

PersistenceDiagram createRandomPersistenceDiagram( unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<DataType> distribution( DataType(0), DataType( std::nextafter( DataType(1), std::numeric_limits<DataType>::max() ) ) );

  PersistenceDiagram D;

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );

    if( x > y )
      std::swap( x,y );

    D.add( x,y );
  }

  return D;
}

/**
  Auxiliary function for creating random persistence diagrams based on
  random samples from a box with a given length.

  Note that this function automatically handles Vietoris--Rips
  expansion.
*/

std::vector<PersistenceDiagram> createRandomBoxPersistenceDiagrams( DataType r, unsigned n )
{
  std::random_device rd;
  std::default_random_engine rng( rd() );
  std::uniform_real_distribution<DataType> distribution( DataType(0), DataType( std::nextafter( DataType(r), std::numeric_limits<DataType>::max() ) ) );

  PointCloud pointCloud( n, 3 );

  for( unsigned i = 0; i < n; i++ )
  {
    auto x = distribution( rng );
    auto y = distribution( rng );
    auto z = distribution( rng );

    std::vector<DataType> p = {x,y,z};
    pointCloud.set(i, p.begin(), p.end() );
  }

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, 0.7 * r, 3 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  for( auto&& diagram : diagrams )
    diagram.removeDiagonal();

  return diagrams;
}

/**
  Auxiliary function for creating a random persistence diagram based on
  random samples from a torus. The torus is described by two radii, one
  for the outer part, the other for the inner part.

  Due to the sampling technique used, the specified number is merely an
  upper bound for the number of points that are to be sampled. Moreover
  the function will automatically handle Vietoris--Rips expansion.
*/

PersistenceDiagram createRandomTorusPersistenceDiagram( DataType R, DataType r, unsigned n )
{
  auto pointCloud = aleph::geometry::makeTorus(
    aleph::geometry::torusRejectionSampling( R, r, n ),
    R, r
  );

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, r, 2 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  diagrams.at(1).removeDiagonal();

  // We are only interested in the one-dimensional persistent homology
  // of the samples.
  return diagrams.at(1);
}

/**
  Auxiliary function for creating a random persistence diagram based on
  random samples from a sphere with a given radius.

  Note that this function automatically handles Vietoris--Rips
  expansion.
*/

PersistenceDiagram createRandomSpherePersistenceDiagram( DataType r, unsigned n )
{
  auto pointCloud = aleph::geometry::makeSphere(
    aleph::geometry::sphereSampling<DataType>( n ),
    r
  );

  aleph::geometry::BruteForce<PointCloud, Distance> bruteForceWrapper( pointCloud );

  auto K
    = aleph::geometry::buildVietorisRipsComplex( bruteForceWrapper, r, 2 );

  auto diagrams
    = aleph::calculatePersistenceDiagrams( K );

  diagrams.at(1).removeDiagonal();

  // We are only interested in the one-dimensional persistent homology
  // of the samples.
  return diagrams.at(1);
}

int main( int argc, char** argv )
{
  static option commandLineOptions[] = {
      { "m"     , required_argument, nullptr, 'm' },
      { "n"     , required_argument, nullptr, 'n' },
      { "R"     , required_argument, nullptr, 'R' },
      { "r"     , required_argument, nullptr, 'r' },
      { "box"   , no_argument      , nullptr, 'b' },
      { "sphere", no_argument      , nullptr, 's' },
      { "torus" , no_argument      , nullptr, 't' },
      { "output", no_argument      , nullptr, 'o' },
      { nullptr , 0                , nullptr,  0  }
  };

  unsigned m            = 50;
  unsigned n            = 50;
  DataType R            = DataType(0.50);
  DataType r            = DataType(0.25);

  bool sampleFromBox    = false;
  bool sampleFromSphere = false;
  bool sampleFromTorus  = false;

  bool output           = false;

  int option = 0;
  while( ( option = getopt_long( argc, argv, "m:n:R:r:bsto", commandLineOptions, nullptr ) ) != -1 )
  {
    switch( option )
    {
    case 'm':
      m = static_cast<unsigned>( std::stoul(optarg) );
      break;
    case 'n':
      n = static_cast<unsigned>( std::stoul(optarg) );
      break;
    case 'R':
      R = static_cast<DataType>( std::stod(optarg) );
      break;
    case 'r':
      r = static_cast<DataType>( std::stod(optarg) );
      break;
    case 'b':
      sampleFromBox    = true;
      sampleFromSphere = false;
      sampleFromTorus  = false;
      break;
    case 's':
      sampleFromBox    = false;
      sampleFromSphere = true;
      sampleFromTorus  = false;
      break;
    case 't':
      sampleFromBox    = false;
      sampleFromSphere = false;
      sampleFromTorus  = true;
      break;
    case 'o':
      output = true;
      break;
    default:
      break;
    }
  }

  std::cerr << "* Sampling " << n << " persistence diagrams\n";
  if( sampleFromBox )
    std::cerr << "* Sampling " << m << " points from a box with a=" << r << "\n";
  else if( sampleFromSphere )
    std::cerr << "* Sampling " << m << " points from a sphere with r=" << r << "\n";
  else if( sampleFromTorus )
    std::cerr << "* Sampling " << m << " points from a torus with R=" << R << " and r=" << r << "\n";
  else
    std::cerr << "* Generating " << m << " random points per diagram\n";

  for( unsigned i = 0; i < n; i++ )
  {
    std::vector<PersistenceDiagram> pds;
    PersistenceDiagram pd;

    if( sampleFromBox )
      pds = createRandomBoxPersistenceDiagrams(r,m);
    else if( sampleFromSphere )
      pd = createRandomSpherePersistenceDiagram(r, m);
    else if( sampleFromTorus )
      pd = createRandomTorusPersistenceDiagram(R, r, m);
    else
      pd = createRandomPersistenceDiagram(m);

    if( output )
    {
      if( !pds.empty() )
      {
        for( auto&& pd : pds )
        {
          std::stringstream stream;
          stream << "/tmp/";
          stream << std::setw( static_cast<int>( std::floor( std::log10(n)+1 ) ) ) << std::setfill( '0' ) << i << "_d" << pd.dimension();
          stream << ".txt";

          std::ofstream out( stream.str() );
          out << pd << "\n";
        }
      }
      else
      {
        std::stringstream stream;
        stream << "/tmp/";
        stream << std::setw( static_cast<int>( std::floor( std::log10(n)+1 ) ) ) << std::setfill( '0' ) << i;
        stream << ".txt";

        std::ofstream out( stream.str() );
        out << pd << "\n";
      }
    }
  }
}
<|endoftext|>


<commit_before>
#include "config.h"

// system
#include <iostream>
#include <sstream>

// boost
#include <boost/filesystem.hpp>

// dune-common
#include <dune/common/exceptions.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/timer.hh>

// dune-grid
#include <dune/grid/io/file/vtk/vtkwriter.hh>

// dune-grid-multiscale
#include <dune/grid/part/leaf.hh>

// dune-fem
#include <dune/fem/misc/mpimanager.hh>
#include <dune/fem/space/common/functionspace.hh>

// dune-stuff
#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/grid/provider/cube.hh>
#include <dune/stuff/function/expression.hh>

// dune-detailed-discretizations
#include <dune/detailed/discretizations/discretefunctionspace/continuous/lagrange.hh>
#include <dune/detailed/discretizations/discretefunctionspace/sub/linear.hh>
#include <dune/detailed/discretizations/evaluation/local/binary/elliptic.hh>
#include <dune/detailed/discretizations/discreteoperator/local/codim0/integral.hh>
#include <dune/detailed/discretizations/evaluation/local/unary/scale.hh>
#include <dune/detailed/discretizations/discretefunctional/local/codim0/integral.hh>
#include <dune/detailed/discretizations/la/factory/eigen.hh>
#include <dune/detailed/discretizations/assembler/local/codim0/matrix.hh>
#include <dune/detailed/discretizations/assembler/local/codim0/vector.hh>
#include <dune/detailed/discretizations/assembler/system/constrained.hh>
#include <dune/detailed/discretizations/la/backend/solver/eigen.hh>
#include <dune/detailed/discretizations/discretefunction/default.hh>

const std::string id = "elliptic.continuousgalerkin";

/**
  \brief      Creates a parameter file if it does not exist.

              Nothing is done if the file already exists. If not, a parameter file will be created with all neccessary
              keys and values.
  \param[in]  filename
              (Relative) path to the file.
  **/
void ensureParamFile(std::string filename)
{
  // only write param file if there is none
  if (!boost::filesystem::exists(filename)) {
    std::ofstream file;
    file.open(filename);
    file << "[stuff.grid.provider.cube]" << std::endl;
    file << "level = 4" << std::endl;
    file << "filename = " << id << ".grid" << std::endl;
    file << "[diffusion]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression.0 = 1.0"  << std::endl;
    file << "expression.1 = 1.0"  << std::endl;
    file << "expression.2 = 1.0"  << std::endl;
    file << "[force]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression.0 = 1.0"  << std::endl;
    file << "expression.1 = 1.0"  << std::endl;
    file << "expression.2 = 1.0"  << std::endl;
    file << "[dirichlet]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression.0 = 0.0"  << std::endl;
    file << "expression.1 = 0.0"  << std::endl;
    file << "expression.2 = 0.0"  << std::endl;
    file << "[solver]" << std::endl;
    file << "maxIter = 5000"  << std::endl;
    file << "precision = 1e-12"  << std::endl;
    file << "[visualization]" << std::endl;
    file << "filename = " << id << ".solution"  << std::endl;
    file << "name = solution"  << std::endl;
    file.close();
  } // only write param file if there is none
} // void ensureParamFile()

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif

int main(int argc, char** argv)
{
  try {
    // mpi
    Dune::MPIManager::initialize(argc, argv);

    // parameter
    const std::string paramFilename = id + ".param";
    ensureParamFile(paramFilename);
    Dune::Stuff::Common::ExtendedParameterTree paramTree(argc, argv, paramFilename);

    // timer
    Dune::Timer timer;

    // grid
    std::cout << "setting up grid:" << std::endl;
    typedef Dune::Stuff::Grid::Provider::UnitCube<> GridProviderType;
    paramTree.assertSub(GridProviderType::id(), id);
    const GridProviderType gridProvider(paramTree.sub(GridProviderType::id()));
    typedef GridProviderType::GridType GridType;
    const GridType& grid = gridProvider.grid();
    typedef Dune::grid::Part::Leaf::Const< GridType > GridPartType;
    const GridPartType gridPart(grid);
    std::cout << "  took " << timer.elapsed() << " sec, has " << grid.size(0) << " entities" << std::endl;
    std::cout << "visualizing grid... " << std::flush;
    timer.reset();
    gridProvider.visualize(paramTree.sub(GridProviderType::id()).get("filename", id + ".grid"));
    std::cout << " done (took " << timer.elapsed() << " sek)" << std::endl;

    // spaces
    std::cout << "initializing spaces... " << std::flush;
    timer.reset();
    const int DUNE_UNUSED(dimDomain) = GridProviderType::dim;
    const int DUNE_UNUSED(dimRange) = 1;
    typedef double DomainFieldType;
    typedef double RangeFieldType;
    typedef Dune::FunctionSpace< DomainFieldType, RangeFieldType, dimDomain, dimRange > FunctionSpaceType;
    typedef Dune::Detailed::Discretizations::DiscreteFunctionSpace::Continuous::Lagrange< FunctionSpaceType, GridPartType, polOrder > TestSpaceType;
    const TestSpaceType testSpace(gridPart);
    typedef Dune::Detailed::Discretizations::DiscreteFunctionSpace::Sub::Linear::Dirichlet< TestSpaceType > AnsatzSpaceType;
    const AnsatzSpaceType ansatzSpace(testSpace);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // data
    std::cout << "initializing data functions... " << std::flush;
    timer.reset();
    typedef Dune::Stuff::Function::Expression< DomainFieldType, dimDomain, RangeFieldType, dimRange > DiffusionType;
    paramTree.assertSub("diffusion", id);
    const Dune::shared_ptr< const DiffusionType > diffusion(new DiffusionType(paramTree.sub("diffusion")));
    typedef DiffusionType ForceType;
    paramTree.assertSub("force", id);
    const Dune::shared_ptr< const ForceType > force(new ForceType(paramTree.sub("force")));
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // left hand side (operator)
    std::cout << "initializing operator and functional... " << std::flush;
    timer.reset();
    typedef Dune::Detailed::Discretizations::Evaluation::Local::Binary::Elliptic< FunctionSpaceType, DiffusionType > EllipticEvaluationType;
    const EllipticEvaluationType ellipticEvaluation(diffusion, paramTree.sub("diffusion").get("order", 0));
    typedef Dune::Detailed::Discretizations::DiscreteOperator::Local::Codim0::Integral< EllipticEvaluationType > EllipticOperatorType;
    const EllipticOperatorType ellipticOperator(ellipticEvaluation);
    // right hand side (functional)
    typedef Dune::Detailed::Discretizations::Evaluation::Local::Unary::Scale< FunctionSpaceType, ForceType > ProductEvaluationType;
    const ProductEvaluationType productEvaluation(force, paramTree.sub("force").get("order", 0));
    typedef Dune::Detailed::Discretizations::DiscreteFunctional::Local::Codim0::Integral< ProductEvaluationType > L2FunctionalType;
    const L2FunctionalType l2Functional(productEvaluation);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // system matrix and right hand side
    std::cout << "initializing matrix and vector containers..." << std::flush;
    timer.reset();
    typedef AnsatzSpaceType::PatternType PatternType;
    const Dune::shared_ptr< const PatternType > pattern = ansatzSpace.computePattern(testSpace);
    typedef Dune::Detailed::Discretizations::LA::Factory::Eigen< RangeFieldType > ContainerFactory;
    typedef ContainerFactory::SparseMatrixType MatrixBackendType;
    MatrixBackendType systemMatrix = ContainerFactory::createSparseMatrix(ansatzSpace.map().size(), testSpace.map().size(), *pattern);
    typedef ContainerFactory::DenseVectorType VectorBackendType;
    VectorBackendType rhs = ContainerFactory::createDenseVector(testSpace.map().size());
    VectorBackendType ret = ContainerFactory::createDenseVector(testSpace);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // assembler
    std::cout << "assembing system... " << std::flush;
    timer.reset();
    typedef Dune::Detailed::Discretizations::Assembler::Local::Codim0::Matrix< EllipticOperatorType > LocalMatrixAssemblerType;
    const LocalMatrixAssemblerType localmatrixAssembler(ellipticOperator);
    typedef Dune::Detailed::Discretizations::Assembler::Local::Codim0::Vector< L2FunctionalType > LocalVectorAssemblerType;
    const LocalVectorAssemblerType localVectorAssembler(l2Functional);
    typedef Dune::Detailed::Discretizations::Assembler::System::Constrained< AnsatzSpaceType, TestSpaceType > SystemAssemblerType;
    const SystemAssemblerType systemAssembler(ansatzSpace, testSpace);
    systemAssembler.assembleSystem(localmatrixAssembler, systemMatrix, localVectorAssembler, rhs);
    systemAssembler.applyConstraints(systemMatrix, rhs);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // solve system
    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::BicgstabIlut Solver;
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::BicgstabDiagonal Solver;
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::CgDiagonalUpper Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::CgDiagonalLower Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::SimplicialcholeskyUpper Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::SimplicialcholeskyLower Solver; // seems to produce strange results
    std::cout << "solving linear system (of size " << systemMatrix.rows() << "x" << systemMatrix.cols() << ")" << std::endl
              << "  using " << Solver::id << "... " << std::flush;
    paramTree.assertSub("solver", id);
    timer.reset();
    Solver::apply(
      systemMatrix,
      ret,
      rhs,
      paramTree.sub("solver").get("maxIter", 5000),
      paramTree.sub("solver").get("precision", 1e-12));
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // postprocess
    paramTree.assertSub("visualization");
    const std::string solutionName = paramTree.sub("visualization").get("name", "solution");
    const std::string solutionFilename = paramTree.sub("visualization").get("filename", id + ".solution");
    std::cout << "writing '" << solutionName << "' to '" << solutionFilename;
    if (dimDomain == 1)
      std::cout << ".vtp";
    else
      std::cout << ".vtu";
    std::cout << "'... " << std::flush;
    typedef Dune::Detailed::Discretizations::DiscreteFunction::Default< AnsatzSpaceType, VectorBackendType > DiscreteFunctionType;
    Dune::shared_ptr< DiscreteFunctionType > solution(new DiscreteFunctionType(ansatzSpace, ret, solutionName));
    typedef Dune::VTKWriter< AnsatzSpaceType::GridViewType > VTKWriterType;
    VTKWriterType vtkWriter(ansatzSpace.gridView());
    vtkWriter.addVertexData(solution);
    vtkWriter.write(solutionFilename);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // done
    return 0;
  } catch(Dune::Exception& e) {
    std::cerr << "Dune reported error: " << e.what() << std::endl;
  } catch(std::exception& e) {
    std::cerr << e.what() << std::endl;
  } catch( ... ) {
    std::cerr << "Unknown exception thrown!" << std::endl;
  } // try
} // main
<commit_msg>[examples.elliptic.cg] update<commit_after>
#include "config.h"

// system
#include <iostream>
#include <sstream>

// boost
#include <boost/filesystem.hpp>

// dune-common
#include <dune/common/exceptions.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/timer.hh>

// dune-grid
#include <dune/grid/io/file/vtk/vtkwriter.hh>

// dune-grid-multiscale
#include <dune/grid/part/leaf.hh>

// dune-fem
#include <dune/fem/misc/mpimanager.hh>
#include <dune/fem/space/common/functionspace.hh>

// dune-stuff
#include <dune/stuff/common/parameter/tree.hh>
#include <dune/stuff/grid/provider/cube.hh>
#include <dune/stuff/function/expression.hh>

// dune-detailed-discretizations
#include <dune/detailed/discretizations/discretefunctionspace/continuous/lagrange.hh>
#include <dune/detailed/discretizations/discretefunctionspace/sub/linear.hh>
#include <dune/detailed/discretizations/evaluation/local/binary/elliptic.hh>
#include <dune/detailed/discretizations/discreteoperator/local/codim0/integral.hh>
#include <dune/detailed/discretizations/evaluation/local/unary/scale.hh>
#include <dune/detailed/discretizations/discretefunctional/local/codim0/integral.hh>
#include <dune/detailed/discretizations/la/factory/eigen.hh>
#include <dune/detailed/discretizations/assembler/local/codim0/matrix.hh>
#include <dune/detailed/discretizations/assembler/local/codim0/vector.hh>
#include <dune/detailed/discretizations/assembler/system/constrained.hh>
#include <dune/detailed/discretizations/la/backend/solver/eigen.hh>
#include <dune/detailed/discretizations/discretefunction/default.hh>

const std::string id = "elliptic.continuousgalerkin";

/**
  \brief      Creates a parameter file if it does not exist.

              Nothing is done if the file already exists. If not, a parameter file will be created with all neccessary
              keys and values.
  \param[in]  filename
              (Relative) path to the file.
  **/
void ensureParamFile(std::string filename)
{
  // only write param file if there is none
  if (!boost::filesystem::exists(filename)) {
    std::ofstream file;
    file.open(filename);
    file << "[stuff.grid.provider.cube]" << std::endl;
    file << "numElements = 4" << std::endl;
    file << "filename = " << id << ".grid" << std::endl;
    file << "[diffusion]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[force]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [1.0; 1.0; 1.0]" << std::endl;
    file << "[dirichlet]" << std::endl;
    file << "order = 0"  << std::endl;
    file << "variable = x" << std::endl;
    file << "expression = [0.0; 0.0; 0.0]" << std::endl;
    file << "[solver]" << std::endl;
    file << "maxIter = 5000"  << std::endl;
    file << "precision = 1e-12"  << std::endl;
    file << "[visualization]" << std::endl;
    file << "filename = " << id << ".solution" << std::endl;
    file << "name = solution" << std::endl;
    file.close();
  } // only write param file if there is none
} // void ensureParamFile()

#ifndef POLORDER
const int polOrder = 1;
#else
const int polOrder = POLORDER;
#endif

int main(int argc, char** argv)
{
  try {
    // mpi
    Dune::MPIManager::initialize(argc, argv);

    // parameter
    const std::string paramFilename = id + ".param";
    ensureParamFile(paramFilename);
    Dune::Stuff::Common::ExtendedParameterTree paramTree(argc, argv, paramFilename);

    // timer
    Dune::Timer timer;

    // grid
    std::cout << "setting up grid:" << std::endl;
    typedef Dune::Stuff::Grid::Provider::Cube<> GridProviderType;
    paramTree.assertSub(GridProviderType::id(), id);
    const GridProviderType gridProvider(paramTree.sub(GridProviderType::id()));
    typedef GridProviderType::GridType GridType;
    const GridType& grid = gridProvider.grid();
    typedef Dune::grid::Part::Leaf::Const< GridType > GridPartType;
    const GridPartType gridPart(grid);
    std::cout << "  took " << timer.elapsed() << " sec, has " << grid.size(0) << " entities" << std::endl;
    std::cout << "visualizing grid... " << std::flush;
    timer.reset();
    gridProvider.visualize(paramTree.sub(GridProviderType::id()).get("filename", id + ".grid"));
    std::cout << " done (took " << timer.elapsed() << " sek)" << std::endl;

    // spaces
    std::cout << "initializing spaces... " << std::flush;
    timer.reset();
    const int DUNE_UNUSED(dimDomain) = GridProviderType::dim;
    const int DUNE_UNUSED(dimRange) = 1;
    typedef double DomainFieldType;
    typedef double RangeFieldType;
    typedef Dune::FunctionSpace< DomainFieldType, RangeFieldType, dimDomain, dimRange > FunctionSpaceType;
    typedef Dune::Detailed::Discretizations::DiscreteFunctionSpace::Continuous::Lagrange< FunctionSpaceType, GridPartType, polOrder > TestSpaceType;
    const TestSpaceType testSpace(gridPart);
    typedef Dune::Detailed::Discretizations::DiscreteFunctionSpace::Sub::Linear::Dirichlet< TestSpaceType > AnsatzSpaceType;
    const AnsatzSpaceType ansatzSpace(testSpace);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // data
    std::cout << "initializing data functions... " << std::flush;
    timer.reset();
    typedef Dune::Stuff::Function::Expression< DomainFieldType, dimDomain, RangeFieldType, dimRange > DiffusionType;
    paramTree.assertSub("diffusion", id);
    const Dune::shared_ptr< const DiffusionType > diffusion(new DiffusionType(paramTree.sub("diffusion")));
    typedef DiffusionType ForceType;
    paramTree.assertSub("force", id);
    const Dune::shared_ptr< const ForceType > force(new ForceType(paramTree.sub("force")));
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // left hand side (operator)
    std::cout << "initializing operator and functional... " << std::flush;
    timer.reset();
    typedef Dune::Detailed::Discretizations::Evaluation::Local::Binary::Elliptic< FunctionSpaceType, DiffusionType > EllipticEvaluationType;
    const EllipticEvaluationType ellipticEvaluation(diffusion, paramTree.sub("diffusion").get("order", 0));
    typedef Dune::Detailed::Discretizations::DiscreteOperator::Local::Codim0::Integral< EllipticEvaluationType > EllipticOperatorType;
    const EllipticOperatorType ellipticOperator(ellipticEvaluation);
    // right hand side (functional)
    typedef Dune::Detailed::Discretizations::Evaluation::Local::Unary::Scale< FunctionSpaceType, ForceType > ProductEvaluationType;
    const ProductEvaluationType productEvaluation(force, paramTree.sub("force").get("order", 0));
    typedef Dune::Detailed::Discretizations::DiscreteFunctional::Local::Codim0::Integral< ProductEvaluationType > L2FunctionalType;
    const L2FunctionalType l2Functional(productEvaluation);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // system matrix and right hand side
    std::cout << "initializing matrix and vector containers..." << std::flush;
    timer.reset();
    typedef AnsatzSpaceType::PatternType PatternType;
    const Dune::shared_ptr< const PatternType > pattern = ansatzSpace.computePattern(testSpace);
    typedef Dune::Detailed::Discretizations::LA::Factory::Eigen< RangeFieldType > ContainerFactory;
    typedef ContainerFactory::SparseMatrixType MatrixBackendType;
    MatrixBackendType systemMatrix = ContainerFactory::createSparseMatrix(ansatzSpace.map().size(), testSpace.map().size(), *pattern);
    typedef ContainerFactory::DenseVectorType VectorBackendType;
    VectorBackendType rhs = ContainerFactory::createDenseVector(testSpace.map().size());
    VectorBackendType ret = ContainerFactory::createDenseVector(testSpace);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // assembler
    std::cout << "assembing system... " << std::flush;
    timer.reset();
    typedef Dune::Detailed::Discretizations::Assembler::Local::Codim0::Matrix< EllipticOperatorType > LocalMatrixAssemblerType;
    const LocalMatrixAssemblerType localmatrixAssembler(ellipticOperator);
    typedef Dune::Detailed::Discretizations::Assembler::Local::Codim0::Vector< L2FunctionalType > LocalVectorAssemblerType;
    const LocalVectorAssemblerType localVectorAssembler(l2Functional);
    typedef Dune::Detailed::Discretizations::Assembler::System::Constrained< AnsatzSpaceType, TestSpaceType > SystemAssemblerType;
    const SystemAssemblerType systemAssembler(ansatzSpace, testSpace);
    systemAssembler.assembleSystem(localmatrixAssembler, systemMatrix, localVectorAssembler, rhs);
    systemAssembler.applyConstraints(systemMatrix, rhs);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // solve system
    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::BicgstabIlut Solver;
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::BicgstabDiagonal Solver;
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::CgDiagonalUpper Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::CgDiagonalLower Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::SimplicialcholeskyUpper Solver; // seems to produce strange results
//    typedef Dune::Detailed::Discretizations::LA::Solver::Eigen::SimplicialcholeskyLower Solver; // seems to produce strange results
    std::cout << "solving linear system (of size " << systemMatrix.rows() << "x" << systemMatrix.cols() << ")" << std::endl
              << "  using " << Solver::id << "... " << std::flush;
    paramTree.assertSub("solver", id);
    timer.reset();
    Solver::apply(
      systemMatrix,
      ret,
      rhs,
      paramTree.sub("solver").get("maxIter", 5000),
      paramTree.sub("solver").get("precision", 1e-12));
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // postprocess
    paramTree.assertSub("visualization");
    const std::string solutionName = paramTree.sub("visualization").get("name", "solution");
    const std::string solutionFilename = paramTree.sub("visualization").get("filename", id + ".solution");
    std::cout << "writing '" << solutionName << "' to '" << solutionFilename;
    if (dimDomain == 1)
      std::cout << ".vtp";
    else
      std::cout << ".vtu";
    std::cout << "'... " << std::flush;
    typedef Dune::Detailed::Discretizations::DiscreteFunction::Default< AnsatzSpaceType, VectorBackendType > DiscreteFunctionType;
    Dune::shared_ptr< DiscreteFunctionType > solution(new DiscreteFunctionType(ansatzSpace, ret, solutionName));
    typedef Dune::VTKWriter< AnsatzSpaceType::GridViewType > VTKWriterType;
    VTKWriterType vtkWriter(ansatzSpace.gridView());
    vtkWriter.addVertexData(solution);
    vtkWriter.write(solutionFilename);
    std::cout << "done (took " << timer.elapsed() << " sec)" << std::endl;

    // done
    return 0;
  } catch(Dune::Exception& e) {
    std::cerr << "Dune reported error: " << e.what() << std::endl;
  } catch(std::exception& e) {
    std::cerr << e.what() << std::endl;
  } catch( ... ) {
    std::cerr << "Unknown exception thrown!" << std::endl;
  } // try
} // main
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

// SparseDenseBinaryOpShared is the shared code for binary coefficient-wise
// (cwise) operations of the following form:
//
//   sparse_t <binary cwise op> dense_t -> new sparse_t
//
// where:
//
//   (1) "binary cwise op" can be, for example, cdiv, cmul, cfloordiv, etc.
//   (2) LIMITATION: we only support broadcasting the dense side to the sparse
//       side.  In other words, NumDims(sparse_t) >= NumDims(dense_t), and if
//       they are equal, each dim size of sparse_t >= that of dense_t.
//   (3) Note that the result is a new sparse tensor, which means the implicitly
//       zero elements of sparse_t do not participate.  (Hence, this should not
//       be used for, say, cadd.)
//
// The only output is a vector of flat values with shape [nnz], since this op
// does not change neither the indices nor the shape of the sparse operand.
//
// See docs of all registered ops in ../ops/sparse_ops.cc.

#define EIGEN_USE_THREADS

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/kernels/cwise_ops.h"
#include "tensorflow/core/kernels/cwise_ops_common.h"
#include "tensorflow/core/util/bcast.h"

using Eigen::TensorRef;
using tensorflow::gtl::ArraySlice;

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T, typename Functor>
class SparseDenseBinaryOpShared : public OpKernel {
 public:
  explicit SparseDenseBinaryOpShared(OpKernelConstruction *ctx)
      : OpKernel(ctx) {}

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *dense_t;
    OP_REQUIRES_OK(ctx, ctx->input("sp_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("dense", &dense_t));

    // Validations.
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(indices_t->shape()),
                errors::InvalidArgument(
                    "Input sp_indices should be a matrix but received shape: ",
                    indices_t->shape().DebugString()));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(values_t->shape()) &&
                    TensorShapeUtils::IsVector(shape_t->shape()),
                errors::InvalidArgument(
                    "Inputs sp_values and sp_shape should be vectors "
                    "but received shapes: ",
                    values_t->shape().DebugString(), " and ",
                    shape_t->shape().DebugString()));
    OP_REQUIRES(ctx, indices_t->dim_size(0) < std::numeric_limits<int>::max(),
                errors::InvalidArgument(
                    "Number of non-zero elements exceeds int32 range"));

    const auto indices_mat = indices_t->matrix<int64>();
    const auto shape_vec = shape_t->vec<int64>();
    const auto lhs_dims = BCast::FromShape(TensorShape(shape_vec));
    const auto rhs_dims = BCast::FromShape(dense_t->shape());
    BCast b(lhs_dims, rhs_dims, false);  // false for keeping the same num dims.

    // True iff (size(lhs) >= size(rhs)) and all dims in lhs is smaller or equal to dims in rhs (from right to left).
    auto VecGreaterEq = [](ArraySlice<int64> lhs, ArraySlice<int64> rhs) {
      if (lhs.size() < rhs.size()) return false;
      for (size_t i = 0; i < rhs.size(); ++i) {
        if (lhs[lhs.size() - 1 - i] < rhs[rhs.size() - 1 - i]) return false;
      }
      return true;
    };
    OP_REQUIRES(ctx, VecGreaterEq(lhs_dims, rhs_dims) && b.IsValid(),
                errors::InvalidArgument(
                    "SparseDenseBinaryOpShared broadcasts dense to sparse "
                    "only; got incompatible shapes: [",
                    str_util::Join(lhs_dims, ","), "] vs. [",
                    str_util::Join(rhs_dims, ","), "]"));

    Tensor *output_values = nullptr;
    Tensor dense_gathered;
    const int nnz = static_cast<int>(indices_t->dim_size(0));
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(0, TensorShape({nnz}), &output_values));
    OP_REQUIRES_OK(
        ctx, ctx->allocate_temp(DataTypeToEnum<T>::value, TensorShape({nnz}),
                                &dense_gathered));

    // Pulls relevant entries from the dense side, with reshape and broadcasting
    // *of the dense side* taken into account.  Use a TensorRef to avoid blowing
    // up memory.
    //
    // We can directly use the sparse indices to look up dense side, because
    // "b.y_reshape()" and "b.y_bcast()" are guaranteed to have rank "ndims".
    auto dense_gathered_flat = dense_gathered.flat<T>();
    const int ndims = lhs_dims.size();
    switch (ndims) {
#define CASE(NDIM)                                                             \
  case NDIM: {                                                                 \
    TensorRef<Eigen::Tensor<const T, NDIM, Eigen::RowMajor>> rhs_ref =         \
        dense_t->shaped<T, NDIM>(b.y_reshape())                                \
            .broadcast(BCast::ToIndexArray<NDIM>(b.y_bcast()));                \
    Eigen::array<Eigen::DenseIndex, NDIM> idx;                                 \
    bool indices_valid = true;                                                 \
    for (int i = 0; i < nnz; ++i) {                                            \
      for (int d = 0; d < NDIM; ++d) {                                         \
        idx[d] = internal::SubtleMustCopy(indices_mat(i, d));                  \
        if (!FastBoundsCheck(idx[d], rhs_ref.dimension(d))) {                  \
          indices_valid = false;                                               \
        }                                                                      \
      }                                                                        \
      OP_REQUIRES(                                                             \
          ctx, indices_valid,                                                  \
          errors::InvalidArgument("Provided indices are out-of-bounds w.r.t. " \
                                  "dense side with broadcasted shape"));       \
      dense_gathered_flat(i) = rhs_ref.coeff(idx);                             \
    }                                                                          \
    break;                                                                     \
  }

      CASE(1);
      CASE(2);
      CASE(3);
      CASE(4);
      CASE(5);
      default:
        OP_REQUIRES(
            ctx, false,
            errors::InvalidArgument("Only tensors with ranks between 1 and 5 "
                                    "are currently supported.  Tensor rank: ",
                                    ndims));
#undef CASE
    }

    output_values->flat<T>().device(ctx->eigen_device<Device>()) =
        values_t->flat<T>().binaryExpr(dense_gathered_flat,
                                       typename Functor::func());
  }
};

// NOTE(aselle): If Div is extended to non-reals, make sure to use the same
// separation of operator semantics as done for dense cwise ops. I.e. you
// should make SparseDenseCwiseRealDiv, SparseDenseCwiseTruncateDiv,
// SparseDenseCwiseFloorDiv, and then deprecate, SparseDenseCwiseDiv.
// TODO(zongheng): extend to other eligible cwise operations as requested.
#define REGISTER_KERNELS(T)                                                  \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseMul").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::mul<T>>)              \
                                                                             \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseDiv").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::div<T>>)              \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseAdd").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::add<T>>)

TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace tensorflow
<commit_msg>Fix `Experimental clang-format Check`<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/

// SparseDenseBinaryOpShared is the shared code for binary coefficient-wise
// (cwise) operations of the following form:
//
//   sparse_t <binary cwise op> dense_t -> new sparse_t
//
// where:
//
//   (1) "binary cwise op" can be, for example, cdiv, cmul, cfloordiv, etc.
//   (2) LIMITATION: we only support broadcasting the dense side to the sparse
//       side.  In other words, NumDims(sparse_t) >= NumDims(dense_t), and if
//       they are equal, each dim size of sparse_t >= that of dense_t.
//   (3) Note that the result is a new sparse tensor, which means the implicitly
//       zero elements of sparse_t do not participate.  (Hence, this should not
//       be used for, say, cadd.)
//
// The only output is a vector of flat values with shape [nnz], since this op
// does not change neither the indices nor the shape of the sparse operand.
//
// See docs of all registered ops in ../ops/sparse_ops.cc.

#define EIGEN_USE_THREADS

#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/tensor_util.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/kernels/cwise_ops.h"
#include "tensorflow/core/kernels/cwise_ops_common.h"
#include "tensorflow/core/util/bcast.h"

using Eigen::TensorRef;
using tensorflow::gtl::ArraySlice;

namespace tensorflow {

typedef Eigen::ThreadPoolDevice CPUDevice;

template <typename Device, typename T, typename Functor>
class SparseDenseBinaryOpShared : public OpKernel {
 public:
  explicit SparseDenseBinaryOpShared(OpKernelConstruction *ctx)
      : OpKernel(ctx) {}

  void Compute(OpKernelContext *ctx) override {
    const Tensor *indices_t, *values_t, *shape_t, *dense_t;
    OP_REQUIRES_OK(ctx, ctx->input("sp_indices", &indices_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_values", &values_t));
    OP_REQUIRES_OK(ctx, ctx->input("sp_shape", &shape_t));
    OP_REQUIRES_OK(ctx, ctx->input("dense", &dense_t));

    // Validations.
    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(indices_t->shape()),
                errors::InvalidArgument(
                    "Input sp_indices should be a matrix but received shape: ",
                    indices_t->shape().DebugString()));
    OP_REQUIRES(ctx,
                TensorShapeUtils::IsVector(values_t->shape()) &&
                    TensorShapeUtils::IsVector(shape_t->shape()),
                errors::InvalidArgument(
                    "Inputs sp_values and sp_shape should be vectors "
                    "but received shapes: ",
                    values_t->shape().DebugString(), " and ",
                    shape_t->shape().DebugString()));
    OP_REQUIRES(ctx, indices_t->dim_size(0) < std::numeric_limits<int>::max(),
                errors::InvalidArgument(
                    "Number of non-zero elements exceeds int32 range"));

    const auto indices_mat = indices_t->matrix<int64>();
    const auto shape_vec = shape_t->vec<int64>();
    const auto lhs_dims = BCast::FromShape(TensorShape(shape_vec));
    const auto rhs_dims = BCast::FromShape(dense_t->shape());
    BCast b(lhs_dims, rhs_dims, false);  // false for keeping the same num dims.

    // True iff (size(lhs) >= size(rhs)) and all dims in lhs is smaller or equal
    // to dims in rhs (from right to left).
    auto VecGreaterEq = [](ArraySlice<int64> lhs, ArraySlice<int64> rhs) {
      if (lhs.size() < rhs.size()) return false;
      for (size_t i = 0; i < rhs.size(); ++i) {
        if (lhs[lhs.size() - 1 - i] < rhs[rhs.size() - 1 - i]) return false;
      }
      return true;
    };
    OP_REQUIRES(ctx, VecGreaterEq(lhs_dims, rhs_dims) && b.IsValid(),
                errors::InvalidArgument(
                    "SparseDenseBinaryOpShared broadcasts dense to sparse "
                    "only; got incompatible shapes: [",
                    str_util::Join(lhs_dims, ","), "] vs. [",
                    str_util::Join(rhs_dims, ","), "]"));

    Tensor *output_values = nullptr;
    Tensor dense_gathered;
    const int nnz = static_cast<int>(indices_t->dim_size(0));
    OP_REQUIRES_OK(ctx,
                   ctx->allocate_output(0, TensorShape({nnz}), &output_values));
    OP_REQUIRES_OK(
        ctx, ctx->allocate_temp(DataTypeToEnum<T>::value, TensorShape({nnz}),
                                &dense_gathered));

    // Pulls relevant entries from the dense side, with reshape and broadcasting
    // *of the dense side* taken into account.  Use a TensorRef to avoid blowing
    // up memory.
    //
    // We can directly use the sparse indices to look up dense side, because
    // "b.y_reshape()" and "b.y_bcast()" are guaranteed to have rank "ndims".
    auto dense_gathered_flat = dense_gathered.flat<T>();
    const int ndims = lhs_dims.size();
    switch (ndims) {
#define CASE(NDIM)                                                             \
  case NDIM: {                                                                 \
    TensorRef<Eigen::Tensor<const T, NDIM, Eigen::RowMajor>> rhs_ref =         \
        dense_t->shaped<T, NDIM>(b.y_reshape())                                \
            .broadcast(BCast::ToIndexArray<NDIM>(b.y_bcast()));                \
    Eigen::array<Eigen::DenseIndex, NDIM> idx;                                 \
    bool indices_valid = true;                                                 \
    for (int i = 0; i < nnz; ++i) {                                            \
      for (int d = 0; d < NDIM; ++d) {                                         \
        idx[d] = internal::SubtleMustCopy(indices_mat(i, d));                  \
        if (!FastBoundsCheck(idx[d], rhs_ref.dimension(d))) {                  \
          indices_valid = false;                                               \
        }                                                                      \
      }                                                                        \
      OP_REQUIRES(                                                             \
          ctx, indices_valid,                                                  \
          errors::InvalidArgument("Provided indices are out-of-bounds w.r.t. " \
                                  "dense side with broadcasted shape"));       \
      dense_gathered_flat(i) = rhs_ref.coeff(idx);                             \
    }                                                                          \
    break;                                                                     \
  }

      CASE(1);
      CASE(2);
      CASE(3);
      CASE(4);
      CASE(5);
      default:
        OP_REQUIRES(
            ctx, false,
            errors::InvalidArgument("Only tensors with ranks between 1 and 5 "
                                    "are currently supported.  Tensor rank: ",
                                    ndims));
#undef CASE
    }

    output_values->flat<T>().device(ctx->eigen_device<Device>()) =
        values_t->flat<T>().binaryExpr(dense_gathered_flat,
                                       typename Functor::func());
  }
};

// NOTE(aselle): If Div is extended to non-reals, make sure to use the same
// separation of operator semantics as done for dense cwise ops. I.e. you
// should make SparseDenseCwiseRealDiv, SparseDenseCwiseTruncateDiv,
// SparseDenseCwiseFloorDiv, and then deprecate, SparseDenseCwiseDiv.
// TODO(zongheng): extend to other eligible cwise operations as requested.
#define REGISTER_KERNELS(T)                                                  \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseMul").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::mul<T>>)              \
                                                                             \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseDiv").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::div<T>>)              \
  REGISTER_KERNEL_BUILDER(                                                   \
      Name("SparseDenseCwiseAdd").Device(DEVICE_CPU).TypeConstraint<T>("T"), \
      SparseDenseBinaryOpShared<CPUDevice, T, functor::add<T>>)

TF_CALL_REAL_NUMBER_TYPES(REGISTER_KERNELS);
#undef REGISTER_KERNELS

}  // namespace tensorflow
<|endoftext|>