<commit_before>// Copyright (c) 2011 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 "base/command_line.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/threading/platform_thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

using base::TimeDelta;

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
class TabSwitchingUITest : public UIPerfTest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void SetUp() {
    // Set the log_file_name_ path according to the selected browser_directory_.
    log_file_name_ = browser_directory_.AppendASCII("chrome_debug.log");

    // Set the log file path for the browser test.
    scoped_ptr<base::Environment> env(base::Environment::Create());
#if defined(OS_WIN)
    env->SetVar(env_vars::kLogFileName, WideToUTF8(log_file_name_.value()));
#else
    env->SetVar(env_vars::kLogFileName, log_file_name_.value());
#endif

    // Add the necessary arguments to Chrome's launch command for these tests.
    AddLaunchArguments();

    // Run the rest of the UITest initialization.
    UITest::SetUp();
  }

  static const int kNumCycles = 5;

  void PrintTimings(const char* label, TimeDelta timings[kNumCycles],
    bool important) {
      std::string times;
      for (int i = 0; i < kNumCycles; ++i)
        base::StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
      PrintResultList("times", "", label, times, "ms", important);
  }

  void RunTabSwitchingUITest(const char* label, bool important) {
    // Shut down from window UITest sets up automatically.
    UITest::TearDown();

    TimeDelta timings[kNumCycles];
    for (int i = 0; i < kNumCycles; ++i) {
      // Prepare for this test run.
      SetUp();

      // Create a browser proxy.
      browser_proxy_ = automation()->GetBrowserWindow(0);

      // Open all the tabs.
      int initial_tab_count = 0;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
      int new_tab_count = OpenTabs();
      int tab_count = -1;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&tab_count));
      ASSERT_EQ(initial_tab_count + new_tab_count, tab_count);

      // Switch linearly between tabs.
      ASSERT_TRUE(browser_proxy_->ActivateTab(0));
      int final_tab_count = 0;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
      for (int j = initial_tab_count; j < final_tab_count; ++j) {
        ASSERT_TRUE(browser_proxy_->ActivateTab(j));
        ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(j, 10000));
      }

      // Close the browser to force a dump of log.
      bool application_closed = false;
      EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

      // Open the corresponding log file and collect average from the
      // histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration.
      bool log_has_been_dumped = false;
      std::string contents;
      int max_tries = 20;
      do {
        log_has_been_dumped = file_util::ReadFileToString(log_file_name_,
                                                          &contents);
        if (!log_has_been_dumped)
          base::PlatformThread::Sleep(100);
      } while (!log_has_been_dumped && max_tries--);
      ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

      // Parse the contents to get average.
      int64 average = 0;
      const std::string average_str("average = ");
      std::string::size_type pos = contents.find(
          "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0);
      std::string::size_type comma_pos;
      std::string::size_type number_length;

      ASSERT_NE(pos, std::string::npos) <<
        "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" <<
        contents;

      // Get the average.
      pos = contents.find(average_str, pos);
      comma_pos = contents.find(",", pos);
      pos += average_str.length();
      number_length = comma_pos - pos;
      average = atoi(contents.substr(pos, number_length).c_str());

      // Print the average and standard deviation.
      timings[i] = TimeDelta::FromMilliseconds(average);

      // Clean up from the test run.
      UITest::TearDown();
    }
    PrintTimings(label, timings, important);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      bool success =
          browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      EXPECT_TRUE(success);
      if (success)
        number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  FilePath log_file_name_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  void AddLaunchArguments() {
    launch_arguments_.AppendSwitch(switches::kEnableLogging);
    launch_arguments_.AppendSwitch(switches::kDumpHistogramsOnExit);
    launch_arguments_.AppendSwitchASCII(switches::kLoggingLevel, "0");
  }

  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

#if defined(OS_WIN)
// Started failing with a webkit roll in r49936. See http://crbug.com/46751
#define MAYBE_TabSwitch FAILS_TabSwitch
#define MAYBE_TabSwitchRef FAILS_TabSwitchRef
#else
#define MAYBE_TabSwitch TabSwitch
#define MAYBE_TabSwitchRef TabSwitchRef
#endif

TEST_F(TabSwitchingUITest, MAYBE_TabSwitch) {
  RunTabSwitchingUITest("t", true);
}

TEST_F(TabSwitchingUITest, MAYBE_TabSwitchRef) {
  UseReferenceBuild();
  RunTabSwitchingUITest("t_ref", true);
}

}  // namespace
<commit_msg>Marking TabSwitch test as fails, it's currently taking ~1 hour to finish and fail. BUG=102162 TBR=nsylvain@chromium.org Review URL: http://codereview.chromium.org/8432007<commit_after>// Copyright (c) 2011 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 "base/command_line.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/threading/platform_thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

using base::TimeDelta;

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
class TabSwitchingUITest : public UIPerfTest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void SetUp() {
    // Set the log_file_name_ path according to the selected browser_directory_.
    log_file_name_ = browser_directory_.AppendASCII("chrome_debug.log");

    // Set the log file path for the browser test.
    scoped_ptr<base::Environment> env(base::Environment::Create());
#if defined(OS_WIN)
    env->SetVar(env_vars::kLogFileName, WideToUTF8(log_file_name_.value()));
#else
    env->SetVar(env_vars::kLogFileName, log_file_name_.value());
#endif

    // Add the necessary arguments to Chrome's launch command for these tests.
    AddLaunchArguments();

    // Run the rest of the UITest initialization.
    UITest::SetUp();
  }

  static const int kNumCycles = 5;

  void PrintTimings(const char* label, TimeDelta timings[kNumCycles],
    bool important) {
      std::string times;
      for (int i = 0; i < kNumCycles; ++i)
        base::StringAppendF(&times, "%.2f,", timings[i].InMillisecondsF());
      PrintResultList("times", "", label, times, "ms", important);
  }

  void RunTabSwitchingUITest(const char* label, bool important) {
    // Shut down from window UITest sets up automatically.
    UITest::TearDown();

    TimeDelta timings[kNumCycles];
    for (int i = 0; i < kNumCycles; ++i) {
      // Prepare for this test run.
      SetUp();

      // Create a browser proxy.
      browser_proxy_ = automation()->GetBrowserWindow(0);

      // Open all the tabs.
      int initial_tab_count = 0;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
      int new_tab_count = OpenTabs();
      int tab_count = -1;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&tab_count));
      ASSERT_EQ(initial_tab_count + new_tab_count, tab_count);

      // Switch linearly between tabs.
      ASSERT_TRUE(browser_proxy_->ActivateTab(0));
      int final_tab_count = 0;
      ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
      for (int j = initial_tab_count; j < final_tab_count; ++j) {
        ASSERT_TRUE(browser_proxy_->ActivateTab(j));
        ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(j, 10000));
      }

      // Close the browser to force a dump of log.
      bool application_closed = false;
      EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

      // Open the corresponding log file and collect average from the
      // histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration.
      bool log_has_been_dumped = false;
      std::string contents;
      int max_tries = 20;
      do {
        log_has_been_dumped = file_util::ReadFileToString(log_file_name_,
                                                          &contents);
        if (!log_has_been_dumped)
          base::PlatformThread::Sleep(100);
      } while (!log_has_been_dumped && max_tries--);
      ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

      // Parse the contents to get average.
      int64 average = 0;
      const std::string average_str("average = ");
      std::string::size_type pos = contents.find(
          "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0);
      std::string::size_type comma_pos;
      std::string::size_type number_length;

      ASSERT_NE(pos, std::string::npos) <<
        "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" <<
        contents;

      // Get the average.
      pos = contents.find(average_str, pos);
      comma_pos = contents.find(",", pos);
      pos += average_str.length();
      number_length = comma_pos - pos;
      average = atoi(contents.substr(pos, number_length).c_str());

      // Print the average and standard deviation.
      timings[i] = TimeDelta::FromMilliseconds(average);

      // Clean up from the test run.
      UITest::TearDown();
    }
    PrintTimings(label, timings, important);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      bool success =
          browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      EXPECT_TRUE(success);
      if (success)
        number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  FilePath log_file_name_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  void AddLaunchArguments() {
    launch_arguments_.AppendSwitch(switches::kEnableLogging);
    launch_arguments_.AppendSwitch(switches::kDumpHistogramsOnExit);
    launch_arguments_.AppendSwitchASCII(switches::kLoggingLevel, "0");
  }

  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

// This is failing, and taking forever to finish when doing so.
// http://crbug.com/102162

TEST_F(TabSwitchingUITest, FAILS_TabSwitch) {
  RunTabSwitchingUITest("t", true);
}

#if defined(OS_WIN)
// Started failing with a webkit roll in r49936. See http://crbug.com/46751
#define MAYBE_TabSwitchRef FAILS_TabSwitchRef
#else
#define MAYBE_TabSwitchRef TabSwitchRef
#endif

TEST_F(TabSwitchingUITest, MAYBE_TabSwitchRef) {
  UseReferenceBuild();
  RunTabSwitchingUITest("t_ref", true);
}

}  // namespace
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "fetch.h"

#include "akonadi.h"
#include "akonadiconnection.h"
#include "../../libs/imapparser_p.h"
#include "../../libs/protocol_p.h"
#include "response.h"
#include "storage/selectquerybuilder.h"
#include "resourceinterface.h"

#include <QtCore/QStringList>
#include <QtCore/QUuid>
#include <QtCore/QVariant>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQuery>

using namespace Akonadi;

Fetch::Fetch()
  : Handler(),
    mIsUidFetch( false ),
    mAllParts( false ),
    mCacheOnly( false )
{
}

Fetch::~Fetch()
{
}

bool Fetch::parseCommand( const QByteArray &line )
{
  // parse the command
  QByteArray buffer;
  int pos = ImapParser::parseString( line, buffer );

  // command
  pos = ImapParser::parseString( line, buffer, pos );
  if ( buffer == AKONADI_CMD_UID ) {
    mIsUidFetch = true;
    pos = ImapParser::parseString( line, buffer, pos );
  }

  // sequence set
  pos = ImapParser::parseSequenceSet( line, mSet, pos );
  if ( mSet.isEmpty() )
    return false;

  // macro vs. attribute list
  forever {
    pos = ImapParser::stripLeadingSpaces( line, pos );
    if ( pos >= line.count() )
      break;
    if ( line[pos] == '(' ) {
      pos = ImapParser::parseParenthesizedList( line, mAttrList, pos );
      break;
    } else {
      pos = ImapParser::parseString( line, buffer, pos );
      if ( buffer == AKONADI_PARAM_CACHEONLY ) {
        mCacheOnly = true;
      } else if ( buffer == AKONADI_PARAM_ALLATTRIBUTES ) {
        mAllParts = true; // ### temporary
      } else if ( buffer == AKONADI_PARAM_FULLPAYLOAD ) {
        mAllParts = true; // ### temporary;
        mAttrList << "RFC822"; // HACK: temporary workaround until we have support for detecting the availability of the full payload in the server
      }
      // IMAP compat stuff
      else if ( buffer == "ALL" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE" << "ENVELOPE";
      } else if ( buffer == "FULL" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE";
      } else if ( buffer == "FAST" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE" << "ENVELOPE" << "BODY";
      } else {
        return false;
      }
    }
  }

  return true;
}

bool Fetch::handleLine( const QByteArray& line )
{
  if ( !parseCommand( line ) )
    return failureResponse( "Unable to parse command" );

  triggerOnDemandFetch();

  // build item query
  QueryBuilder itemQuery;
  itemQuery.addTable( PimItem::tableName() );
  itemQuery.addTable( MimeType::tableName() );
  itemQuery.addTable( Location::tableName() );
  itemQuery.addTable( Resource::tableName() );
  itemQuery.addColumn( PimItem::idFullColumnName() );
  itemQuery.addColumn( PimItem::revFullColumnName() );
  itemQuery.addColumn( PimItem::remoteIdFullColumnName() );
  itemQuery.addColumn( MimeType::nameFullColumnName() );
  itemQuery.addColumn( Resource::nameFullColumnName() );
  itemQuery.addColumnCondition( PimItem::mimeTypeIdFullColumnName(), Query::Equals, MimeType::idFullColumnName() );
  itemQuery.addColumnCondition( PimItem::locationIdFullColumnName(), Query::Equals, Location::idFullColumnName() );
  itemQuery.addColumnCondition( Location::resourceIdFullColumnName(), Query::Equals, Resource::idFullColumnName() );
  imapSetToQuery( mSet, mIsUidFetch, itemQuery );
  itemQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );
  const int itemQueryIdColumn = 0;
  const int itemQueryRevColumn = 1;
  const int itemQueryRidColumn = 2;
  const int itemQueryMimeTypeColumn = 3;
  const int itemQueryResouceColumn = 4;

  if ( !itemQuery.exec() )
    return failureResponse( "Unable to list items" );
  itemQuery.query().next();

  // build flag query if needed
  QueryBuilder flagQuery;
  if ( mAttrList.contains( "FLAGS" ) || mAllParts ) {
    flagQuery.addTable( PimItem::tableName() );
    flagQuery.addTable( PimItemFlagRelation::tableName() );
    flagQuery.addTable( Flag::tableName() );
    flagQuery.addColumn( PimItem::idFullColumnName() );
    flagQuery.addColumn( Flag::nameFullColumnName() );
    flagQuery.addColumnCondition( PimItem::idFullColumnName(), Query::Equals, PimItemFlagRelation::leftFullColumnName() );
    flagQuery.addColumnCondition( Flag::idFullColumnName(), Query::Equals, PimItemFlagRelation::rightFullColumnName() );
    imapSetToQuery( mSet, mIsUidFetch, flagQuery );
    flagQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );

    if ( !flagQuery.exec() )
      return failureResponse( "Unable to retrieve item flags" );
    flagQuery.query().next();
  }
  const int flagQueryIdColumn = 0;
  const int flagQueryNameColumn = 1;

  // build part query if needed
  QueryBuilder partQuery;
  QStringList partList;
  foreach( const QByteArray &b, mAttrList ) {
    // filter out non-part attributes
    if ( b == "REV" || b == "FLAGS" || b == "UID" || b == "REMOTEID" || b.startsWith( "akonadi-" ) )
      continue;
    if ( b == "RFC822.SIZE" )
      partList << QString::fromLatin1( "RFC822" );
    else
      partList << QString::fromLatin1( b );
  }
  if ( !partList.isEmpty() || mAllParts || mAttrList.contains( "RFC822.SIZE" ) ) {
    partQuery = buildPartQuery( partList );
    if ( !partQuery.exec() )
      return failureResponse( "Unable to retrieve item parts" );
    partQuery.query().next();
  }
  const int partQueryIdColumn = 0;
  const int partQueryNameColumn = 1;
  const int partQueryDataColumn = 2;
  const int partQueryVersionColumn = 3;

  // fetch not yet cached item parts
  // TODO: I'm sure this can be done with a single query instead of manually
  DataStore *store = connection()->storageBackend();
  if ( !mCacheOnly && (!partList.isEmpty() || mAllParts) ) {
    while ( itemQuery.query().isValid() ) {
      const qint64 pimItemId = itemQuery.query().value( itemQueryIdColumn ).toLongLong();
      QStringList missingParts = partList;
      while ( partQuery.query().isValid() ) {
        const qint64 id = partQuery.query().value( partQueryIdColumn ).toLongLong();
        if ( id < pimItemId ) {
          partQuery.query().next();
          continue;
        } else if ( id > pimItemId ) {
          break;
        }
        const QString partName = partQuery.query().value( partQueryNameColumn ).toString();
        if ( partQuery.query().value( partQueryDataColumn ).toByteArray().isNull() ) {
          if ( mAllParts )
            missingParts << partName;
        } else {
          missingParts.removeAll( partName );
        }
        partQuery.query().next();
      }
      if ( !missingParts.isEmpty() ) {
        store->retrieveDataFromResource( pimItemId, itemQuery.query().value( itemQueryRidColumn ).toString().toUtf8(),
                                         itemQuery.query().value( itemQueryMimeTypeColumn ).toString().toUtf8(),
                                         itemQuery.query().value( itemQueryResouceColumn ).toString(), missingParts );
      }
      itemQuery.query().next();
    }

    // re-exec part query, rewind item query
    itemQuery.query().first();
    partQuery = buildPartQuery( partList );
    if ( !partQuery.exec() )
      return failureResponse( "Unable to retrieve item parts" );
    partQuery.query().next();
  }

  // build responses
  Response response;
  response.setUntagged();
  while ( itemQuery.query().isValid() ) {
    const qint64 pimItemId = itemQuery.query().value( itemQueryIdColumn ).toLongLong();
    const int pimItemRev = itemQuery.query().value( itemQueryRevColumn ).toInt();
    QList<QByteArray> attributes;
    attributes.append( "UID " + QByteArray::number( pimItemId ) );
    attributes.append( "REV " + QByteArray::number( pimItemRev ) );
    attributes.append( "REMOTEID " + ImapParser::quote( itemQuery.query().value( itemQueryRidColumn ).toString().toUtf8() ) );
    attributes.append( "MIMETYPE " + ImapParser::quote( itemQuery.query().value( itemQueryMimeTypeColumn ).toString().toUtf8() ) );

    if ( mAttrList.contains( "FLAGS" ) ) {
      QList<QByteArray> flags;
      while ( flagQuery.query().isValid() ) {
        const qint64 id = flagQuery.query().value( flagQueryIdColumn ).toLongLong();
        if ( id < pimItemId ) {
          flagQuery.query().next();
          continue;
        } else if ( id > pimItemId ) {
          break;
        }
        flags << flagQuery.query().value( flagQueryNameColumn ).toString().toUtf8();
        flagQuery.query().next();
      }
      attributes.append( "FLAGS (" + ImapParser::join( flags, " " ) + ')' );
    }

    while ( partQuery.query().isValid() ) {
      const qint64 id = partQuery.query().value( partQueryIdColumn ).toLongLong();
      if ( id < pimItemId ) {
        partQuery.query().next();
        continue;
      } else if ( id > pimItemId ) {
        break;
      }
      QByteArray partName = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
      QByteArray part = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
      QByteArray data = partQuery.query().value( partQueryDataColumn ).toByteArray();
      int version = partQuery.query().value( partQueryVersionColumn ).toInt();
      if ( version != 0 ) { // '0' is the default, so don't send it
        part += "[" + QByteArray::number( version ) + "]";
      }
      if ( data.isNull() ) {
        part += " NIL";
      } else if ( data.isEmpty() ) {
        part += " \"\"";
      } else {
        part += " {" + QByteArray::number( data.length() ) + "}\n";
        part += data;
      }
      // return only requested parts (when RFC822.SIZE is requested, RFC822 is retrieved, but should not be returned)
      if ( mAttrList.contains( partName ) || mAllParts )
        attributes << part;

      if ( partName == "RFC822" && mAttrList.contains( "RFC822.SIZE" ) )
        attributes.append( "RFC822.SIZE " + QByteArray::number( data.length() ) );

      partQuery.query().next();
    }

    // IMAP protocol violation: should actually be the sequence number
    QByteArray attr = QByteArray::number( pimItemId ) + " FETCH (";
    attr += ImapParser::join( attributes, " " ) + ')';
    response.setUntagged();
    response.setString( attr );
    emit responseAvailable( response );

    itemQuery.query().next();
  }

  // update atime
  updateItemAccessTime();

  response.setTag( tag() );
  response.setSuccess();
  if ( mIsUidFetch )
    response.setString( "UID FETCH completed" );
  else
    response.setString( "FETCH completed" );
  emit responseAvailable( response );
  deleteLater();
  return true;
}

void Fetch::updateItemAccessTime()
{
  QueryBuilder qb( QueryBuilder::Update );
  qb.addTable( PimItem::tableName() );
  qb.updateColumnValue( PimItem::atimeColumn(), QDateTime::currentDateTime() );
  imapSetToQuery( mSet, mIsUidFetch, qb );
  if ( !qb.exec() )
    qWarning() << "Unable to update item access time";
}

void Fetch::triggerOnDemandFetch()
{
  if ( mIsUidFetch || connection()->selectedCollection() <= 0 )
    return;
  Location loc = connection()->selectedLocation();
  // HACK: don't trigger on-demand syncing if the resource is the one triggering it
  if ( connection()->sessionId() == loc.resource().name().toLatin1() )
    return;
  DataStore *store = connection()->storageBackend();
  store->activeCachePolicy( loc );
  if ( !loc.cachePolicySyncOnDemand() )
    return;
  store->triggerCollectionSync( loc );
}

QueryBuilder Fetch::buildPartQuery( const QStringList &partList )
{
  QueryBuilder partQuery;
  if ( !partList.isEmpty() || mAllParts || mAttrList.contains( "RFC822.SIZE" ) ) {
    partQuery.addTable( PimItem::tableName() );
    partQuery.addTable( Part::tableName() );
    partQuery.addColumn( PimItem::idFullColumnName() );
    partQuery.addColumn( Part::nameFullColumnName() );
    partQuery.addColumn( Part::dataFullColumnName() );
    partQuery.addColumn( Part::versionFullColumnName() );
    partQuery.addColumnCondition( PimItem::idFullColumnName(), Query::Equals, Part::pimItemIdFullColumnName() );
    if ( !mAllParts )
      partQuery.addValueCondition( Part::nameFullColumnName(), Query::In, partList );
    imapSetToQuery( mSet, mIsUidFetch, partQuery );
    partQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );
  }
  return partQuery;
}
<commit_msg>Don't overwrite the part list, it might have content here already.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "fetch.h"

#include "akonadi.h"
#include "akonadiconnection.h"
#include "../../libs/imapparser_p.h"
#include "../../libs/protocol_p.h"
#include "response.h"
#include "storage/selectquerybuilder.h"
#include "resourceinterface.h"

#include <QtCore/QStringList>
#include <QtCore/QUuid>
#include <QtCore/QVariant>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>
#include <QtSql/QSqlQuery>

using namespace Akonadi;

Fetch::Fetch()
  : Handler(),
    mIsUidFetch( false ),
    mAllParts( false ),
    mCacheOnly( false )
{
}

Fetch::~Fetch()
{
}

bool Fetch::parseCommand( const QByteArray &line )
{
  // parse the command
  QByteArray buffer;
  int pos = ImapParser::parseString( line, buffer );

  // command
  pos = ImapParser::parseString( line, buffer, pos );
  if ( buffer == AKONADI_CMD_UID ) {
    mIsUidFetch = true;
    pos = ImapParser::parseString( line, buffer, pos );
  }

  // sequence set
  pos = ImapParser::parseSequenceSet( line, mSet, pos );
  if ( mSet.isEmpty() )
    return false;

  // macro vs. attribute list
  forever {
    pos = ImapParser::stripLeadingSpaces( line, pos );
    if ( pos >= line.count() )
      break;
    if ( line[pos] == '(' ) {
      QList<QByteArray> tmp;
      pos = ImapParser::parseParenthesizedList( line, tmp, pos );
      mAttrList += tmp;
      break;
    } else {
      pos = ImapParser::parseString( line, buffer, pos );
      if ( buffer == AKONADI_PARAM_CACHEONLY ) {
        mCacheOnly = true;
      } else if ( buffer == AKONADI_PARAM_ALLATTRIBUTES ) {
        mAllParts = true; // ### temporary
      } else if ( buffer == AKONADI_PARAM_FULLPAYLOAD ) {
        mAllParts = true; // ### temporary;
        mAttrList << "RFC822"; // HACK: temporary workaround until we have support for detecting the availability of the full payload in the server
      }
      // IMAP compat stuff
      else if ( buffer == "ALL" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE" << "ENVELOPE";
      } else if ( buffer == "FULL" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE";
      } else if ( buffer == "FAST" ) {
        mAttrList << "FLAGS" << "INTERNALDATE" << "RFC822.SIZE" << "ENVELOPE" << "BODY";
      } else {
        return false;
      }
    }
  }

  return true;
}

bool Fetch::handleLine( const QByteArray& line )
{
  if ( !parseCommand( line ) )
    return failureResponse( "Unable to parse command" );

  triggerOnDemandFetch();

  // build item query
  QueryBuilder itemQuery;
  itemQuery.addTable( PimItem::tableName() );
  itemQuery.addTable( MimeType::tableName() );
  itemQuery.addTable( Location::tableName() );
  itemQuery.addTable( Resource::tableName() );
  itemQuery.addColumn( PimItem::idFullColumnName() );
  itemQuery.addColumn( PimItem::revFullColumnName() );
  itemQuery.addColumn( PimItem::remoteIdFullColumnName() );
  itemQuery.addColumn( MimeType::nameFullColumnName() );
  itemQuery.addColumn( Resource::nameFullColumnName() );
  itemQuery.addColumnCondition( PimItem::mimeTypeIdFullColumnName(), Query::Equals, MimeType::idFullColumnName() );
  itemQuery.addColumnCondition( PimItem::locationIdFullColumnName(), Query::Equals, Location::idFullColumnName() );
  itemQuery.addColumnCondition( Location::resourceIdFullColumnName(), Query::Equals, Resource::idFullColumnName() );
  imapSetToQuery( mSet, mIsUidFetch, itemQuery );
  itemQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );
  const int itemQueryIdColumn = 0;
  const int itemQueryRevColumn = 1;
  const int itemQueryRidColumn = 2;
  const int itemQueryMimeTypeColumn = 3;
  const int itemQueryResouceColumn = 4;

  if ( !itemQuery.exec() )
    return failureResponse( "Unable to list items" );
  itemQuery.query().next();

  // build flag query if needed
  QueryBuilder flagQuery;
  if ( mAttrList.contains( "FLAGS" ) || mAllParts ) {
    flagQuery.addTable( PimItem::tableName() );
    flagQuery.addTable( PimItemFlagRelation::tableName() );
    flagQuery.addTable( Flag::tableName() );
    flagQuery.addColumn( PimItem::idFullColumnName() );
    flagQuery.addColumn( Flag::nameFullColumnName() );
    flagQuery.addColumnCondition( PimItem::idFullColumnName(), Query::Equals, PimItemFlagRelation::leftFullColumnName() );
    flagQuery.addColumnCondition( Flag::idFullColumnName(), Query::Equals, PimItemFlagRelation::rightFullColumnName() );
    imapSetToQuery( mSet, mIsUidFetch, flagQuery );
    flagQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );

    if ( !flagQuery.exec() )
      return failureResponse( "Unable to retrieve item flags" );
    flagQuery.query().next();
  }
  const int flagQueryIdColumn = 0;
  const int flagQueryNameColumn = 1;

  // build part query if needed
  QueryBuilder partQuery;
  QStringList partList;
  foreach( const QByteArray &b, mAttrList ) {
    // filter out non-part attributes
    if ( b == "REV" || b == "FLAGS" || b == "UID" || b == "REMOTEID" || b.startsWith( "akonadi-" ) )
      continue;
    if ( b == "RFC822.SIZE" )
      partList << QString::fromLatin1( "RFC822" );
    else
      partList << QString::fromLatin1( b );
  }
  if ( !partList.isEmpty() || mAllParts || mAttrList.contains( "RFC822.SIZE" ) ) {
    partQuery = buildPartQuery( partList );
    if ( !partQuery.exec() )
      return failureResponse( "Unable to retrieve item parts" );
    partQuery.query().next();
  }
  const int partQueryIdColumn = 0;
  const int partQueryNameColumn = 1;
  const int partQueryDataColumn = 2;
  const int partQueryVersionColumn = 3;

  // fetch not yet cached item parts
  // TODO: I'm sure this can be done with a single query instead of manually
  DataStore *store = connection()->storageBackend();
  if ( !mCacheOnly && (!partList.isEmpty() || mAllParts) ) {
    while ( itemQuery.query().isValid() ) {
      const qint64 pimItemId = itemQuery.query().value( itemQueryIdColumn ).toLongLong();
      QStringList missingParts = partList;
      while ( partQuery.query().isValid() ) {
        const qint64 id = partQuery.query().value( partQueryIdColumn ).toLongLong();
        if ( id < pimItemId ) {
          partQuery.query().next();
          continue;
        } else if ( id > pimItemId ) {
          break;
        }
        const QString partName = partQuery.query().value( partQueryNameColumn ).toString();
        if ( partQuery.query().value( partQueryDataColumn ).toByteArray().isNull() ) {
          if ( mAllParts )
            missingParts << partName;
        } else {
          missingParts.removeAll( partName );
        }
        partQuery.query().next();
      }
      if ( !missingParts.isEmpty() ) {
        store->retrieveDataFromResource( pimItemId, itemQuery.query().value( itemQueryRidColumn ).toString().toUtf8(),
                                         itemQuery.query().value( itemQueryMimeTypeColumn ).toString().toUtf8(),
                                         itemQuery.query().value( itemQueryResouceColumn ).toString(), missingParts );
      }
      itemQuery.query().next();
    }

    // re-exec part query, rewind item query
    itemQuery.query().first();
    partQuery = buildPartQuery( partList );
    if ( !partQuery.exec() )
      return failureResponse( "Unable to retrieve item parts" );
    partQuery.query().next();
  }

  // build responses
  Response response;
  response.setUntagged();
  while ( itemQuery.query().isValid() ) {
    const qint64 pimItemId = itemQuery.query().value( itemQueryIdColumn ).toLongLong();
    const int pimItemRev = itemQuery.query().value( itemQueryRevColumn ).toInt();
    QList<QByteArray> attributes;
    attributes.append( "UID " + QByteArray::number( pimItemId ) );
    attributes.append( "REV " + QByteArray::number( pimItemRev ) );
    attributes.append( "REMOTEID " + ImapParser::quote( itemQuery.query().value( itemQueryRidColumn ).toString().toUtf8() ) );
    attributes.append( "MIMETYPE " + ImapParser::quote( itemQuery.query().value( itemQueryMimeTypeColumn ).toString().toUtf8() ) );

    if ( mAttrList.contains( "FLAGS" ) ) {
      QList<QByteArray> flags;
      while ( flagQuery.query().isValid() ) {
        const qint64 id = flagQuery.query().value( flagQueryIdColumn ).toLongLong();
        if ( id < pimItemId ) {
          flagQuery.query().next();
          continue;
        } else if ( id > pimItemId ) {
          break;
        }
        flags << flagQuery.query().value( flagQueryNameColumn ).toString().toUtf8();
        flagQuery.query().next();
      }
      attributes.append( "FLAGS (" + ImapParser::join( flags, " " ) + ')' );
    }

    while ( partQuery.query().isValid() ) {
      const qint64 id = partQuery.query().value( partQueryIdColumn ).toLongLong();
      if ( id < pimItemId ) {
        partQuery.query().next();
        continue;
      } else if ( id > pimItemId ) {
        break;
      }
      QByteArray partName = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
      QByteArray part = partQuery.query().value( partQueryNameColumn ).toString().toUtf8();
      QByteArray data = partQuery.query().value( partQueryDataColumn ).toByteArray();
      int version = partQuery.query().value( partQueryVersionColumn ).toInt();
      if ( version != 0 ) { // '0' is the default, so don't send it
        part += "[" + QByteArray::number( version ) + "]";
      }
      if ( data.isNull() ) {
        part += " NIL";
      } else if ( data.isEmpty() ) {
        part += " \"\"";
      } else {
        part += " {" + QByteArray::number( data.length() ) + "}\n";
        part += data;
      }
      // return only requested parts (when RFC822.SIZE is requested, RFC822 is retrieved, but should not be returned)
      if ( mAttrList.contains( partName ) || mAllParts )
        attributes << part;

      if ( partName == "RFC822" && mAttrList.contains( "RFC822.SIZE" ) )
        attributes.append( "RFC822.SIZE " + QByteArray::number( data.length() ) );

      partQuery.query().next();
    }

    // IMAP protocol violation: should actually be the sequence number
    QByteArray attr = QByteArray::number( pimItemId ) + " FETCH (";
    attr += ImapParser::join( attributes, " " ) + ')';
    response.setUntagged();
    response.setString( attr );
    emit responseAvailable( response );

    itemQuery.query().next();
  }

  // update atime
  updateItemAccessTime();

  response.setTag( tag() );
  response.setSuccess();
  if ( mIsUidFetch )
    response.setString( "UID FETCH completed" );
  else
    response.setString( "FETCH completed" );
  emit responseAvailable( response );
  deleteLater();
  return true;
}

void Fetch::updateItemAccessTime()
{
  QueryBuilder qb( QueryBuilder::Update );
  qb.addTable( PimItem::tableName() );
  qb.updateColumnValue( PimItem::atimeColumn(), QDateTime::currentDateTime() );
  imapSetToQuery( mSet, mIsUidFetch, qb );
  if ( !qb.exec() )
    qWarning() << "Unable to update item access time";
}

void Fetch::triggerOnDemandFetch()
{
  if ( mIsUidFetch || connection()->selectedCollection() <= 0 )
    return;
  Location loc = connection()->selectedLocation();
  // HACK: don't trigger on-demand syncing if the resource is the one triggering it
  if ( connection()->sessionId() == loc.resource().name().toLatin1() )
    return;
  DataStore *store = connection()->storageBackend();
  store->activeCachePolicy( loc );
  if ( !loc.cachePolicySyncOnDemand() )
    return;
  store->triggerCollectionSync( loc );
}

QueryBuilder Fetch::buildPartQuery( const QStringList &partList )
{
  QueryBuilder partQuery;
  if ( !partList.isEmpty() || mAllParts || mAttrList.contains( "RFC822.SIZE" ) ) {
    partQuery.addTable( PimItem::tableName() );
    partQuery.addTable( Part::tableName() );
    partQuery.addColumn( PimItem::idFullColumnName() );
    partQuery.addColumn( Part::nameFullColumnName() );
    partQuery.addColumn( Part::dataFullColumnName() );
    partQuery.addColumn( Part::versionFullColumnName() );
    partQuery.addColumnCondition( PimItem::idFullColumnName(), Query::Equals, Part::pimItemIdFullColumnName() );
    if ( !mAllParts )
      partQuery.addValueCondition( Part::nameFullColumnName(), Query::In, partList );
    imapSetToQuery( mSet, mIsUidFetch, partQuery );
    partQuery.addSortColumn( PimItem::idFullColumnName(), Query::Ascending );
  }
  return partQuery;
}
<|endoftext|>


<commit_before>int main()
{
    return 0;
}
<commit_msg>Issue #6: exposed Cimage to python<commit_after>#include <boost/python.hpp>
#include "cimage.h"

using namespace boost::python;

BOOST_PYTHON_MODULE(pymycpp)
{
    class_<Cimage>("Cimage", init<size_t, size_t>())
        .def("width", &Cimage::width)
        .def("height", &Cimage::height)
        ;
}
<|endoftext|>


<commit_before>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief Definitions for geo::ProbRay
*/

#include "libgeo/ProbRay.h"

#include "libgeo/intersect.h"
#include "libio/sprintf.h"
#include "libmath/QuadEq.h"

#include <cassert>
#include <algorithm>
#include <fstream>
#include <sstream>

namespace
{
	std::vector<ga::Vector>
	pointsAlong
		( geo::Ray const & uRay
		, math::Partition const & uPart
		)
	{
		std::vector<ga::Vector> uPnts;
		size_t const numSamps{ uPart.size() };
		uPnts.reserve(numSamps);
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			// sampling distance along the ray
			double const mu{ uPart.interpValueFor(double(nn)) };
			ga::Vector const uPnt{ uRay.pointAt(mu) };
			uPnts.emplace_back(uPnt);
		}
		return uPnts;
	}
}

namespace geo
{

// explicit
ProbRay :: ProbRay
	( geo::Ray const & ray
	, math::Partition const & probPart
	, double const & rayAngleSigma
	)
	: theRay{ ray }
	, thePart{ probPart }
	, theAccums(thePart.size(), 0.) // allocate and initialize
	, thePntUs{ pointsAlong(theRay, thePart) }
	, theDistroAngU{ rayAngleSigma, 0. }
{
	assert(thePart.isValid());
	assert(theDistroAngU.isValid());
	assert(thePntUs.size() == theAccums.size());

	// can override in initAccumulator
	double const pSelf{ theDistroAngU(0.) };
	std::fill(theAccums.begin(), theAccums.end(), pSelf);
}

bool
ProbRay :: isValid
	() const
{
	return
		(  theRay.isValid()
		&& thePart.isValid() && (0u < numSamples())
		&& dat::isValid(theDistroAngU)
		);
}

void
ProbRay :: considerPoint
	( ga::Vector const & vPnt
	, double const & vPntSigma
	)
{
	if (isValid() && vPnt.isValid())
	{
		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };

		prob::Gauss const & distroVwU = theDistroAngU;
		prob::Gauss const distroUwV(vPntSigma);

		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			geo::Ray const & uRay = theRay;

			// prob density of point w.r.t uRay
			double const angVwU{ ga::magnitude(uRay.angleTo(vPnt)) };

			// prob density of ray w.r.t. point
			ga::Vector const & uPnt = thePntUs[nn];
			double const dstUwV{ ga::magnitude(uPnt - vPnt) };

			// compute the probability of each entity w.r.t. the other
			double const pdfVwU{ distroVwU(angVwU) };
			double const pdfUwV{ distroUwV(dstUwV) };

			// use composite as probability of interest (TODO good?bad?)
			double const density{ pdfVwU * pdfUwV };
			accumulateDensity(density, nn);
		}
	}
}

void
ProbRay :: considerRay
	( geo::Ray const & vRay
	, double const & vRaySigma
	)
{
	if (isValid() && vRay.isValid())
	{
		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };
		prob::Gauss const & distroVwU = theDistroAngU;
		prob::Gauss const distroUwV(vRaySigma);
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			geo::Ray const & uRay = theRay;
			ga::Vector const & uPnt = thePntUs[nn];

			// other entity
			ga::Vector const vPnt{ vRay.projectionOf(uPnt) };

			// probability of vRay w.r.t uRay and v.v.
			double const angVwU{ ga::magnitude(uRay.angleTo(vPnt)) };
			double const angUwV{ ga::magnitude(vRay.angleTo(uPnt)) };

			// compute the probability of each point being on the other ray
			double const pdfVwU{ distroVwU(angVwU) };
			double const pdfUwV{ distroUwV(angUwV) };

			// use composite as probability of interest (TODO good?bad?)
			double const density{ pdfVwU * pdfUwV };
			accumulateDensity(density, nn);
		}
	}
}

namespace
{
	inline
	double
	angleMagBetween
		( ga::Vector const & vecA
		, ga::Vector const & vecB
		)
	{
		ga::Spinor const spinAB{ ga::spin::between(vecA, vecB) };
		ga::BiVector const angleAB{ ga::spin::physicalAngleFrom(spinAB) };
		return ga::magnitude(angleAB);
	}
}

void
ProbRay :: considerCone
	( geo::Ray const & rayOnCone
	, ga::Vector const & coneAxisDir
	, double const & apexSigma
	)
{
	if (isValid() && rayOnCone.isValid() && coneAxisDir.isValid())
	{
		// access the relevant entities
		ga::Vector const & vSta = rayOnCone.theStart;
		ga::Vector const & vDir = rayOnCone.theDir;
		ga::Vector const aDir{ ga::unit(coneAxisDir) };
		assert(aDir.isValid());

		// determine cones (half)apex angle
		double const apexAngle{ angleMagBetween(vDir, aDir) };
		prob::Gauss const distroUwV(apexSigma, apexAngle);

		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			ga::Vector const & uPnt = thePntUs[nn];

			// compute direction to sampling point on ray
			ga::Vector const uDir{ ga::unit(uPnt - vSta) };
			double const angUwV{ angleMagBetween(uDir, aDir) };

			// probability value at this sample
			double const density{ distroUwV(angUwV) };
			if (dat::isValid(density))
			{
				theAccums[nn] += density;
			}
		}
	}
}

double
ProbRay :: probDensityAt
	( double const & distAlong
	, std::vector<DistProb> const & distProbs
	) const
{
	double prob{ dat::nullValue<double>() };
	if (isValid() && dat::isValid(distAlong))
	{
		double const fndx{ thePart.interpIndexFor(distAlong) };
		size_t const ndxLo{ (size_t)std::floor(fndx) };
		size_t const ndxHi{ ndxLo + 1u };
		if ((0u < ndxLo) && (ndxHi < theAccums.size()))
		{
			double const frac{ fndx - double(ndxLo) };
			std::pair<double, double> const probPair
				{ distProbs[ndxLo].second, distProbs[ndxHi].second };
			prob = math::interp::valueAtValid(frac, probPair);
		}
	}
	return prob;
}

std::vector<ProbRay::DistProb>
ProbRay :: distProbs
	() const
{
	std::vector<DistProb> dps;
	if (isValid())
	{
		// compute sum (for normalization)
		double const sum
			{ std::accumulate(theAccums.begin(), theAccums.end(), 0.) };
		size_t const numSamps{ numSamples() };
		dps.resize(numSamps);
		double normCo{ 0. };
		if (std::numeric_limits<double>::min() < sum)
		{
			normCo = 1. / sum;

		}
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			// sampling distance along the ray
			double const mu{ thePart.interpValueFor(double(nn)) };
			double const prob{ normCo * theAccums[nn] };
			dps[nn] = DistProb{ mu, prob };
		}
	}
	return dps;
}

std::pair<double, double>
ProbRay :: likelyDistProb
	( std::vector<DistProb> const & distProbs
	) const
{
	std::pair<double, double> dpPair
		{ dat::nullValue<double>(), dat::nullValue<double>() };
	double & dist = dpPair.first;
	double & prob = dpPair.second;

	std::vector<DistProb> const & dps = distProbs;

	if (isValid())
	{
		using Iter = std::vector<DistProb>::const_iterator;
		std::pair<Iter, Iter> const itMinMax
			{ std::minmax_element
				( dps.begin(), dps.end()
				, [] (DistProb const & dpA, DistProb const &dpB)
					{ return (dpA.second < dpB.second); }
				)
			};
		Iter const & itMin = itMinMax.first;
		Iter const & itMax = itMinMax.second;
		if (itMax != itMin) // non-const prob samples
		{
			size_t const ndxCurr{ size_t(itMax - dps.begin()) };
			if (0u < ndxCurr)
			{
				size_t const ndxPrev{ ndxCurr - 1u };
				size_t const ndxNext{ ndxCurr + 1u };
				if (ndxNext < dps.size())
				{
					// three values spaning the (assumed) peak
					double const alpha{ dps[ndxPrev].second };
					double const beta{ dps[ndxCurr].second };
					double const gamma{ dps[ndxNext].second };

					// verify a 'true' peak (not a flat-ish spot)
					if ((alpha < beta) && (gamma < beta))
					{
						// interpolated peak location
						// formula from
						//   https://www.dsprelated.com
						//   /freebooks/sasp
						//   /Quadratic_Interpolation_Spectral_Peaks.html
						double const num{ alpha - gamma };
						double const den{ alpha - 2.*beta + gamma };
						double const denMag{ std::abs(den) };
						if (std::numeric_limits<double>::min() < denMag)
						{
							// peak location - provides distance
							double const fndx{ .5 * num / den };
							double const ndx{ double(ndxCurr) + fndx };
							dist = thePart.interpValueFor(ndx);

							// peak magnitude - provides (quasi)probability
							prob = beta - .25*(alpha - gamma)*fndx;
						}
					}
				} // not at end
			} // not at start
		} // distinct min and max

	} // valid instance

	return dpPair;
}

std::pair<double, double>
ProbRay :: likelyDistProb
	() const
{
	return likelyDistProb(distProbs());
}

double
ProbRay :: likelyDistance
	() const
{
	return likelyDistProb().first;
}

ga::Vector
ProbRay :: likelyPoint
	() const
{
	ga::Vector pnt;
	if (isValid())
	{
		double const dist{ likelyDistance() };
		if (dat::isValid(dist))
		{
			pnt = theRay.pointAt(dist);
		}
	}
	return pnt;
}

std::string
ProbRay :: infoString
	( std::string const & title
	) const
{
	std::ostringstream oss;
	if (! title.empty())
	{
		oss << title << std::endl;
	}
	if (isValid())
	{
		oss << dat::infoString(theRay, "theRay");

		oss << std::endl;
		oss << dat::infoString(thePart, "thePart");

		oss << std::endl;
		oss << dat::infoString(theDistroAngU, "theDistroAngU");
	}
	else
	{
		oss << " <null>";
	}
	return oss.str();
}

std::string
ProbRay :: infoStringPDF
	( std::string const & fmtDist
	, std::string const & fmtProb
	) const
{
	std::ostringstream oss;
	if (isValid())
	{
		std::vector<DistProb> const dps{ distProbs() };
		oss << "# dist-on-ray, probability" << '\n';
		for (DistProb const & dp : dps)
		{
			double const & dist = dp.first;
			double const & prob = dp.second;
			oss
				<< " " << io::sprintf(fmtDist, dist)
				<< " " << io::sprintf(fmtProb, prob)
				<< '\n';
		}
	}
	else
	{
		oss << "# <null>";
	}
	return oss.str();
}

void
ProbRay :: saveDistProbs
	( std::ostream & oss
	, std::string const & fmt
	) const
{
	std::vector<DistProb> const dps{ distProbs() };
	for (DistProb const & dp : dps)
	{
		oss
			<< io::sprintf(fmt, dp.first)
			<< " "
			<< io::sprintf(fmt, dp.second)
			<< '\n';
	}
}

void
ProbRay :: accumulateDensity
	( double const & nextProb
	, size_t const & ndx
	)
{
	if (dat::isValid(nextProb))
	{
		assert(ndx < theAccums.size());
		theAccums[ndx] += nextProb;
		/*
		double const & pA = theAccums[ndx];
		double const & pB = nextProb;
		theAccums[ndx] = netProb(pA, pB);
		*/
	}
}

} // geo

<commit_msg>libgeo/ProbRay added checks on ctor args before using to set members<commit_after>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief Definitions for geo::ProbRay
*/

#include "libgeo/ProbRay.h"

#include "libgeo/intersect.h"
#include "libio/sprintf.h"
#include "libmath/QuadEq.h"

#include <cassert>
#include <algorithm>
#include <fstream>
#include <sstream>

namespace
{
	std::vector<ga::Vector>
	pointsAlong
		( geo::Ray const & uRay
		, math::Partition const & uPart
		)
	{
		std::vector<ga::Vector> uPnts;
		if (uRay.isValid() && uPart.isValid())
		{
			size_t const numSamps{ uPart.size() };
			uPnts.reserve(numSamps);
			for (size_t nn{0u} ; nn < numSamps ; ++nn)
			{
				// sampling distance along the ray
				double const mu{ uPart.interpValueFor(double(nn)) };
				ga::Vector const uPnt{ uRay.pointAt(mu) };
				uPnts.emplace_back(uPnt);
			}
		}
		return uPnts;
	}
}

namespace geo
{

// explicit
ProbRay :: ProbRay
	( geo::Ray const & ray
	, math::Partition const & probPart
	, double const & rayAngleSigma
	)
	: theRay{ ray }
	, thePart{ probPart }
	, theAccums{} // alloc/init below
	, thePntUs{ pointsAlong(theRay, thePart) }
	, theDistroAngU{ rayAngleSigma, 0. }
{
	assert(thePart.isValid());
	assert(theDistroAngU.isValid());

	// can override in initAccumulator
	double const pSelf{ theDistroAngU(0.) };
	theAccums.resize(thePart.size(), pSelf); // allocate and initialize

	assert(thePntUs.size() == theAccums.size());
}

bool
ProbRay :: isValid
	() const
{
	return
		(  theRay.isValid()
		&& thePart.isValid() && (0u < numSamples())
		&& dat::isValid(theDistroAngU)
		);
}

void
ProbRay :: considerPoint
	( ga::Vector const & vPnt
	, double const & vPntSigma
	)
{
	if (isValid() && vPnt.isValid())
	{
		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };

		prob::Gauss const & distroVwU = theDistroAngU;
		prob::Gauss const distroUwV(vPntSigma);

		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			geo::Ray const & uRay = theRay;

			// prob density of point w.r.t uRay
			double const angVwU{ ga::magnitude(uRay.angleTo(vPnt)) };

			// prob density of ray w.r.t. point
			ga::Vector const & uPnt = thePntUs[nn];
			double const dstUwV{ ga::magnitude(uPnt - vPnt) };

			// compute the probability of each entity w.r.t. the other
			double const pdfVwU{ distroVwU(angVwU) };
			double const pdfUwV{ distroUwV(dstUwV) };

			// use composite as probability of interest (TODO good?bad?)
			double const density{ pdfVwU * pdfUwV };
			accumulateDensity(density, nn);
		}
	}
}

void
ProbRay :: considerRay
	( geo::Ray const & vRay
	, double const & vRaySigma
	)
{
	if (isValid() && vRay.isValid())
	{
		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };
		prob::Gauss const & distroVwU = theDistroAngU;
		prob::Gauss const distroUwV(vRaySigma);
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			geo::Ray const & uRay = theRay;
			ga::Vector const & uPnt = thePntUs[nn];

			// other entity
			ga::Vector const vPnt{ vRay.projectionOf(uPnt) };

			// probability of vRay w.r.t uRay and v.v.
			double const angVwU{ ga::magnitude(uRay.angleTo(vPnt)) };
			double const angUwV{ ga::magnitude(vRay.angleTo(uPnt)) };

			// compute the probability of each point being on the other ray
			double const pdfVwU{ distroVwU(angVwU) };
			double const pdfUwV{ distroUwV(angUwV) };

			// use composite as probability of interest (TODO good?bad?)
			double const density{ pdfVwU * pdfUwV };
			accumulateDensity(density, nn);
		}
	}
}

namespace
{
	inline
	double
	angleMagBetween
		( ga::Vector const & vecA
		, ga::Vector const & vecB
		)
	{
		ga::Spinor const spinAB{ ga::spin::between(vecA, vecB) };
		ga::BiVector const angleAB{ ga::spin::physicalAngleFrom(spinAB) };
		return ga::magnitude(angleAB);
	}
}

void
ProbRay :: considerCone
	( geo::Ray const & rayOnCone
	, ga::Vector const & coneAxisDir
	, double const & apexSigma
	)
{
	if (isValid() && rayOnCone.isValid() && coneAxisDir.isValid())
	{
		// access the relevant entities
		ga::Vector const & vSta = rayOnCone.theStart;
		ga::Vector const & vDir = rayOnCone.theDir;
		ga::Vector const aDir{ ga::unit(coneAxisDir) };
		assert(aDir.isValid());

		// determine cones (half)apex angle
		double const apexAngle{ angleMagBetween(vDir, aDir) };
		prob::Gauss const distroUwV(apexSigma, apexAngle);

		// evaluate probability at each sample location
		size_t const numSamps{ numSamples() };
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			ga::Vector const & uPnt = thePntUs[nn];

			// compute direction to sampling point on ray
			ga::Vector const uDir{ ga::unit(uPnt - vSta) };
			double const angUwV{ angleMagBetween(uDir, aDir) };

			// probability value at this sample
			double const density{ distroUwV(angUwV) };
			if (dat::isValid(density))
			{
				theAccums[nn] += density;
			}
		}
	}
}

double
ProbRay :: probDensityAt
	( double const & distAlong
	, std::vector<DistProb> const & distProbs
	) const
{
	double prob{ dat::nullValue<double>() };
	if (isValid() && dat::isValid(distAlong))
	{
		double const fndx{ thePart.interpIndexFor(distAlong) };
		size_t const ndxLo{ (size_t)std::floor(fndx) };
		size_t const ndxHi{ ndxLo + 1u };
		if ((0u < ndxLo) && (ndxHi < theAccums.size()))
		{
			double const frac{ fndx - double(ndxLo) };
			std::pair<double, double> const probPair
				{ distProbs[ndxLo].second, distProbs[ndxHi].second };
			prob = math::interp::valueAtValid(frac, probPair);
		}
	}
	return prob;
}

std::vector<ProbRay::DistProb>
ProbRay :: distProbs
	() const
{
	std::vector<DistProb> dps;
	if (isValid())
	{
		// compute sum (for normalization)
		double const sum
			{ std::accumulate(theAccums.begin(), theAccums.end(), 0.) };
		size_t const numSamps{ numSamples() };
		dps.resize(numSamps);
		double normCo{ 0. };
		if (std::numeric_limits<double>::min() < sum)
		{
			normCo = 1. / sum;

		}
		for (size_t nn{0u} ; nn < numSamps ; ++nn)
		{
			// sampling distance along the ray
			double const mu{ thePart.interpValueFor(double(nn)) };
			double const prob{ normCo * theAccums[nn] };
			dps[nn] = DistProb{ mu, prob };
		}
	}
	return dps;
}

std::pair<double, double>
ProbRay :: likelyDistProb
	( std::vector<DistProb> const & distProbs
	) const
{
	std::pair<double, double> dpPair
		{ dat::nullValue<double>(), dat::nullValue<double>() };
	double & dist = dpPair.first;
	double & prob = dpPair.second;

	std::vector<DistProb> const & dps = distProbs;

	if (isValid())
	{
		using Iter = std::vector<DistProb>::const_iterator;
		std::pair<Iter, Iter> const itMinMax
			{ std::minmax_element
				( dps.begin(), dps.end()
				, [] (DistProb const & dpA, DistProb const &dpB)
					{ return (dpA.second < dpB.second); }
				)
			};
		Iter const & itMin = itMinMax.first;
		Iter const & itMax = itMinMax.second;
		if (itMax != itMin) // non-const prob samples
		{
			size_t const ndxCurr{ size_t(itMax - dps.begin()) };
			if (0u < ndxCurr)
			{
				size_t const ndxPrev{ ndxCurr - 1u };
				size_t const ndxNext{ ndxCurr + 1u };
				if (ndxNext < dps.size())
				{
					// three values spaning the (assumed) peak
					double const alpha{ dps[ndxPrev].second };
					double const beta{ dps[ndxCurr].second };
					double const gamma{ dps[ndxNext].second };

					// verify a 'true' peak (not a flat-ish spot)
					if ((alpha < beta) && (gamma < beta))
					{
						// interpolated peak location
						// formula from
						//   https://www.dsprelated.com
						//   /freebooks/sasp
						//   /Quadratic_Interpolation_Spectral_Peaks.html
						double const num{ alpha - gamma };
						double const den{ alpha - 2.*beta + gamma };
						double const denMag{ std::abs(den) };
						if (std::numeric_limits<double>::min() < denMag)
						{
							// peak location - provides distance
							double const fndx{ .5 * num / den };
							double const ndx{ double(ndxCurr) + fndx };
							dist = thePart.interpValueFor(ndx);

							// peak magnitude - provides (quasi)probability
							prob = beta - .25*(alpha - gamma)*fndx;
						}
					}
				} // not at end
			} // not at start
		} // distinct min and max

	} // valid instance

	return dpPair;
}

std::pair<double, double>
ProbRay :: likelyDistProb
	() const
{
	return likelyDistProb(distProbs());
}

double
ProbRay :: likelyDistance
	() const
{
	return likelyDistProb().first;
}

ga::Vector
ProbRay :: likelyPoint
	() const
{
	ga::Vector pnt;
	if (isValid())
	{
		double const dist{ likelyDistance() };
		if (dat::isValid(dist))
		{
			pnt = theRay.pointAt(dist);
		}
	}
	return pnt;
}

std::string
ProbRay :: infoString
	( std::string const & title
	) const
{
	std::ostringstream oss;
	if (! title.empty())
	{
		oss << title << std::endl;
	}
	if (isValid())
	{
		oss << dat::infoString(theRay, "theRay");

		oss << std::endl;
		oss << dat::infoString(thePart, "thePart");

		oss << std::endl;
		oss << dat::infoString(theDistroAngU, "theDistroAngU");
	}
	else
	{
		oss << " <null>";
	}
	return oss.str();
}

std::string
ProbRay :: infoStringPDF
	( std::string const & fmtDist
	, std::string const & fmtProb
	) const
{
	std::ostringstream oss;
	if (isValid())
	{
		std::vector<DistProb> const dps{ distProbs() };
		oss << "# dist-on-ray, probability" << '\n';
		for (DistProb const & dp : dps)
		{
			double const & dist = dp.first;
			double const & prob = dp.second;
			oss
				<< " " << io::sprintf(fmtDist, dist)
				<< " " << io::sprintf(fmtProb, prob)
				<< '\n';
		}
	}
	else
	{
		oss << "# <null>";
	}
	return oss.str();
}

void
ProbRay :: saveDistProbs
	( std::ostream & oss
	, std::string const & fmt
	) const
{
	std::vector<DistProb> const dps{ distProbs() };
	for (DistProb const & dp : dps)
	{
		oss
			<< io::sprintf(fmt, dp.first)
			<< " "
			<< io::sprintf(fmt, dp.second)
			<< '\n';
	}
}

void
ProbRay :: accumulateDensity
	( double const & nextProb
	, size_t const & ndx
	)
{
	if (dat::isValid(nextProb))
	{
		assert(ndx < theAccums.size());
		theAccums[ndx] += nextProb;
		/*
		double const & pA = theAccums[ndx];
		double const & pB = nextProb;
		theAccums[ndx] = netProb(pA, pB);
		*/
	}
}

} // geo

<|endoftext|>


<commit_before>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "libmv/numeric/numeric.h"
#include "testing/testing.h"

using namespace libmv;
/*
//using libmv::Mat;
using libmv::Mat2;
using libmv::Mat34;
using libmv::Vec;
using libmv::Vec2;
using libmv::Nullspace;
using libmv::Transpose;
*/

namespace {

TEST(Numeric, Nullspace) {
  Mat A(3, 4);
  A = 0.76026643, 0.01799744, 0.55192142, 0.8699745,
      0.42016166, 0.97863392, 0.33711682, 0.14479271,
      0.51016811, 0.66528302, 0.54395496, 0.57794893;
  Vec x;
  double s = Nullspace(&A, &x);
  EXPECT_NEAR(s, 0.122287, 1e-7);
  EXPECT_NEAR(x(0), -0.05473917, 1e-7);
  EXPECT_NEAR(x(1),  0.21822937, 1e-7);
  EXPECT_NEAR(x(2), -0.80258116, 1e-7);
  EXPECT_NEAR(x(3),  0.55248805, 1e-7);
}

TEST(Numeric, TinyMatrixNullspace) {
  Mat34 A;
  A = 0.76026643, 0.01799744, 0.55192142, 0.8699745,
      0.42016166, 0.97863392, 0.33711682, 0.14479271,
      0.51016811, 0.66528302, 0.54395496, 0.57794893;
  Vec x;
  double s = Nullspace(&A, &x);
  EXPECT_NEAR(s, 0.122287, 1e-7);
  EXPECT_NEAR(x(0), -0.05473917, 1e-7);
  EXPECT_NEAR(x(1),  0.21822937, 1e-7);
  EXPECT_NEAR(x(2), -0.80258116, 1e-7);
  EXPECT_NEAR(x(3),  0.55248805, 1e-7);
}

TEST(Numeric, TinyMatrixSquareTranspose) {
  Mat2 A;
  A = 1.0, 2.0, 3.0, 4.0;
  libmv::TransposeInPlace(&A);
  EXPECT_EQ(1.0, A(0, 0));
  EXPECT_EQ(3.0, A(0, 1));
  EXPECT_EQ(2.0, A(1, 0));
  EXPECT_EQ(4.0, A(1, 1));
}

TEST(Numeric, NormalizeL1) {
  Vec2 x;
  x = 1, 2;
  double l1 = NormalizeL1(&x);
  EXPECT_DOUBLE_EQ(3., l1);
  EXPECT_DOUBLE_EQ(1./3., x(0));
  EXPECT_DOUBLE_EQ(2./3., x(1));
}

TEST(Numeric, NormalizeL2) {
  Vec2 x;
  x = 1, 2;
  double l2 = NormalizeL2(&x);
  EXPECT_DOUBLE_EQ(sqrt(5.0), l2);
  EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0));
  EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1));
}

TEST(Numeric, Diag) {
  Vec x(2);
  x = 1, 2;
  Mat D;
  D = Diag(x);
  EXPECT_EQ(1, D(0,0));
  EXPECT_EQ(0, D(0,1));
  EXPECT_EQ(0, D(1,0));
  EXPECT_EQ(2, D(1,1));
}

TEST(Numeric, DeterminantSlow) {
  Mat A(2, 2);
  A =  1, 2,
      -1, 3;
  double detA = DeterminantSlow(A);
  EXPECT_NEAR(5, detA, 1e-8);

  Mat B(4,4);
  B =  0,  1,  2,  3,
       4,  5,  6,  7,
       8,  9, 10, 11,
      12, 13, 14, 15;
  double detB = DeterminantSlow(B);
  EXPECT_NEAR(0, detB, 1e-8);
}

TEST(Numeric, InverseSlow) {
  Mat A(2, 2), A1, I;
  A =  1, 2,
      -1, 3;
  InverseSlow(A, &A1);
  I = A * A1;

  EXPECT_NEAR(1, I(0,0), 1e-8);
  EXPECT_NEAR(0, I(0,1), 1e-8);
  EXPECT_NEAR(0, I(1,0), 1e-8);
  EXPECT_NEAR(1, I(1,1), 1e-8);

  Mat B(4,4), B1;
  B =  0,  1,  2,  3,
       4,  5,  6,  7,
       8,  9,  2, 11,
      12, 13, 14,  4;
  InverseSlow(B, &B1);
  I = B * B1;
  EXPECT_NEAR(1, I(0,0), 1e-8);
  EXPECT_NEAR(0, I(0,1), 1e-8);
  EXPECT_NEAR(0, I(0,2), 1e-8);
  EXPECT_NEAR(0, I(1,0), 1e-8);
  EXPECT_NEAR(1, I(1,1), 1e-8);
  EXPECT_NEAR(0, I(1,2), 1e-8);
  EXPECT_NEAR(0, I(2,0), 1e-8);
  EXPECT_NEAR(0, I(2,1), 1e-8);
  EXPECT_NEAR(1, I(2,2), 1e-8);
}

TEST(Numeric, MeanAndVarianceAlongRows) {
  int n = 4;
  Mat points(2,n);
  points = 0, 0, 1, 1,
           0, 2, 1, 3;

  Vec mean, variance;
  MeanAndVarianceAlongRows(points, &mean, &variance);

  EXPECT_NEAR(0.5, mean(0), 1e-8);
  EXPECT_NEAR(1.5, mean(1), 1e-8);
  EXPECT_NEAR(0.25, variance(0), 1e-8);
  EXPECT_NEAR(1.25, variance(1), 1e-8);
}

TEST(Numeric, HorizontalStack) {
  Mat x(2,1), y(2,1), z;
  x(0,0) = 1; // List initialization do not work here.  See ThisCrashes bellow.
  x(1,0) = 2;
  y(0,0) = 3;
  y(1,0) = 4;

  HorizontalStack(x, y, &z);

  EXPECT_EQ(2, z.numCols());
  EXPECT_EQ(2, z.numRows());
  EXPECT_EQ(1, z(0,0));
  EXPECT_EQ(2, z(1,0));
  EXPECT_EQ(3, z(0,1));
  EXPECT_EQ(4, z(1,1));
}

TEST(Numeric, VerticalStack) {
  Mat x(1,2), y(1,2), z;
  x = 1, 2;
  y = 3, 4;
  VerticalStack(x, y, &z);

  EXPECT_EQ(2, z.numCols());
  EXPECT_EQ(2, z.numRows());
  EXPECT_EQ(1, z(0,0));
  EXPECT_EQ(2, z(0,1));
  EXPECT_EQ(3, z(1,0));
  EXPECT_EQ(4, z(1,1));
}

// This segfaults inside lapack.
//TEST(Numeric, DeterminantLU) {
//  Mat A(2, 2);
//  A =  1, 2,
//      -1, 3;
//  double detA = DeterminantLU(&A);
//  EXPECT_NEAR(5, detA, 1e-8);
//}

// This does unexpected things.
//TEST(Numeric, InplaceProduct) {
//  Mat K(2,2), S(2,2);
//  K = 1, 0,
//      0, 1;
//  S = 1, 0,
//      0, 1;
//  K = K * S; // This sets K to zero without warning!
//  EXPECT_NEAR(1, K(0,0), 1e-8);
//  EXPECT_NEAR(0, K(0,1), 1e-8);
//  EXPECT_NEAR(0, K(1,0), 1e-8);
//  EXPECT_NEAR(1, K(1,1), 1e-8);
//}

}  // namespace
<commit_msg>Added a FLENS feature request.<commit_after>// Copyright (c) 2007, 2008 libmv authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "libmv/numeric/numeric.h"
#include "testing/testing.h"

using namespace libmv;
/*
//using libmv::Mat;
using libmv::Mat2;
using libmv::Mat34;
using libmv::Vec;
using libmv::Vec2;
using libmv::Nullspace;
using libmv::Transpose;
*/

namespace {

TEST(Numeric, Nullspace) {
  Mat A(3, 4);
  A = 0.76026643, 0.01799744, 0.55192142, 0.8699745,
      0.42016166, 0.97863392, 0.33711682, 0.14479271,
      0.51016811, 0.66528302, 0.54395496, 0.57794893;
  Vec x;
  double s = Nullspace(&A, &x);
  EXPECT_NEAR(s, 0.122287, 1e-7);
  EXPECT_NEAR(x(0), -0.05473917, 1e-7);
  EXPECT_NEAR(x(1),  0.21822937, 1e-7);
  EXPECT_NEAR(x(2), -0.80258116, 1e-7);
  EXPECT_NEAR(x(3),  0.55248805, 1e-7);
}

TEST(Numeric, TinyMatrixNullspace) {
  Mat34 A;
  A = 0.76026643, 0.01799744, 0.55192142, 0.8699745,
      0.42016166, 0.97863392, 0.33711682, 0.14479271,
      0.51016811, 0.66528302, 0.54395496, 0.57794893;
  Vec x;
  double s = Nullspace(&A, &x);
  EXPECT_NEAR(s, 0.122287, 1e-7);
  EXPECT_NEAR(x(0), -0.05473917, 1e-7);
  EXPECT_NEAR(x(1),  0.21822937, 1e-7);
  EXPECT_NEAR(x(2), -0.80258116, 1e-7);
  EXPECT_NEAR(x(3),  0.55248805, 1e-7);
}

TEST(Numeric, TinyMatrixSquareTranspose) {
  Mat2 A;
  A = 1.0, 2.0, 3.0, 4.0;
  libmv::TransposeInPlace(&A);
  EXPECT_EQ(1.0, A(0, 0));
  EXPECT_EQ(3.0, A(0, 1));
  EXPECT_EQ(2.0, A(1, 0));
  EXPECT_EQ(4.0, A(1, 1));
}

TEST(Numeric, NormalizeL1) {
  Vec2 x;
  x = 1, 2;
  double l1 = NormalizeL1(&x);
  EXPECT_DOUBLE_EQ(3., l1);
  EXPECT_DOUBLE_EQ(1./3., x(0));
  EXPECT_DOUBLE_EQ(2./3., x(1));
}

TEST(Numeric, NormalizeL2) {
  Vec2 x;
  x = 1, 2;
  double l2 = NormalizeL2(&x);
  EXPECT_DOUBLE_EQ(sqrt(5.0), l2);
  EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0));
  EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1));
}

TEST(Numeric, Diag) {
  Vec x(2);
  x = 1, 2;
  Mat D;
  D = Diag(x);
  EXPECT_EQ(1, D(0,0));
  EXPECT_EQ(0, D(0,1));
  EXPECT_EQ(0, D(1,0));
  EXPECT_EQ(2, D(1,1));
}

TEST(Numeric, DeterminantSlow) {
  Mat A(2, 2);
  A =  1, 2,
      -1, 3;
  double detA = DeterminantSlow(A);
  EXPECT_NEAR(5, detA, 1e-8);

  Mat B(4,4);
  B =  0,  1,  2,  3,
       4,  5,  6,  7,
       8,  9, 10, 11,
      12, 13, 14, 15;
  double detB = DeterminantSlow(B);
  EXPECT_NEAR(0, detB, 1e-8);
}

TEST(Numeric, InverseSlow) {
  Mat A(2, 2), A1, I;
  A =  1, 2,
      -1, 3;
  InverseSlow(A, &A1);
  I = A * A1;

  EXPECT_NEAR(1, I(0,0), 1e-8);
  EXPECT_NEAR(0, I(0,1), 1e-8);
  EXPECT_NEAR(0, I(1,0), 1e-8);
  EXPECT_NEAR(1, I(1,1), 1e-8);

  Mat B(4,4), B1;
  B =  0,  1,  2,  3,
       4,  5,  6,  7,
       8,  9,  2, 11,
      12, 13, 14,  4;
  InverseSlow(B, &B1);
  I = B * B1;
  EXPECT_NEAR(1, I(0,0), 1e-8);
  EXPECT_NEAR(0, I(0,1), 1e-8);
  EXPECT_NEAR(0, I(0,2), 1e-8);
  EXPECT_NEAR(0, I(1,0), 1e-8);
  EXPECT_NEAR(1, I(1,1), 1e-8);
  EXPECT_NEAR(0, I(1,2), 1e-8);
  EXPECT_NEAR(0, I(2,0), 1e-8);
  EXPECT_NEAR(0, I(2,1), 1e-8);
  EXPECT_NEAR(1, I(2,2), 1e-8);
}

TEST(Numeric, MeanAndVarianceAlongRows) {
  int n = 4;
  Mat points(2,n);
  points = 0, 0, 1, 1,
           0, 2, 1, 3;

  Vec mean, variance;
  MeanAndVarianceAlongRows(points, &mean, &variance);

  EXPECT_NEAR(0.5, mean(0), 1e-8);
  EXPECT_NEAR(1.5, mean(1), 1e-8);
  EXPECT_NEAR(0.25, variance(0), 1e-8);
  EXPECT_NEAR(1.25, variance(1), 1e-8);
}

TEST(Numeric, HorizontalStack) {
  Mat x(2,1), y(2,1), z;
  x = 1, 2;
  y = 3, 4;

  HorizontalStack(x, y, &z);

  EXPECT_EQ(2, z.numCols());
  EXPECT_EQ(2, z.numRows());
  EXPECT_EQ(1, z(0,0));
  EXPECT_EQ(2, z(1,0));
  EXPECT_EQ(3, z(0,1));
  EXPECT_EQ(4, z(1,1));
}

TEST(Numeric, VerticalStack) {
  Mat x(1,2), y(1,2), z;
  x = 1, 2;
  y = 3, 4;
  VerticalStack(x, y, &z);

  EXPECT_EQ(2, z.numCols());
  EXPECT_EQ(2, z.numRows());
  EXPECT_EQ(1, z(0,0));
  EXPECT_EQ(2, z(0,1));
  EXPECT_EQ(3, z(1,0));
  EXPECT_EQ(4, z(1,1));
}

// This gives a compile error.
//TEST(Numeric, Mat3MatProduct) {
//  Mat3 A;
//  Mat B, C;
//  C = A * B;
//}

// This segfaults inside lapack.
//TEST(Numeric, DeterminantLU) {
//  Mat A(2, 2);
//  A =  1, 2,
//      -1, 3;
//  double detA = DeterminantLU(&A);
//  EXPECT_NEAR(5, detA, 1e-8);
//}

// This does unexpected things.
//TEST(Numeric, InplaceProduct) {
//  Mat K(2,2), S(2,2);
//  K = 1, 0,
//      0, 1;
//  S = 1, 0,
//      0, 1;
//  K = K * S; // This sets K to zero without warning!
//  EXPECT_NEAR(1, K(0,0), 1e-8);
//  EXPECT_NEAR(0, K(0,1), 1e-8);
//  EXPECT_NEAR(0, K(1,0), 1e-8);
//  EXPECT_NEAR(1, K(1,1), 1e-8);
//}

}  // namespace
<|endoftext|>


<commit_before>#include "inmost.h"

using namespace INMOST;

// use ADMFD or ADVDIFF to solve for phi

//setup BC
//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//
// BOUNDARY_CONDTION - 3 entries (for calculation of phi and measures of drag and lift)

typedef Storage::real real;
const double eps = 1.0e-5;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh [mesh_out=grid_out.pmf]" << std::endl;
		return 0;
	}

	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try
	{
		m->Load(argv[1]);
	}
	catch(...)
	{
		std::cout << "Cannot load the mesh " << argv[1] << std::endl;
		return -1;
	}

	std::string fout = "grid_out.pmf";
	double Umax = 2.25;
	int fix_cylinder = 0;
	if( argc > 2 ) fout = std::string(argv[2]);
	if( argc > 3 ) Umax = atof(argv[3]);
	if( argc > 4 ) fix_cylinder = atoi(argv[4]);

	double cmax[3] = {-1.0e20,-1.0e20,-1.0e20}, cmin[3] = {1.0e20,1.0e20,1.0e20};
	for(Mesh::iteratorNode n = m->BeginNode(); n != m->EndNode(); ++n)
	{
		Storage::real_array c = n->Coords();
		for(int k = 0; k < 3; ++k)
		{
			if( cmax[k] < c[k] ) cmax[k] = c[k];
			if( cmin[k] > c[k] ) cmin[k] = c[k];
		}
	}
	for(int d = 0; d < 3; ++d)
		std::cout << d << " " << cmin[d] << ":" << cmax[d] << std::endl;

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray  bc      = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal       bcp     = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagInteger    bb      = m->CreateTag("BOUNDARY_BLOOD",DATA_INTEGER,FACE,FACE,1);
	TagRealArray  uvw     = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagReal       p       = m->CreateTag("P",DATA_REAL,CELL,NONE,1);
	m->self().Real(m->CreateTag("Umax",DATA_REAL,MESH,NONE,1)) = Umax;

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	{ // prepare geometrical data on the mesh
		Mesh::GeomParam table;
		table[CENTROID]    = CELL | FACE; //Compute averaged center of mass
		table[NORMAL]      = FACE;        //Compute normals
		table[MEASURE]     = CELL | FACE; //Compute volumes and areas
		table[BARYCENTER]  = CELL | FACE; //Compute volumetric center of mass
		m->RemoveGeometricData(table); //Ask to precompute the data
	}

	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		double  n[3], c[3];
		it->UnitNormal(n);
		it->Centroid(c);
		bb[*it] = 0;
		if( fabs(n[0]-1) < 1.0e-3 && c[0] > 1.8+eps) // outflow
		{
			bcp[*it] = 0;
			//~ bc[*it][0] = 0;
			//~ bc[*it][1] = 1;
			//~ bc[*it][2] = 0;
			//~ bc[*it][3] = 1;
			//~ bc[*it][4] = 0;
			//~ bc[*it][5] = 0;
			//~ bc[*it][6] = 0;
		}
		else if(  fabs(n[0]+1) < 1.0e-3 && c[0] < 0.0+eps) //inflow
		{
			bb[*it] = 1;
			bcp[*it] = 0.825;
			//~ bc[*it][0] = 1;
			//~ bc[*it][1] = 0;
			//~ bc[*it][2] = 1;
			//~ bc[*it][3] = 0;
			//~ bc[*it][4] = 17.3 * c[1]*(3.0-c[1])/9.0 * 4.0 * (3.0 / 2.0); //parabolic profile with average of 17.3
			//~ bc[*it][5] = 0;
			//~ bc[*it][6] = 0;
		}
		else if( (fabs(n[1]-1) < 1.0e-3 && c[1] > 1.5-eps) || (fabs(n[2]-1) < 1.0e-3 && c[2] > 0.1-eps) || (fabs(n[2]+1) < 1.0e-3 && c[2] < 0.0+eps) ) //slip wall
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 0;
			bc[*it][3] = 1;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else //no-slip walls
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<commit_msg>change BC in NS crevice test<commit_after>#include "inmost.h"

using namespace INMOST;

// use ADMFD or ADVDIFF to solve for phi

//setup BC
//setup on mesh:
//
// FORCE - 3 entries
//
// BOUNDARY_CONDITION_VELOCITY - 7 entries
// r = (a5,a6,a7)
// n.(a1*u + a2*t) = n.r
// (I - nn.)(a3*u + a4*t) = (I-nn.)r
//
// BOUNDARY_CONDITION_PRESSURE - 1 entry
//
// REFERENCE_VELOCITY - 3 entries
//
// REFERENCE_PRESSURE - 1 entry
//
// BOUNDARY_CONDTION - 3 entries (for calculation of phi and measures of drag and lift)

typedef Storage::real real;
const double eps = 1.0e-5;

int main(int argc, char ** argv)
{

	if( argc < 2 )
	{
		std::cout << "Usage: " << argv[0] << " mesh [mesh_out=grid_out.pmf]" << std::endl;
		return 0;
	}

	Mesh * m = new Mesh;
	m->SetFileOption("VERBOSITY","2");
	try
	{
		m->Load(argv[1]);
	}
	catch(...)
	{
		std::cout << "Cannot load the mesh " << argv[1] << std::endl;
		return -1;
	}

	std::string fout = "grid_out.pmf";
	double Umax = 2.25;
	int fix_cylinder = 0;
	if( argc > 2 ) fout = std::string(argv[2]);
	if( argc > 3 ) Umax = atof(argv[3]);
	if( argc > 4 ) fix_cylinder = atoi(argv[4]);

	double cmax[3] = {-1.0e20,-1.0e20,-1.0e20}, cmin[3] = {1.0e20,1.0e20,1.0e20};
	for(Mesh::iteratorNode n = m->BeginNode(); n != m->EndNode(); ++n)
	{
		Storage::real_array c = n->Coords();
		for(int k = 0; k < 3; ++k)
		{
			if( cmax[k] < c[k] ) cmax[k] = c[k];
			if( cmin[k] > c[k] ) cmin[k] = c[k];
		}
	}
	for(int d = 0; d < 3; ++d)
		std::cout << d << " " << cmin[d] << ":" << cmax[d] << std::endl;

	//TagRealArray force = m->CreateTag("FORCE",DATA_REAL,CELL,NONE,3);
	TagRealArray  bc      = m->CreateTag("BOUNDARY_CONDITION_VELOCITY",DATA_REAL,FACE,FACE,7);
	TagReal       bcp     = m->CreateTag("BOUNDARY_CONDITION_PRESSURE",DATA_REAL,FACE,FACE,1);
	TagInteger    bb      = m->CreateTag("BOUNDARY_BLOOD",DATA_INTEGER,FACE,FACE,1);
	TagRealArray  uvw     = m->CreateTag("UVW",DATA_REAL,CELL,NONE,3);
	TagReal       p       = m->CreateTag("P",DATA_REAL,CELL,NONE,1);
	m->self().Real(m->CreateTag("Umax",DATA_REAL,MESH,NONE,1)) = Umax;

	//this should not be needed?
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
		it->FixNormalOrientation();

	{ // prepare geometrical data on the mesh
		Mesh::GeomParam table;
		table[CENTROID]    = CELL | FACE; //Compute averaged center of mass
		table[NORMAL]      = FACE;        //Compute normals
		table[MEASURE]     = CELL | FACE; //Compute volumes and areas
		table[BARYCENTER]  = CELL | FACE; //Compute volumetric center of mass
		m->RemoveGeometricData(table); //Ask to precompute the data
	}
	bool onep = false;
	for(Mesh::iteratorFace it = m->BeginFace(); it != m->EndFace(); ++it) if( it->Boundary() )
	{
		double  n[3], c[3];
		it->UnitNormal(n);
		it->Centroid(c);
		bb[*it] = 0;
		if( fabs(n[0]-1) < 1.0e-3 && c[0] > 1.8+eps) // outflow
		{
			//~ bcp[*it] = 0;
			//~ if( !onep )
			{
				//~ onep = true;
				bc[*it][0] = 0;
				bc[*it][1] = 1;
				bc[*it][2] = 0;
				bc[*it][3] = 1;
				bc[*it][4] = 0;
				bc[*it][5] = 0;
				bc[*it][6] = 0;
			}
			//~ else
			//~ {
				//~ bc[*it][0] = 1;
				//~ bc[*it][1] = 0;
				//~ bc[*it][2] = 1;
				//~ bc[*it][3] = 0;
				//~ bc[*it][4] = 17.3 * c[1]*(3.0-c[1])/9.0 * 4.0 * (3.0 / 2.0); //parabolic profile with average of 17.3
				//~ bc[*it][5] = 0;
				//~ bc[*it][6] = 0;
			//~ }
		}
		else if(  fabs(n[0]+1) < 1.0e-3 && c[0] < 0.0+eps) //inflow
		{
			bb[*it] = 1;
			//~ bcp[*it] = 0.13;
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 17.3 * c[1]*(3.0-c[1])/9.0 * 4.0 * (3.0 / 2.0); //parabolic profile with average of 17.3
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else if( (fabs(n[1]-1) < 1.0e-3 && c[1] > 1.5-eps) || (fabs(n[2]-1) < 1.0e-3 && c[2] > 0.1-eps) || (fabs(n[2]+1) < 1.0e-3 && c[2] < 0.0+eps) ) //slip wall
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 0;
			bc[*it][3] = 1;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
		else //no-slip walls
		{
			bc[*it][0] = 1;
			bc[*it][1] = 0;
			bc[*it][2] = 1;
			bc[*it][3] = 0;
			bc[*it][4] = 0;
			bc[*it][5] = 0;
			bc[*it][6] = 0;
		}
	}

	std::cout << "Saving output to " << fout << std::endl;

	m->Save(fout);

	return 0;
}
<|endoftext|>


<commit_before>/*
 * File:   remlog.cpp
 * Author: Oleg Zharkov
 *
 * Created on February 27, 2014, 3:07 PM
 */

#include <sstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include "remlog.h"

int RemLog::GetConfig() {

    //Read sinks config
    if(!sk.GetConfig()) return 0;

    status = 1;
    return status;
}

int RemLog::Open() {

    if (!sk.Open()) return 0;

    return 1;
}

void  RemLog::Close() {
    sk.Close();
}

int RemLog::Go(void) {

    while (!q_logs_nids.empty() || !q_logs_hids.empty()) {

        if (!q_logs_nids.empty()) {
            q_logs_nids.pop(rec);
            logs_list.push_back(rec);
            counter++;
        }

        if (!q_logs_hids.empty()) {
            q_logs_hids.pop(rec);
            logs_list.push_back(rec);
            counter++;
        }
    }

    if (counter < 100 && timeout < 10) {
        usleep(GetGosleepTimer()*60);
        timeout++;
    }
    else {
        ProcessLogs();
        counter = 0;
        timeout = 0;
    }

    return 1;
}

void RemLog::ProcessLogs() {

    if (!logs_list.empty()) {
        report = "{ \"logs\" : [";

        std::vector<string>::iterator i, end;

        int j = 0;
        for(i = logs_list.begin(), end = logs_list.end(); i != end; ++i) {

            report += *i;

            if ( j < logs_list.size() - 1) {
                report += ", ";
                j++;
            }
        }
        report += " ] }";
        logs_list.clear();

        // SysLog((char*) report.c_str());

        ss << report;

        boost::iostreams::filtering_streambuf< boost::iostreams::input> in;
        in.push(boost::iostreams::gzip_compressor());
        in.push(ss);
        boost::iostreams::copy(in, comp);

        int rep_size = comp.str().length();
        IncrementEventsCounter();
        IncrementEventsVolume(rep_size);

        //string s = std::to_string(rep_size);
        //string output = "logs compressed = " + s;
        //SysLog((char*) output.c_str());
        bd.data = comp.str();
        sk.SendMessage(&bd);

        ResetStreams();
    }
}

long RemLog::ResetEventsVolume() {
    unsigned long r;

    r = events_volume;
    events_volume = 0;

    return r;
}

void RemLog::IncrementEventsVolume(int inc) {

    events_volume = events_volume + inc;

}
<commit_msg>add event type for log<commit_after>/*
 * File:   remlog.cpp
 * Author: Oleg Zharkov
 *
 * Created on February 27, 2014, 3:07 PM
 */

#include <sstream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include "remlog.h"

int RemLog::GetConfig() {

    //Read sinks config
    if(!sk.GetConfig()) return 0;

    status = 1;
    return status;
}

int RemLog::Open() {

    if (!sk.Open()) return 0;

    return 1;
}

void  RemLog::Close() {
    sk.Close();
}

int RemLog::Go(void) {

    while (!q_logs_nids.empty() || !q_logs_hids.empty()) {

        if (!q_logs_nids.empty()) {
            q_logs_nids.pop(rec);
            logs_list.push_back(rec);
            counter++;
        }

        if (!q_logs_hids.empty()) {
            q_logs_hids.pop(rec);
            logs_list.push_back(rec);
            counter++;
        }
    }

    if (counter < 100 && timeout < 10) {
        usleep(GetGosleepTimer()*60);
        timeout++;
    }
    else {
        ProcessLogs();
        counter = 0;
        timeout = 0;
    }

    return 1;
}

void RemLog::ProcessLogs() {

    if (!logs_list.empty()) {
        report = "{ \"logs\" : [";

        std::vector<string>::iterator i, end;

        int j = 0;
        for(i = logs_list.begin(), end = logs_list.end(); i != end; ++i) {

            report += *i;

            if ( j < logs_list.size() - 1) {
                report += ", ";
                j++;
            }
        }
        report += " ] }";
        logs_list.clear();

        // SysLog((char*) report.c_str());

        ss << report;

        boost::iostreams::filtering_streambuf< boost::iostreams::input> in;
        in.push(boost::iostreams::gzip_compressor());
        in.push(ss);
        boost::iostreams::copy(in, comp);

        int rep_size = comp.str().length();
        IncrementEventsCounter();
        IncrementEventsVolume(rep_size);

        //string s = std::to_string(rep_size);
        //string output = "logs compressed = " + s;
        //SysLog((char*) output.c_str());
        bd.data = comp.str();
        bd.event_type = 2;
        sk.SendMessage(&bd);

        ResetStreams();
    }
}

long RemLog::ResetEventsVolume() {
    unsigned long r;

    r = events_volume;
    events_volume = 0;

    return r;
}

void RemLog::IncrementEventsVolume(int inc) {

    events_volume = events_volume + inc;

}
<|endoftext|>


<commit_before>//===--- GoogleTidyModule.cpp - clang-tidy --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "GoogleTidyModule.h"
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {

void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(constructorDecl().bind("ctor"), this);
}

// Looks for the token matching the predicate and returns the range of the found
// token including trailing whitespace.
SourceRange FindToken(const SourceManager &Sources, LangOptions LangOpts,
                      SourceLocation StartLoc, SourceLocation EndLoc,
                      bool (*Pred)(const Token &)) {
  if (StartLoc.isMacroID() || EndLoc.isMacroID())
    return SourceRange();
  FileID File = Sources.getFileID(Sources.getSpellingLoc(StartLoc));
  StringRef Buf = Sources.getBufferData(File);
  const char *StartChar = Sources.getCharacterData(StartLoc);
  Lexer Lex(StartLoc, LangOpts, StartChar, StartChar, Buf.end());
  Lex.SetCommentRetentionState(true);
  Token Tok;
  do {
    Lex.LexFromRawLexer(Tok);
    if (Pred(Tok)) {
      Token NextTok;
      Lex.LexFromRawLexer(NextTok);
      return SourceRange(Tok.getLocation(), NextTok.getLocation());
    }
  } while (Tok.isNot(tok::eof) && Tok.getLocation() < EndLoc);

  return SourceRange();
}

void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
  const CXXConstructorDecl *Ctor =
      Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
  // Do not be confused: isExplicit means 'explicit' keyword is present,
  // isImplicit means that it's a compiler-generated constructor.
  if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted())
    return;

  if (Ctor->isExplicit() && Ctor->isCopyOrMoveConstructor()) {
    auto isKWExplicit = [](const Token &Tok) {
      return Tok.is(tok::raw_identifier) &&
             StringRef(Tok.getRawIdentifierData(), Tok.getLength()) ==
                 "explicit";
    };
    SourceRange ExplicitTokenRange =
        FindToken(*Result.SourceManager, Result.Context->getLangOpts(),
                  Ctor->getOuterLocStart(), Ctor->getLocEnd(), isKWExplicit);
    DiagnosticBuilder Diag =
        diag(Ctor->getLocation(), "%0 constructor declared explicit.")
        << (Ctor->isMoveConstructor() ? "Move" : "Copy");
    if (ExplicitTokenRange.isValid()) {
      Diag << FixItHint::CreateRemoval(
          CharSourceRange::getCharRange(ExplicitTokenRange));
    }
  }

  if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() ||
      Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1)
    return;

  SourceLocation Loc = Ctor->getLocation();
  diag(Loc, "Single-argument constructors must be explicit")
      << FixItHint::CreateInsertion(Loc, "explicit ");
}

class GoogleModule : public ClangTidyModule {
public:
  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
    CheckFactories.addCheckFactory(
        "google-explicit-constructor",
        new ClangTidyCheckFactory<ExplicitConstructorCheck>());
  }
};

// Register the GoogleTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<GoogleModule> X("google-module",
                                                    "Adds Google lint checks.");

// This anchor is used to force the linker to link in the generated object file
// and thus register the GoogleModule.
volatile int GoogleModuleAnchorSource = 0;

} // namespace tidy
} // namespace clang
<commit_msg>Track clang changes from r209061<commit_after>//===--- GoogleTidyModule.cpp - clang-tidy --------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "GoogleTidyModule.h"
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {

void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
  Finder->addMatcher(constructorDecl().bind("ctor"), this);
}

// Looks for the token matching the predicate and returns the range of the found
// token including trailing whitespace.
SourceRange FindToken(const SourceManager &Sources, LangOptions LangOpts,
                      SourceLocation StartLoc, SourceLocation EndLoc,
                      bool (*Pred)(const Token &)) {
  if (StartLoc.isMacroID() || EndLoc.isMacroID())
    return SourceRange();
  FileID File = Sources.getFileID(Sources.getSpellingLoc(StartLoc));
  StringRef Buf = Sources.getBufferData(File);
  const char *StartChar = Sources.getCharacterData(StartLoc);
  Lexer Lex(StartLoc, LangOpts, StartChar, StartChar, Buf.end());
  Lex.SetCommentRetentionState(true);
  Token Tok;
  do {
    Lex.LexFromRawLexer(Tok);
    if (Pred(Tok)) {
      Token NextTok;
      Lex.LexFromRawLexer(NextTok);
      return SourceRange(Tok.getLocation(), NextTok.getLocation());
    }
  } while (Tok.isNot(tok::eof) && Tok.getLocation() < EndLoc);

  return SourceRange();
}

void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
  const CXXConstructorDecl *Ctor =
      Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
  // Do not be confused: isExplicit means 'explicit' keyword is present,
  // isImplicit means that it's a compiler-generated constructor.
  if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted())
    return;

  if (Ctor->isExplicit() && Ctor->isCopyOrMoveConstructor()) {
    auto isKWExplicit = [](const Token &Tok) {
      return Tok.is(tok::raw_identifier) &&
             Tok.getRawIdentifier() == "explicit";
    };
    SourceRange ExplicitTokenRange =
        FindToken(*Result.SourceManager, Result.Context->getLangOpts(),
                  Ctor->getOuterLocStart(), Ctor->getLocEnd(), isKWExplicit);
    DiagnosticBuilder Diag =
        diag(Ctor->getLocation(), "%0 constructor declared explicit.")
        << (Ctor->isMoveConstructor() ? "Move" : "Copy");
    if (ExplicitTokenRange.isValid()) {
      Diag << FixItHint::CreateRemoval(
          CharSourceRange::getCharRange(ExplicitTokenRange));
    }
  }

  if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() ||
      Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1)
    return;

  SourceLocation Loc = Ctor->getLocation();
  diag(Loc, "Single-argument constructors must be explicit")
      << FixItHint::CreateInsertion(Loc, "explicit ");
}

class GoogleModule : public ClangTidyModule {
public:
  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
    CheckFactories.addCheckFactory(
        "google-explicit-constructor",
        new ClangTidyCheckFactory<ExplicitConstructorCheck>());
  }
};

// Register the GoogleTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<GoogleModule> X("google-module",
                                                    "Adds Google lint checks.");

// This anchor is used to force the linker to link in the generated object file
// and thus register the GoogleModule.
volatile int GoogleModuleAnchorSource = 0;

} // namespace tidy
} // namespace clang
<|endoftext|>


<commit_before>#pragma once

namespace helene
{
}
<commit_msg>Add template dependent member variables. 	modified:   include/dag.hpp<commit_after>#pragma once

#include <vector>

namespace helene
{
template <class NodeType, class EdgeType> class dag
{
private:
    ////////////////////////////////////////////////////////////////////////////
    // internal classes

public:
    dag() = default;

private:
    std::vector<NodeType> node_properties_;
    std::vector<EdgeType> edge_properties_;
};
}
<|endoftext|>


<commit_before><commit_msg>using tolerance<commit_after><|endoftext|>


<commit_before>class Solution {
public:
    /**
     * @param k: An integer
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(int k, vector<int> &prices) {
        // write your code here
    }
};<commit_msg>Find a solution<commit_after>class Solution {
public:
    /**
     * @param k: An integer
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(int k, vector<int> &prices) {
        if (prices.empty())
            return 0;

        int ans = 0;
        if (k >= prices.size() / 2)
        {
            for (int i = 1; i < prices.size(); ++i) {
                if (prices[i] - prices[i - 1] > 0) {
                    ans += prices[i] - prices[i - 1];
                }
            }
        } else {
            vector<int> local(k+1);
            vector<int> global(k+1);

            for (int i = 0; i < prices.size() - 1; ++i) {
                int increase = prices[i + 1] - prices[i];

                for (int j = k; j >= 1; --j) {
                    local[j] = max(global[j - 1] + max(increase, 0), local[j] + increase);
                    global[j] = max(global[j], local[j]);
                }
            }
            ans = global[k];
        }
        return ans;
    }

};<|endoftext|>