<commit_before>#ifndef BAYES_CLASSIFIER_HPP
#define BAYES_CLASSIFIER_HPP

#include <cmath>

#include <vector>
#include <utility>

#include <boost/math/constants/constants.hpp>

namespace osrm
{
namespace engine
{
namespace map_matching
{

struct NormalDistribution
{
    NormalDistribution(const double mean, const double standard_deviation)
        : mean(mean), standard_deviation(standard_deviation)
    {
    }

    // FIXME implement log-probability version since it's faster
    double density_function(const double val) const
    {
        using namespace boost::math::constants;

        const double x = val - mean;
        return 1.0 / (std::sqrt(two_pi<double>()) * standard_deviation) *
               std::exp(-x * x / (standard_deviation * standard_deviation));
    }

    double mean;
    double standard_deviation;
};

struct LaplaceDistribution
{
    LaplaceDistribution(const double location, const double scale)
        : location(location), scale(scale)
    {
    }

    // FIXME implement log-probability version since it's faster
    double density_function(const double val) const
    {
        const double x = std::abs(val - location);
        return 1.0 / (2. * scale) * std::exp(-x / scale);
    }

    double location;
    double scale;
};

template <typename PositiveDistributionT, typename NegativeDistributionT, typename ValueT>
class BayesClassifier
{
  public:
    enum class ClassLabel : unsigned
    {
        NEGATIVE,
        POSITIVE
    };
    using ClassificationT = std::pair<ClassLabel, double>;

    BayesClassifier(PositiveDistributionT positive_distribution,
                    NegativeDistributionT negative_distribution,
                    const double positive_apriori_probability)
        : positive_distribution(std::move(positive_distribution)),
          negative_distribution(std::move(negative_distribution)),
          positive_apriori_probability(positive_apriori_probability),
          negative_apriori_probability(1. - positive_apriori_probability)
    {
    }

    // Returns label and the probability of the label.
    ClassificationT classify(const ValueT &v) const
    {
        const double positive_postpriori =
            positive_apriori_probability * positive_distribution.density_function(v);
        const double negative_postpriori =
            negative_apriori_probability * negative_distribution.density_function(v);
        const double norm = positive_postpriori + negative_postpriori;

        if (positive_postpriori > negative_postpriori)
        {
            return std::make_pair(ClassLabel::POSITIVE, positive_postpriori / norm);
        }

        return std::make_pair(ClassLabel::NEGATIVE, negative_postpriori / norm);
    }

  private:
    PositiveDistributionT positive_distribution;
    NegativeDistributionT negative_distribution;
    double positive_apriori_probability;
    double negative_apriori_probability;
};
}
}
}

#endif // BAYES_CLASSIFIER_HPP
<commit_msg>Fix naming convention in BayesClassifier<commit_after>#ifndef BAYES_CLASSIFIER_HPP
#define BAYES_CLASSIFIER_HPP

#include <cmath>

#include <vector>
#include <utility>

#include <boost/math/constants/constants.hpp>

namespace osrm
{
namespace engine
{
namespace map_matching
{

struct NormalDistribution
{
    NormalDistribution(const double mean, const double standard_deviation)
        : mean(mean), standard_deviation(standard_deviation)
    {
    }

    // FIXME implement log-probability version since it's faster
    double Density(const double val) const
    {
        using namespace boost::math::constants;

        const double x = val - mean;
        return 1.0 / (std::sqrt(two_pi<double>()) * standard_deviation) *
               std::exp(-x * x / (standard_deviation * standard_deviation));
    }

    double mean;
    double standard_deviation;
};

struct LaplaceDistribution
{
    LaplaceDistribution(const double location, const double scale)
        : location(location), scale(scale)
    {
    }

    // FIXME implement log-probability version since it's faster
    double Density(const double val) const
    {
        const double x = std::abs(val - location);
        return 1.0 / (2. * scale) * std::exp(-x / scale);
    }

    double location;
    double scale;
};

template <typename PositiveDistributionT, typename NegativeDistributionT, typename ValueT>
class BayesClassifier
{
  public:
    enum class ClassLabel : unsigned
    {
        NEGATIVE,
        POSITIVE
    };
    using ClassificationT = std::pair<ClassLabel, double>;

    BayesClassifier(PositiveDistributionT positive_distribution,
                    NegativeDistributionT negative_distribution,
                    const double positive_apriori_probability)
        : positive_distribution(std::move(positive_distribution)),
          negative_distribution(std::move(negative_distribution)),
          positive_apriori_probability(positive_apriori_probability),
          negative_apriori_probability(1. - positive_apriori_probability)
    {
    }

    // Returns label and the probability of the label.
    ClassificationT classify(const ValueT &v) const
    {
        const double positive_postpriori =
            positive_apriori_probability * positive_distribution.Density(v);
        const double negative_postpriori =
            negative_apriori_probability * negative_distribution.Density(v);
        const double norm = positive_postpriori + negative_postpriori;

        if (positive_postpriori > negative_postpriori)
        {
            return std::make_pair(ClassLabel::POSITIVE, positive_postpriori / norm);
        }

        return std::make_pair(ClassLabel::NEGATIVE, negative_postpriori / norm);
    }

  private:
    PositiveDistributionT positive_distribution;
    NegativeDistributionT negative_distribution;
    double positive_apriori_probability;
    double negative_apriori_probability;
};
}
}
}

#endif // BAYES_CLASSIFIER_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "top_panel.hpp"
#include "account.hpp"
#include "account_list_ctrl.hpp"
#include "draft_journal_list_ctrl.hpp"
#include "draft_journal_reader.hpp"
#include "entry_list_ctrl.hpp"
#include "frame.hpp"
#include "ordinary_journal.hpp"
#include "phatbooks_database_connection.hpp"
#include "sizing.hpp"
#include "transaction_ctrl.hpp"
#include <boost/optional.hpp>
#include <jewel/optional.hpp>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/string.h>
#include <cassert>
#include <vector>

using boost::optional;
using jewel::value;
using std::vector;

namespace phatbooks
{
namespace gui
{

TopPanel::TopPanel
(	Frame* p_parent,
	PhatbooksDatabaseConnection& p_database_connection
):
	wxPanel
	(	p_parent,
		wxID_ANY,
		wxDefaultPosition,
		wxDefaultSize,
		wxFULL_REPAINT_ON_RESIZE
	),
	m_database_connection(p_database_connection),
	m_top_sizer(0),
	m_notebook(0),
	m_notebook_page_1(0),
	m_notebook_page_2(0),
	m_right_column_sizer(0),
	m_bs_account_list(0),
	m_pl_account_list(0),
	m_entry_list(0),
	m_transaction_ctrl(0),
	m_draft_journal_list(0)
{
	m_top_sizer = new wxBoxSizer(wxHORIZONTAL);
	m_notebook = new wxNotebook
	(	this,
		wxID_ANY,
		wxDefaultPosition,
		wxDefaultSize,
		wxNB_TOP
	);
	m_right_column_sizer = new wxBoxSizer(wxVERTICAL);
	m_top_sizer->Add
	(	m_notebook,
		wxSizerFlags(6).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border())
	);
	m_notebook_page_1 = new wxPanel(m_notebook, wxID_ANY);
	m_notebook_page_2 = new wxPanel(m_notebook, wxID_ANY);
	m_notebook->AddPage(m_notebook_page_1, wxString("Balances"), true);
	m_notebook->AddPage(m_notebook_page_2, wxString("Transactions"), false);
	m_top_sizer->Add
	(	m_right_column_sizer,
		wxSizerFlags(4).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border())
	);
	configure_account_lists();
	configure_entry_list();
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	SetSizer(m_top_sizer);
	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	Layout();
}

// TODO We have no consistent convention here about what is "configure" and
// what is "update", and when each such function gets called (i.e. once, or
// every update, or...?).

void
TopPanel::configure_account_lists()
{
	assert (m_notebook_page_1);
	m_bs_account_list = AccountListCtrl::create_balance_sheet_account_list
	(	m_notebook_page_1,
		m_database_connection
	);
	m_pl_account_list = AccountListCtrl::create_pl_account_list
	(	m_notebook_page_1,
		m_database_connection
	);
	wxBoxSizer* page_1_sizer = new wxBoxSizer(wxHORIZONTAL);
	page_1_sizer->Add
	(	m_bs_account_list,
		wxSizerFlags(2).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST, standard_border())
	);
	page_1_sizer->Add
	(	m_pl_account_list,
		wxSizerFlags(3).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST, standard_border())
	);
	m_notebook_page_1->SetSizer(page_1_sizer);
	page_1_sizer->Fit(m_notebook_page_1);
	page_1_sizer->SetSizeHints(m_notebook_page_1);
	m_notebook_page_1->Fit();
	Layout();
	return;
}

void
TopPanel::configure_entry_list()
{
	assert (m_notebook_page_2);
	assert (m_notebook_page_1);
	m_entry_list = EntryListCtrl::create_actual_ordinary_entry_list
	(	m_notebook_page_2,
		m_database_connection
	);
	wxBoxSizer* page_2_sizer = new wxBoxSizer(wxHORIZONTAL);
	m_notebook_page_2->SetSizer(page_2_sizer);
	page_2_sizer->Add(m_entry_list, wxSizerFlags(1).Expand());
	page_2_sizer->Fit(m_notebook_page_2);
	page_2_sizer->SetSizeHints(m_notebook_page_2);
	m_notebook_page_2->Fit();
	Layout();
	return;
}

void
TopPanel::configure_transaction_ctrl()
{
	assert (m_top_sizer);
	assert (m_right_column_sizer);
	vector<Account> balance_sheet_accounts;
	selected_balance_sheet_accounts(balance_sheet_accounts);
	vector<Account> pl_accounts;
	selected_pl_accounts(pl_accounts);
	configure_transaction_ctrl(balance_sheet_accounts, pl_accounts);
	return;
}

void
TopPanel::configure_transaction_ctrl
(	vector<Account> p_balance_sheet_accounts,
	vector<Account> p_pl_accounts
)
{
	if (p_balance_sheet_accounts.size() + p_pl_accounts.size() < unsigned(2))
	{
		if (p_balance_sheet_accounts.empty())
		{
			optional<Account> const maybe_bs_account =
				m_bs_account_list->default_account();
			if (maybe_bs_account)
			{
				p_balance_sheet_accounts.push_back(value(maybe_bs_account));
			}
		}
		if (p_pl_accounts.empty())
		{
			optional<Account> const maybe_pl_account =
				m_pl_account_list->default_account();
			if (maybe_pl_account)
			{
				p_pl_accounts.push_back(value(maybe_pl_account));
			}
		}
	}
	TransactionCtrl* old = 0;
	assert (m_right_column_sizer);
	if (m_transaction_ctrl)
	{
		m_right_column_sizer->Detach(m_transaction_ctrl);
		old = m_transaction_ctrl;
	}
	m_transaction_ctrl = new TransactionCtrl
	(	this,
		p_balance_sheet_accounts,
		p_pl_accounts,
		m_database_connection
	);
	m_right_column_sizer->Add
	(	m_transaction_ctrl,
		wxSizerFlags(6).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border() * 2)
	);
	if (old)
	{
		old->Destroy();
		old = 0;
	}
	Layout();
	return;
}

void
TopPanel::configure_draft_journal_list_ctrl()
{
	DraftJournalListCtrl* old = 0;
	assert (m_right_column_sizer);
	if (m_draft_journal_list)
	{
		m_right_column_sizer->Detach(m_draft_journal_list);
		old = m_draft_journal_list;
	}
	UserDraftJournalReader const reader(m_database_connection);
	m_draft_journal_list = new DraftJournalListCtrl
	(	this,
		wxDefaultSize,
		reader
	);
	m_right_column_sizer->Add(m_draft_journal_list, wxSizerFlags(1).Expand());
	if (old)
	{
		old->Destroy();
		old = 0;
	}
	Layout();
	return;
}

void
TopPanel::selected_balance_sheet_accounts(vector<Account>& out) const
{
	m_bs_account_list->selected_accounts(out);
	return;
}

void
TopPanel::selected_pl_accounts(vector<Account>& out) const
{
	m_pl_account_list->selected_accounts(out);
	return;
}

void
TopPanel::update_for(OrdinaryJournal const& p_saved_object)
{
	m_bs_account_list->update(true);
	m_pl_account_list->update(false);
	m_entry_list->update_for_posted_journal(p_saved_object);
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

void
TopPanel::update_for(DraftJournal const& p_saved_object)
{
	(void)p_saved_object;  // Silence compiler re. unused parameter.
	// m_bs_account_list->update(true);  // No point doing this here.
	// m_pl_account_list->update(false); // No point doing this here.
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

void
TopPanel::update_for(Account const& p_saved_object)
{
	// TODO HIGH PRIORITY Need to update for opening balance journal as well??
	(void)p_saved_object;  // Silence compiler re. unused parameter.
	m_bs_account_list->update(true);
	m_pl_account_list->update(false);
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

}  // namespace gui
}  // namespace phatbooks

<commit_msg>Created TODO re. DraftJournalListCtrl and TransactionCtrl swapping places in the display, when TopPanel is updated.<commit_after>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#include "top_panel.hpp"
#include "account.hpp"
#include "account_list_ctrl.hpp"
#include "draft_journal_list_ctrl.hpp"
#include "draft_journal_reader.hpp"
#include "entry_list_ctrl.hpp"
#include "frame.hpp"
#include "ordinary_journal.hpp"
#include "phatbooks_database_connection.hpp"
#include "sizing.hpp"
#include "transaction_ctrl.hpp"
#include <boost/optional.hpp>
#include <jewel/optional.hpp>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/string.h>
#include <cassert>
#include <vector>

using boost::optional;
using jewel::value;
using std::vector;

namespace phatbooks
{
namespace gui
{

TopPanel::TopPanel
(	Frame* p_parent,
	PhatbooksDatabaseConnection& p_database_connection
):
	wxPanel
	(	p_parent,
		wxID_ANY,
		wxDefaultPosition,
		wxDefaultSize,
		wxFULL_REPAINT_ON_RESIZE
	),
	m_database_connection(p_database_connection),
	m_top_sizer(0),
	m_notebook(0),
	m_notebook_page_1(0),
	m_notebook_page_2(0),
	m_right_column_sizer(0),
	m_bs_account_list(0),
	m_pl_account_list(0),
	m_entry_list(0),
	m_transaction_ctrl(0),
	m_draft_journal_list(0)
{
	m_top_sizer = new wxBoxSizer(wxHORIZONTAL);
	m_notebook = new wxNotebook
	(	this,
		wxID_ANY,
		wxDefaultPosition,
		wxDefaultSize,
		wxNB_TOP
	);
	m_right_column_sizer = new wxBoxSizer(wxVERTICAL);
	m_top_sizer->Add
	(	m_notebook,
		wxSizerFlags(6).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border())
	);
	m_notebook_page_1 = new wxPanel(m_notebook, wxID_ANY);
	m_notebook_page_2 = new wxPanel(m_notebook, wxID_ANY);
	m_notebook->AddPage(m_notebook_page_1, wxString("Balances"), true);
	m_notebook->AddPage(m_notebook_page_2, wxString("Transactions"), false);
	m_top_sizer->Add
	(	m_right_column_sizer,
		wxSizerFlags(4).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border())
	);
	configure_account_lists();
	configure_entry_list();
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	SetSizer(m_top_sizer);
	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	Layout();
}

// TODO We have no consistent convention here about what is "configure" and
// what is "update", and when each such function gets called (i.e. once, or
// every update, or...?).

// TODO The TransactionCtrl and the DraftJournalListCtrl swap places in the
// display when updated. Need to fix.

void
TopPanel::configure_account_lists()
{
	assert (m_notebook_page_1);
	m_bs_account_list = AccountListCtrl::create_balance_sheet_account_list
	(	m_notebook_page_1,
		m_database_connection
	);
	m_pl_account_list = AccountListCtrl::create_pl_account_list
	(	m_notebook_page_1,
		m_database_connection
	);
	wxBoxSizer* page_1_sizer = new wxBoxSizer(wxHORIZONTAL);
	page_1_sizer->Add
	(	m_bs_account_list,
		wxSizerFlags(2).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST, standard_border())
	);
	page_1_sizer->Add
	(	m_pl_account_list,
		wxSizerFlags(3).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST, standard_border())
	);
	m_notebook_page_1->SetSizer(page_1_sizer);
	page_1_sizer->Fit(m_notebook_page_1);
	page_1_sizer->SetSizeHints(m_notebook_page_1);
	m_notebook_page_1->Fit();
	Layout();
	return;
}

void
TopPanel::configure_entry_list()
{
	assert (m_notebook_page_2);
	assert (m_notebook_page_1);
	m_entry_list = EntryListCtrl::create_actual_ordinary_entry_list
	(	m_notebook_page_2,
		m_database_connection
	);
	wxBoxSizer* page_2_sizer = new wxBoxSizer(wxHORIZONTAL);
	m_notebook_page_2->SetSizer(page_2_sizer);
	page_2_sizer->Add(m_entry_list, wxSizerFlags(1).Expand());
	page_2_sizer->Fit(m_notebook_page_2);
	page_2_sizer->SetSizeHints(m_notebook_page_2);
	m_notebook_page_2->Fit();
	Layout();
	return;
}

void
TopPanel::configure_transaction_ctrl()
{
	assert (m_top_sizer);
	assert (m_right_column_sizer);
	vector<Account> balance_sheet_accounts;
	selected_balance_sheet_accounts(balance_sheet_accounts);
	vector<Account> pl_accounts;
	selected_pl_accounts(pl_accounts);
	configure_transaction_ctrl(balance_sheet_accounts, pl_accounts);
	return;
}

void
TopPanel::configure_transaction_ctrl
(	vector<Account> p_balance_sheet_accounts,
	vector<Account> p_pl_accounts
)
{
	if (p_balance_sheet_accounts.size() + p_pl_accounts.size() < unsigned(2))
	{
		if (p_balance_sheet_accounts.empty())
		{
			optional<Account> const maybe_bs_account =
				m_bs_account_list->default_account();
			if (maybe_bs_account)
			{
				p_balance_sheet_accounts.push_back(value(maybe_bs_account));
			}
		}
		if (p_pl_accounts.empty())
		{
			optional<Account> const maybe_pl_account =
				m_pl_account_list->default_account();
			if (maybe_pl_account)
			{
				p_pl_accounts.push_back(value(maybe_pl_account));
			}
		}
	}
	TransactionCtrl* old = 0;
	assert (m_right_column_sizer);
	if (m_transaction_ctrl)
	{
		m_right_column_sizer->Detach(m_transaction_ctrl);
		old = m_transaction_ctrl;
	}
	m_transaction_ctrl = new TransactionCtrl
	(	this,
		p_balance_sheet_accounts,
		p_pl_accounts,
		m_database_connection
	);
	m_right_column_sizer->Add
	(	m_transaction_ctrl,
		wxSizerFlags(6).Expand().
			Border(wxNORTH | wxSOUTH | wxWEST | wxEAST, standard_border() * 2)
	);
	if (old)
	{
		old->Destroy();
		old = 0;
	}
	Layout();
	return;
}

void
TopPanel::configure_draft_journal_list_ctrl()
{
	DraftJournalListCtrl* old = 0;
	assert (m_right_column_sizer);
	if (m_draft_journal_list)
	{
		m_right_column_sizer->Detach(m_draft_journal_list);
		old = m_draft_journal_list;
	}
	UserDraftJournalReader const reader(m_database_connection);
	m_draft_journal_list = new DraftJournalListCtrl
	(	this,
		wxDefaultSize,
		reader
	);
	m_right_column_sizer->Add(m_draft_journal_list, wxSizerFlags(1).Expand());
	if (old)
	{
		old->Destroy();
		old = 0;
	}
	Layout();
	return;
}

void
TopPanel::selected_balance_sheet_accounts(vector<Account>& out) const
{
	m_bs_account_list->selected_accounts(out);
	return;
}

void
TopPanel::selected_pl_accounts(vector<Account>& out) const
{
	m_pl_account_list->selected_accounts(out);
	return;
}

void
TopPanel::update_for(OrdinaryJournal const& p_saved_object)
{
	m_bs_account_list->update(true);
	m_pl_account_list->update(false);
	m_entry_list->update_for_posted_journal(p_saved_object);
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

void
TopPanel::update_for(DraftJournal const& p_saved_object)
{
	(void)p_saved_object;  // Silence compiler re. unused parameter.
	// m_bs_account_list->update(true);  // No point doing this here.
	// m_pl_account_list->update(false); // No point doing this here.
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

void
TopPanel::update_for(Account const& p_saved_object)
{
	// TODO HIGH PRIORITY Need to update for opening balance journal as well??
	(void)p_saved_object;  // Silence compiler re. unused parameter.
	m_bs_account_list->update(true);
	m_pl_account_list->update(false);
	configure_transaction_ctrl();
	configure_draft_journal_list_ctrl();
	return;
}

}  // namespace gui
}  // namespace phatbooks

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#if !defined LABEL_COLLISION_DETECTOR
#define LABEL_COLLISION_DETECTOR
// mapnik
#include <mapnik/quad_tree.hpp>
// stl
#include <vector>

namespace mapnik
{
   //this needs to be tree structure
   //as a proof of a concept _only_ we use sequential scan

   struct label_collision_detector
   {
         typedef std::vector<Envelope<double> > label_placements;

         bool has_plasement(Envelope<double> const& box)
         {
            label_placements::const_iterator itr=labels_.begin();
            for( ; itr !=labels_.end();++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }
            labels_.push_back(box);
            return true;
         }
         void clear()
         {
            labels_.clear();
         }

      private:

         label_placements labels_;
   };

   // quad_tree based label collision detector
   class label_collision_detector2 : boost::noncopyable
   {
         typedef quad_tree<Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector2(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            tree_.insert(box,box);
            return true;
         }

         void clear()
         {
            tree_.clear();
         }

   };

   // quad_tree based label collision detector with seperate check/insert
   class label_collision_detector3 : boost::noncopyable
   {
         typedef quad_tree< Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector3(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            return true;
         }

         void insert(Envelope<double> const& box)
         {
            tree_.insert(box, box);
         }

         void clear()
         {
            tree_.clear();
         }
   };

    //quad tree based label collission detector so labels dont appear within a given distance
    class label_collision_detector4 : boost::noncopyable
    {
        struct label
        {
            label(Envelope<double> const& b) : box(b) {}
            label(Envelope<double> const& b, std::wstring const& t) : box(b), text(t) {}

            Envelope<double> box;
            std::wstring text;
        };

        typedef quad_tree< label > tree_t;
        tree_t tree_;
    public:

        explicit label_collision_detector4(Envelope<double> const& extent)
            : tree_(extent) {}

        bool has_placement(Envelope<double> const& box)
        {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->box.intersects(box))
               {
                  return false;
               }
            }

            return true;
        }

        bool has_placement(Envelope<double> const& box, std::wstring const& text, double distance)
        {
            Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);

            tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
                if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
                {
                    return false;
                }
            }

            return true;
        }

         void insert(Envelope<double> const& box)
         {
            tree_.insert(label(box), box);
         }

         void insert(Envelope<double> const& box, std::wstring const& text)
         {
            tree_.insert(label(box, text), box);
         }

         void clear()
         {
            tree_.clear();
         }
    };
}

#endif
<commit_msg>added missing extent() method<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#if !defined LABEL_COLLISION_DETECTOR
#define LABEL_COLLISION_DETECTOR
// mapnik
#include <mapnik/quad_tree.hpp>
// stl
#include <vector>

namespace mapnik
{
   //this needs to be tree structure
   //as a proof of a concept _only_ we use sequential scan

   struct label_collision_detector
   {
         typedef std::vector<Envelope<double> > label_placements;

         bool has_plasement(Envelope<double> const& box)
         {
            label_placements::const_iterator itr=labels_.begin();
            for( ; itr !=labels_.end();++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }
            labels_.push_back(box);
            return true;
         }
         void clear()
         {
            labels_.clear();
         }

      private:

         label_placements labels_;
   };

   // quad_tree based label collision detector
   class label_collision_detector2 : boost::noncopyable
   {
         typedef quad_tree<Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector2(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            tree_.insert(box,box);
            return true;
         }

         void clear()
         {
            tree_.clear();
         }

   };

   // quad_tree based label collision detector with seperate check/insert
   class label_collision_detector3 : boost::noncopyable
   {
         typedef quad_tree< Envelope<double> > tree_t;
         tree_t tree_;
      public:

         explicit label_collision_detector3(Envelope<double> const& extent)
            : tree_(extent) {}

         bool has_placement(Envelope<double> const& box)
         {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->intersects(box))
               {
                  return false;
               }
            }

            return true;
         }

         void insert(Envelope<double> const& box)
         {
            tree_.insert(box, box);
         }

         void clear()
         {
            tree_.clear();
         }
   };

   //quad tree based label collission detector so labels dont appear within a given distance
   class label_collision_detector4 : boost::noncopyable
   {
         struct label
         {
               label(Envelope<double> const& b) : box(b) {}
               label(Envelope<double> const& b, std::wstring const& t) : box(b), text(t) {}

               Envelope<double> box;
               std::wstring text;
         };

         typedef quad_tree< label > tree_t;
         Envelope<double> extent_;
         tree_t tree_;

    public:

        explicit label_collision_detector4(Envelope<double> const& extent)
           : extent_(extent),
             tree_(extent) {}

        bool has_placement(Envelope<double> const& box)
        {
            tree_t::query_iterator itr = tree_.query_in_box(box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
               if (itr->box.intersects(box))
               {
                  return false;
               }
            }

            return true;
        }

        bool has_placement(Envelope<double> const& box, std::wstring const& text, double distance)
        {
            Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);

            tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
            tree_t::query_iterator end = tree_.query_end();

            for ( ;itr != end; ++itr)
            {
                if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
                {
                    return false;
                }
            }

            return true;
        }

         void insert(Envelope<double> const& box)
         {
            tree_.insert(label(box), box);
         }

         void insert(Envelope<double> const& box, std::wstring const& text)
         {
            tree_.insert(label(box, text), box);
         }

         void clear()
         {
            tree_.clear();
         }
         Envelope<double> const& extent() const
         {
            return extent_;
         }
    };
}

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef MTAC_CONSTANT_PROPAGATION_PROBLEM_H
#define MTAC_CONSTANT_PROPAGATION_PROBLEM_H

#include <unordered_map>
#include <memory>

#include "variant.hpp"
#include "assert.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/DataFlowProblem.hpp"
#include "mtac/EscapeAnalysis.hpp"

namespace eddic {

class Variable;

namespace mtac {

typedef boost::variant<std::string, double, int, std::shared_ptr<Variable>> ConstantValue;

class ConstantPropagationLattice {
    public:
        ConstantPropagationLattice(){}; //NAC
        ConstantPropagationLattice(ConstantValue value) : m_value(value) {}

        ConstantPropagationLattice(const ConstantPropagationLattice& rhs) : m_value(rhs.m_value) {}
        ConstantPropagationLattice& operator=(const ConstantPropagationLattice& rhs){
            m_value = rhs.m_value;

            return *this;
        }

        ConstantPropagationLattice(ConstantPropagationLattice&& rhs) : m_value(std::move(rhs.m_value)) {}
        ConstantPropagationLattice& operator=(ConstantPropagationLattice&& rhs){
            m_value = std::move(rhs.m_value);

            return *this;
        }

        ConstantValue& value(){
            return *m_value;
        }

        ConstantValue value() const {
            return *m_value;
        }

        bool constant() const {
            return m_value;
        }

        bool nac() const {
            return !constant();
        }

        void set_nac(){
            m_value = boost::none;
        }

    private:
        boost::optional<ConstantValue> m_value;
};

typedef std::unordered_map<std::shared_ptr<Variable>, ConstantPropagationLattice> ConstantPropagationValues;

class ConstantPropagationProblem {
    public:
        //The type of data managed
        typedef Domain<ConstantPropagationValues> ProblemDomain;

        //The direction
        STATIC_CONSTANT(DataFlowType, Type, DataFlowType::Fast_Forward);
        STATIC_CONSTANT(bool, Low, false);

        ProblemDomain Init(mtac::Function& function);
        ProblemDomain Boundary(mtac::Function& function);

        void meet(ProblemDomain& in, const ProblemDomain& out);

        void transfer(mtac::basic_block_p basic_block, mtac::Quadruple& quadruple, ProblemDomain& in);
        bool optimize(mtac::Function& function, std::shared_ptr<DataFlowResults<ProblemDomain>> global_results);

    private:
        ProblemDomain top_element();
        ProblemDomain default_element();

        mtac::EscapedVariables pointer_escaped;
};

bool operator==(const mtac::Domain<ConstantPropagationValues>& lhs, const mtac::Domain<ConstantPropagationValues>& rhs);
bool operator!=(const mtac::Domain<ConstantPropagationValues>& lhs, const mtac::Domain<ConstantPropagationValues>& rhs);

template<>
struct pass_traits<ConstantPropagationProblem> {
    STATIC_CONSTANT(pass_type, type, pass_type::DATA_FLOW);
    STATIC_STRING(name, "constant_propagation");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);
};

std::ostream& operator<<(std::ostream& stream, const ConstantPropagationLattice& lattice);

} //end of mtac

} //end of eddic

#endif
<commit_msg>Fix explicit conversion<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2013.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef MTAC_CONSTANT_PROPAGATION_PROBLEM_H
#define MTAC_CONSTANT_PROPAGATION_PROBLEM_H

#include <unordered_map>
#include <memory>

#include "variant.hpp"
#include "assert.hpp"

#include "mtac/pass_traits.hpp"
#include "mtac/DataFlowProblem.hpp"
#include "mtac/EscapeAnalysis.hpp"

namespace eddic {

class Variable;

namespace mtac {

typedef boost::variant<std::string, double, int, std::shared_ptr<Variable>> ConstantValue;

class ConstantPropagationLattice {
    public:
        ConstantPropagationLattice(){}; //NAC
        ConstantPropagationLattice(ConstantValue value) : m_value(value) {}

        ConstantPropagationLattice(const ConstantPropagationLattice& rhs) : m_value(rhs.m_value) {}
        ConstantPropagationLattice& operator=(const ConstantPropagationLattice& rhs){
            m_value = rhs.m_value;

            return *this;
        }

        ConstantPropagationLattice(ConstantPropagationLattice&& rhs) : m_value(std::move(rhs.m_value)) {}
        ConstantPropagationLattice& operator=(ConstantPropagationLattice&& rhs){
            m_value = std::move(rhs.m_value);

            return *this;
        }

        ConstantValue& value(){
            return *m_value;
        }

        ConstantValue value() const {
            return *m_value;
        }

        bool constant() const {
            return static_cast<bool>(m_value);
        }

        bool nac() const {
            return !constant();
        }

        void set_nac(){
            m_value = boost::none;
        }

    private:
        boost::optional<ConstantValue> m_value;
};

typedef std::unordered_map<std::shared_ptr<Variable>, ConstantPropagationLattice> ConstantPropagationValues;

class ConstantPropagationProblem {
    public:
        //The type of data managed
        typedef Domain<ConstantPropagationValues> ProblemDomain;

        //The direction
        STATIC_CONSTANT(DataFlowType, Type, DataFlowType::Fast_Forward);
        STATIC_CONSTANT(bool, Low, false);

        ProblemDomain Init(mtac::Function& function);
        ProblemDomain Boundary(mtac::Function& function);

        void meet(ProblemDomain& in, const ProblemDomain& out);

        void transfer(mtac::basic_block_p basic_block, mtac::Quadruple& quadruple, ProblemDomain& in);
        bool optimize(mtac::Function& function, std::shared_ptr<DataFlowResults<ProblemDomain>> global_results);

    private:
        ProblemDomain top_element();
        ProblemDomain default_element();

        mtac::EscapedVariables pointer_escaped;
};

bool operator==(const mtac::Domain<ConstantPropagationValues>& lhs, const mtac::Domain<ConstantPropagationValues>& rhs);
bool operator!=(const mtac::Domain<ConstantPropagationValues>& lhs, const mtac::Domain<ConstantPropagationValues>& rhs);

template<>
struct pass_traits<ConstantPropagationProblem> {
    STATIC_CONSTANT(pass_type, type, pass_type::DATA_FLOW);
    STATIC_STRING(name, "constant_propagation");
    STATIC_CONSTANT(unsigned int, property_flags, 0);
    STATIC_CONSTANT(unsigned int, todo_after_flags, 0);
};

std::ostream& operator<<(std::ostream& stream, const ConstantPropagationLattice& lattice);

} //end of mtac

} //end of eddic

#endif
<|endoftext|>


<commit_before>#include <imgui.h>

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <map>
#include <set>
#include <stack>
#include <string>
#include <functional>
#include <random>
#include <mutex>
#include <atomic>
#include <cstddef>

namespace usagi
{
  namespace imgui
  {
    /// @brief ImGui の menu 系 API のステートフルラッパー
    /// @note Q: Is this a thread-safe? => Yes.
    struct statefull_menu_type
    {
      using functor_type = std::function< auto () -> void >;
      using value_type = std::pair< std::string, functor_type >;
      using self_type = statefull_menu_type;

      statefull_menu_type( const bool in_is_popup = true, const bool in_ignore_exceptions = false )
        : _root_node_label
          ( "##" + std::to_string( _generate_random_number() )
          )
        , _is_popup( in_is_popup )
        , _ignore_exceptions( in_ignore_exceptions )
      { }

      /// @brief open the context menu
      auto operator()()
        -> std::unique_ptr< std::string >
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );

        // このタイミングで削除処理を行わないと ImGui の描画タイミングの都合存在しないメモリー領域を参照する可能性がある
        _remove();
        _add();

        if ( _is_popup )
        {
          if ( ImGui::BeginPopup( _root_node_label.c_str() ) )
          {
            _recursive_menu_render( _m );
            ImGui::EndPopup();
          }
        }
        else
          _recursive_menu_render( _m );

        return { };
      }

      auto remove( const std::string& concatenated_path )
      {
        std::lock_guard< decltype( _mutex_removes ) > lock_guard( _mutex_removes );
        _removes.emplace( concatenated_path );
      }
      auto add( const std::string& concatenated_path, const std::function< auto () -> void >& f )
      {
        std::lock_guard< decltype( _mutex_adds ) > lock_guard( _mutex_adds );
        _adds.emplace( concatenated_path, f );
      }

      auto add( const value_type& head )
      {
        add( head.first, head.second );
      }

      template < typename ... T >
      auto add( const value_type& head, const T ... tails )
      {
        add( head );
        add( tails ... );
      }

      /// @todo 手抜き実装なので気が向いたら最適化する
      auto modify( const std::string& concatenated_path, const functor_type& f )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );

        remove( concatenated_path );
        add( concatenated_path, f );
      }

      /// @note default label will be "##xxxxxx", `xxxxxx` is a random number generated by mt19937_64 and random-device's seed.
      auto root_node_label()
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label;
      }
      auto root_node_label( const std::string& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label = in;
      }
      auto root_node_label( std::string&& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label = std::forward< std::string >( in );
      }

      auto path_separator()
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator;
      }
      auto path_separator( const std::string& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator = in;
      }
      auto path_separator( std::string&& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator = std::forward< std::string >( in );
      }

      auto is_popup() -> bool { return _is_popup; }
      auto is_popup( const bool in ) -> bool { return _is_popup = in; }

      auto ignore_exceptions() -> bool { return _ignore_exceptions; }
      auto ignore_exceptions( const bool in ) -> bool { return _ignore_exceptions = in; }

      auto show() { ImGui::OpenPopup( _root_node_label.c_str() ); }

      auto empty() { return _m.empty(); }

    private:

      auto _split( const std::string& in ) -> std::vector< std::string >
      {
        std::vector< std::string > r;
        boost::algorithm::split( r, in, boost::is_any_of( _path_separator ) );
        return r;
      }

      static auto _generate_random_number() -> std::mt19937_64::result_type
      {
        static std::random_device rnd;
        static std::mt19937_64 rne( rnd() );
        return rne();
      }

      using indices_type = std::vector< std::size_t >;
      struct recursive_mapper_type;
      using internal_mapper_type = std::map< std::string, recursive_mapper_type >;
      struct recursive_mapper_type
        : public internal_mapper_type
      {
        recursive_mapper_type() { }
        explicit recursive_mapper_type( const functor_type& f ) : _f( f ) { }
        explicit recursive_mapper_type( functor_type&& f ) : _f( std::forward< functor_type >( f ) ) { }
        auto operator()() const { _f(); }
        functor_type _f;
      };

      auto _remove()
        -> void
      {
        std::lock_guard< decltype( _mutex_removes ) > lock_guard( _mutex_removes );

        for ( const auto concatenated_path : _removes )
        {
          const auto path_parts = _split( concatenated_path );

          auto m = &_m;

          std::stack
          < std::pair
            < recursive_mapper_type*
            , typename recursive_mapper_type::iterator
            >
          > erase_candidates;

          for ( const auto p : path_parts )
          {
            const auto i = m->find( p );

            if ( i == cend( *m ) and not _ignore_exceptions )
              throw std::runtime_error( "usagi::imgui::statefull_menu_type::remove: cannot find the given path `" + concatenated_path + "`." );

            erase_candidates.emplace( std::make_pair( m, i ) );

            m = &i->second;
          }

          for ( auto* p = &erase_candidates.top(); not erase_candidates.empty(); erase_candidates.pop(), p = &erase_candidates.top() )
          {
            if ( not p->second->second.empty() )
              break;
            p->first->erase( p->second );
          }
        }

        _removes.clear();
      }

      /// @param path eg. "xxx/yyy/zzz" then xxx and yyy are intermediary node its like a directory, and zzz is marginal leaf node.
      /// @note you can change a path separator to use `path_separator( "your-separator" )`.
      auto _add()
        -> void
      {
        std::lock_guard< decltype( _mutex_adds ) > lock_guard( _mutex_adds );

        for ( const auto& in : _adds )
        {
          const auto& path_parts = _split( in.first );

          auto m = &_m;

          for ( const auto& p : path_parts )
          {
            const auto i = m->find( p );
            if ( i == cend( *m ) )
            {
              bool is_succeeded = false;
              typename recursive_mapper_type::iterator inserted;

              std::tie( inserted, is_succeeded ) = m->emplace( p, recursive_mapper_type( in.second ) );

              if ( not is_succeeded and not _ignore_exceptions )
                throw std::runtime_error( "usagi::imgui::statefull_menu_type::add_menu_path: failed. given path are: " + in.first );

              m = &inserted->second;
            }
            else
              m = &i->second;
          }
        }

        _adds.clear();
      }

      auto _recursive_menu_render( const recursive_mapper_type& m )
        -> void
      {
        if ( m.empty() )
          return;

        for ( const auto p : m )
        {
          if ( p.second.empty() )
          {
            if ( ImGui::MenuItem( p.first.c_str(), "", false ) )
              p.second();
          }
          else
          {
            if ( ImGui::BeginMenu( p.first.c_str() ) )
            {
              _recursive_menu_render( p.second );
              ImGui::EndMenu();
            }
          }
        }
      }

      /// @brief internal recursive mapper
      recursive_mapper_type _m;

      std::string _root_node_label;
      std::string _path_separator = "/";
      std::atomic< bool > _is_popup;
      std::atomic< bool > _ignore_exceptions;
      std::mutex _mutex;
      std::mutex _mutex_removes;
      std::mutex _mutex_adds;

      std::set< std::string > _removes;
      std::map< std::string, functor_type > _adds;
    };

  }
}
<commit_msg>add clear<commit_after>#include <imgui.h>

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <map>
#include <set>
#include <stack>
#include <string>
#include <functional>
#include <random>
#include <mutex>
#include <atomic>
#include <cstddef>

namespace usagi
{
  namespace imgui
  {
    /// @brief ImGui の menu 系 API のステートフルラッパー
    /// @note Q: Is this a thread-safe? => Yes.
    struct statefull_menu_type
    {
      using functor_type = std::function< auto () -> void >;
      using value_type = std::pair< std::string, functor_type >;
      using self_type = statefull_menu_type;

      statefull_menu_type( const bool in_is_popup = true, const bool in_ignore_exceptions = false )
        : _root_node_label
          ( "##" + std::to_string( _generate_random_number() )
          )
        , _is_popup( in_is_popup )
        , _ignore_exceptions( in_ignore_exceptions )
      { }

      /// @brief open the context menu
      auto operator()()
        -> std::unique_ptr< std::string >
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );

        // このタイミングで削除処理を行わないと ImGui の描画タイミングの都合存在しないメモリー領域を参照する可能性がある
        if ( _clear )
        {
          _m.clear();
          _clear = false;
        }
        else
        {
          _remove();
          _add();
        }

        if ( _is_popup )
        {
          if ( ImGui::BeginPopup( _root_node_label.c_str() ) )
          {
            _recursive_menu_render( _m );
            ImGui::EndPopup();
          }
        }
        else
          _recursive_menu_render( _m );

        return { };
      }

      auto clear()
      {
        {
          std::lock_guard< decltype( _mutex_removes ) > lock_guard( _mutex_removes );
          _removes.clear();
        }
        {
          std::lock_guard< decltype( _mutex_adds ) > lock_guard( _mutex_adds );
          _adds.clear();
        }
        _clear = true;
      }

      auto remove( const std::string& concatenated_path )
      {
        std::lock_guard< decltype( _mutex_removes ) > lock_guard( _mutex_removes );
        _removes.emplace( concatenated_path );
      }
      auto add( const std::string& concatenated_path, const std::function< auto () -> void >& f )
      {
        std::lock_guard< decltype( _mutex_adds ) > lock_guard( _mutex_adds );
        _adds.emplace( concatenated_path, f );
      }

      auto add( const value_type& head )
      {
        add( head.first, head.second );
      }

      template < typename ... T >
      auto add( const value_type& head, const T ... tails )
      {
        add( head );
        add( tails ... );
      }

      /// @todo 手抜き実装なので気が向いたら最適化する
      auto modify( const std::string& concatenated_path, const functor_type& f )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );

        remove( concatenated_path );
        add( concatenated_path, f );
      }

      /// @note default label will be "##xxxxxx", `xxxxxx` is a random number generated by mt19937_64 and random-device's seed.
      auto root_node_label()
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label;
      }
      auto root_node_label( const std::string& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label = in;
      }
      auto root_node_label( std::string&& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _root_node_label = std::forward< std::string >( in );
      }

      auto path_separator()
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator;
      }
      auto path_separator( const std::string& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator = in;
      }
      auto path_separator( std::string&& in )
      {
        std::lock_guard< decltype( _mutex ) > lock_guard( _mutex );
        return _path_separator = std::forward< std::string >( in );
      }

      auto is_popup() -> bool { return _is_popup; }
      auto is_popup( const bool in ) -> bool { return _is_popup = in; }

      auto ignore_exceptions() -> bool { return _ignore_exceptions; }
      auto ignore_exceptions( const bool in ) -> bool { return _ignore_exceptions = in; }

      auto show() { ImGui::OpenPopup( _root_node_label.c_str() ); }

      auto empty() { return _m.empty(); }

    private:

      auto _split( const std::string& in ) -> std::vector< std::string >
      {
        std::vector< std::string > r;
        boost::algorithm::split( r, in, boost::is_any_of( _path_separator ) );
        return r;
      }

      static auto _generate_random_number() -> std::mt19937_64::result_type
      {
        static std::random_device rnd;
        static std::mt19937_64 rne( rnd() );
        return rne();
      }

      using indices_type = std::vector< std::size_t >;
      struct recursive_mapper_type;
      using internal_mapper_type = std::map< std::string, recursive_mapper_type >;
      struct recursive_mapper_type
        : public internal_mapper_type
      {
        recursive_mapper_type() { }
        explicit recursive_mapper_type( const functor_type& f ) : _f( f ) { }
        explicit recursive_mapper_type( functor_type&& f ) : _f( std::forward< functor_type >( f ) ) { }
        auto operator()() const { _f(); }
        functor_type _f;
      };

      auto _remove()
        -> void
      {
        std::lock_guard< decltype( _mutex_removes ) > lock_guard( _mutex_removes );

        for ( const auto concatenated_path : _removes )
        {
          const auto path_parts = _split( concatenated_path );

          auto m = &_m;

          std::stack
          < std::pair
            < recursive_mapper_type*
            , typename recursive_mapper_type::iterator
            >
          > erase_candidates;

          for ( const auto p : path_parts )
          {
            const auto i = m->find( p );

            if ( i == cend( *m ) and not _ignore_exceptions )
              throw std::runtime_error( "usagi::imgui::statefull_menu_type::remove: cannot find the given path `" + concatenated_path + "`." );

            erase_candidates.emplace( std::make_pair( m, i ) );

            m = &i->second;
          }

          for ( auto* p = &erase_candidates.top(); not erase_candidates.empty(); erase_candidates.pop(), p = &erase_candidates.top() )
          {
            if ( not p->second->second.empty() )
              break;
            p->first->erase( p->second );
          }
        }

        _removes.clear();
      }

      /// @param path eg. "xxx/yyy/zzz" then xxx and yyy are intermediary node its like a directory, and zzz is marginal leaf node.
      /// @note you can change a path separator to use `path_separator( "your-separator" )`.
      auto _add()
        -> void
      {
        std::lock_guard< decltype( _mutex_adds ) > lock_guard( _mutex_adds );

        for ( const auto& in : _adds )
        {
          const auto& path_parts = _split( in.first );

          auto m = &_m;

          for ( const auto& p : path_parts )
          {
            const auto i = m->find( p );
            if ( i == cend( *m ) )
            {
              bool is_succeeded = false;
              typename recursive_mapper_type::iterator inserted;

              std::tie( inserted, is_succeeded ) = m->emplace( p, recursive_mapper_type( in.second ) );

              if ( not is_succeeded and not _ignore_exceptions )
                throw std::runtime_error( "usagi::imgui::statefull_menu_type::add_menu_path: failed. given path are: " + in.first );

              m = &inserted->second;
            }
            else
              m = &i->second;
          }
        }

        _adds.clear();
      }

      auto _recursive_menu_render( const recursive_mapper_type& m )
        -> void
      {
        if ( m.empty() )
          return;

        for ( const auto p : m )
        {
          if ( p.second.empty() )
          {
            if ( ImGui::MenuItem( p.first.c_str(), "", false ) )
              p.second();
          }
          else
          {
            if ( ImGui::BeginMenu( p.first.c_str() ) )
            {
              _recursive_menu_render( p.second );
              ImGui::EndMenu();
            }
          }
        }
      }

      /// @brief internal recursive mapper
      recursive_mapper_type _m;

      std::string _root_node_label;
      std::string _path_separator = "/";
      std::atomic< bool > _is_popup;
      std::atomic< bool > _ignore_exceptions;
      std::atomic< bool > _clear;
      std::mutex _mutex;
      std::mutex _mutex_removes;
      std::mutex _mutex_adds;

      std::set< std::string > _removes;
      std::map< std::string, functor_type > _adds;
    };

  }
}
<|endoftext|>


<commit_before>/*
 * File:   main.cpp
 * Author: vlad
 *
 * Created on December 12, 2013, 10:38 PM
 */

#include "qpp.h"

//#include "matlab.h" // support for MATLAB

// TODO: use .data() raw pointer instead of looping
// TODO: optimize syspermute: ?Eigen::Map?
// TODO: IMPORTANT Rewrite partial trace without syspermute
// TODO: further parallelization
// TODO: testing

using namespace std;
using namespace qpp;
using namespace qpp::types;
using namespace qpp::ct;

int main()
{
	cout << "Starting qpp..." << endl;

	// output format
	//cout << std::scientific;
	cout << std::fixed; // use fixed format for nice formatting
	cout << std::setprecision(4); // only for fixed or scientific modes

	// TESTING

	// quantum teleportation
	cout << endl << "Qudit teleportation." << endl;
	ket psi = randket(2); // a random state;
	cout << "|psi><psi|:" << endl;
	displn(proj(psi));
	cmat telecircuit = expandout(gt.H, { 0 }, { 2, 2, 2 })
			* gt.CTRL(gt.X, { 0 }, { 1 }, 3);
	ket psiin = kron(psi, gt.b00); // input state
	ket psiout = telecircuit * psiin; // output state before measurement
	// measure Alice's qubits, results 1 1
	psiout = kronlist<cmat>( { proj(gt.z1), proj(gt.z1), gt.Id2 }) * psiout;
	psiout = psiout / norm(psiout); // normalize
	// apply correction
	psiout = expandout(powm(gt.Z, 1) * powm(gt.X, 1), { 2 }, { 2, 2, 2 })
			* psiout;
	cmat rhoout = ptrace(proj(psiout), { 0, 1 }, { 2, 2, 2 });
	cout << endl << "Teleported state:" << endl;
	displn(rhoout);
	cout << "Difference in norm: " << norm(proj(psi) - rhoout) << endl;

	// qudit measurements
	cout << endl << "Qudit measurements." << endl;
	cout << "Initially in state |0><0|." << endl;
	ket zd0(3);
	zd0 << 1, 0, 0;
	Qudit q(proj(zd0));
	cout << "Measuring Z operator non-destructively. Results:" << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << "Measuring X operator non-destructively. Results:" << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	// von Neumann projective measurement
	cout << "Measuring X operator destructively (collapse). Results:" << endl;
	cout << q.measure(gt.Xd(3), true) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << "Finally measuring Z operator destructively. Results:" << endl;
	cout << q.measure(true) << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << "Final state of qudit:" << endl;
	displn(q.getRho());

	// Bell state generator
	cout << endl << "Bell state generator: " << endl;
	cmat circuit;
	circuit = gt.CTRL(gt.X, { 0 }, { 1 }, 2) * expandout(gt.H, 0, { 2, 2 });
	cmat z0(2, 1);
	z0 << 1, 0;
	cmat z1(2, 1);
	z1 << 0, 1;
	cmat input = kron(z0, z0);
	cmat output = circuit * input;
	cout << "Circuit matrix representation: " << endl;
	displn(circuit);
	cout << endl << "Output (|Bell_0> state) of the circuit on |00>: " << endl;
	displn(output);

	// 3-qubit repetion code
	cout << endl << "3-qubit repetition code: " << endl;
	cmat rep;
	rep = gt.CTRL(gt.X, { 0 }, { 2 }, 3) * gt.CTRL(gt.X, { 0 }, { 1 }, 3);
	input = kronlist<cmat>( { z1, z0, z0 });
	output = rep * input;
	cout << "Circuit acting on |000> produces |111>. Check: " << endl;
	displn(output);

	// Gram-Schmidt
	cout << endl << "Gram-Schmidt on matrix:" << endl;
	cmat A(3, 3);
	A << 1, 1, 0, 0, 2, 0, 0, 0, 0;
	displn(A);
	cmat Ags = grams(A);
	cout << endl << "Result:" << endl;
	displn(Ags);
	cout << endl << "Projector is:" << endl;
	displn(Ags * adjoint(Ags));

	// spectral decomposition test
	cout << endl << "Spectral decomposition tests." << endl;
	size_t D = 4;
	cmat rH = randH(D);
	cmat evalsH = hevals(rH);
	cmat evectsH = hevects(rH);
	cmat spec = cmat::Zero(D, D);
	for (size_t i = 0; i < D; i++)
		spec += evalsH(i) * proj(evectsH.col(i));
	cout << "Original matrix: " << endl;
	displn(rH);
	cout << endl << "Reconstructed from spectral decomposition: " << endl;
	displn(spec);
	cout << "Difference in norm: " << norm(spec - rH) << endl;

	// channel tests
	cout << endl << "Channel tests." << endl;
	size_t nk = 10, d = 2; // nk Kraus on d-dimensional system
	cout << "Generating a random channel with " << nk
			<< " Kraus operators on a " << d << " dimensional space..." << endl;
	std::vector<cmat> Ks = randkraus(nk, d);

	cmat rho_in = randrho(d); // input state
	cmat rho_out = channel(rho_in, Ks); // output state

	cout << "Computing its Choi matrix..." << endl;
	cmat choim = choi(Ks);
	cout << "Choi matrix:" << endl;
	displn(choim);
	cout << endl << "The eigenvalues of the Choi matrix are: " << endl;
	displn(transpose(hevals(choim)));
	cout << endl << "Their sum is: " << sum(hevals(choim)).real() << endl;
	std::vector<cmat> Kperps = choi2kraus(choim);
	cout << endl << "The Kraus rank of the channel is: " << Kperps.size()
			<< endl;
	cmat rho_out1 = channel(rho_in, Kperps);
	cout << endl << "Difference in norm on output states: "
			<< norm(rho_out1 - rho_out) << endl;
	cout << endl << "Superoperator matrix:" << endl;
	cmat smat = super(Ks);
	displn(smat);
	cout << endl << "The eigenvalues of the superoperator matrix are: " << endl;
	cmat evalsupop = evals(smat);
	displn(transpose(evalsupop));
	cout << endl << "Their absolute values are: " << endl;
	for (size_t i = 0; i < (size_t) evalsupop.size(); i++)
		cout << std::abs((cplx) evalsupop(i)) << " ";
	cout << endl << endl << "Diference in norm for superoperator action: ";
	cmat rho_out2 = transpose(
			reshape(smat * reshape(transpose(rho_in), d * d, 1), d, d));
	cout << norm(rho_out - rho_out2) << endl;

	// statistics tests
	cout << endl << "Statistics tests." << endl;
	std::vector<cplx> ampl = { 1. + ii, 1. - ii };
	cmat va(1, 4);
	va << 0.1, 1, 1. + ii, 1. + 2. * ii;
	DiscreteDistributionAbsSquare dc(va);
	cout << "The probabilities are: ";
	displn(dc.probabilities(), ", ", "{", "}");

	// other tests
	cout << endl << "Timing tests..." << endl;
	size_t n = 12; // number of qubits
	size_t N = std::pow(2, n);
	vector<size_t> dims; // local dimensions
	for (size_t i = 0; i < n; i++)
		dims.push_back(2);
	cout << "n = " << n << " qubits, matrix size " << N << " x " << N << "."
			<< endl;

	// TIMING
	Timer t, total; // start the timer, automatic tic() in the constructor

	// matrix initialization
	cout << endl << "Matrix initialization timing." << endl;
	cmat randcmat = cmat::Random(N, N);
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// lazy matrix product
	cout << endl << "Lazy matrix product timing." << endl;
	t.tic();
	auto lazyprod = randcmat * randcmat; // lazyprod has type GenMatProduct
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// matrix product
	cout << endl << "Matrix product timing." << endl;
	t.tic(); // reset the chronometer
	cmat prodmat = randcmat * randcmat; // explicit cmat now
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// ptrace2 timing
	cout << endl << "ptrace2 timing." << endl;
	t.tic(); // reset the chronometer
	// trace away half of the qubits
	ptrace2(randcmat, { (size_t) std::sqrt(N), (size_t) std::sqrt(N) });
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// ptrace SLOW SLOW SLOW (because of syspermute, do it without)
	cout << endl << "ptrace timing." << endl;
	vector<size_t> subsys_ptrace = { 0 }; // trace away the first qubit
	cout << "Subsytem(s): ";
	displn(subsys_ptrace, ", ");
	t.tic();
	ptrace(randcmat, subsys_ptrace, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// ptranspose
	cout << endl << "ptranspose timing." << endl;
	vector<size_t> subsys_ptranspose; // partially transpose all subsystems
	for (size_t i = 0; i < n; i++)
		subsys_ptranspose.push_back(i);
	cout << "Subsytem(s): ";
	displn(subsys_ptranspose, ", ");
	t.tic();
	ptranspose(randcmat, subsys_ptranspose, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// syspermute SLOW SLOW SLOW
	cout << endl << "syspermute timing." << endl;
	vector<size_t> perm; // left-shift all subsystems by 1
	for (size_t i = 0; i < n; i++)
		perm.push_back((i + 1) % n);
	cout << "Subsytem(s): ";
	displn(perm, ", ");
	t.tic();
	syspermute(randcmat, perm, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// END TIMING
	total.toc(); // read the total running time
	cout << endl << "Total time: " << total.seconds() << " seconds.";

	cout << endl << "Exiting qpp..." << endl;
}
<commit_msg>commit<commit_after>/*
 * File:   main.cpp
 * Author: vlad
 *
 * Created on December 12, 2013, 10:38 PM
 */

#include "qpp.h"

//#include "matlab.h" // support for MATLAB

// TODO: use .data() raw pointer instead of looping
// TODO: optimize syspermute: ?Eigen::Map?
// TODO: IMPORTANT Rewrite partial trace without syspermute
// TODO: further parallelization
// TODO: testing

using namespace std;
using namespace qpp;
using namespace qpp::types;
using namespace qpp::ct;

int main()
{
	cout << "Starting qpp..." << endl;

	// output format
	//cout << std::scientific;
	cout << std::fixed; // use fixed format for nice formatting
	cout << std::setprecision(4); // only for fixed or scientific modes

	// TESTING

	// quantum teleportation
	cout << endl << "Qudit teleportation." << endl;
	ket psi = randket(2); // a random state;
	cout << "|psi><psi|:" << endl;
	displn(proj(psi));
	cmat telecircuit = expandout(gt.H, { 0 }, { 2, 2, 2 })
			* gt.CTRL(gt.X, { 0 }, { 1 }, 3);
	ket psiin = kron(psi, gt.b00); // input state
	ket psiout = telecircuit * psiin; // output state before measurement
	// measure Alice's qubits, measurement results are 1 0
	psiout = kronlist<cmat>( { proj(gt.z1), proj(gt.z0), gt.Id2 }) * psiout;
	psiout = psiout / norm(psiout); // normalize
	// apply correction
	psiout = expandout(powm(gt.Z, 1) * powm(gt.X, 0), { 2 }, { 2, 2, 2 })
			* psiout;
	cmat rhoout = ptrace(proj(psiout), { 0, 1 }, { 2, 2, 2 });
	cout << endl << "Teleported state:" << endl;
	displn(rhoout);
	cout << "Difference in norm: " << norm(proj(psi) - rhoout) << endl;

	// qudit measurements
	cout << endl << "Qudit measurements." << endl;
	cout << "Initially in state |0><0|." << endl;
	ket zd0(3);
	zd0 << 1, 0, 0;
	Qudit q(proj(zd0));
	cout << "Measuring Z operator non-destructively. Results:" << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << "Measuring X operator non-destructively. Results:" << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	// von Neumann projective measurement
	cout << "Measuring X operator destructively (collapse). Results:" << endl;
	cout << q.measure(gt.Xd(3), true) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << q.measure(gt.Xd(3)) << endl;
	cout << "Finally measuring Z operator destructively. Results:" << endl;
	cout << q.measure(true) << endl;
	cout << q.measure() << endl;
	cout << q.measure() << endl;
	cout << "Final state of qudit:" << endl;
	displn(q.getRho());

	// Bell state generator
	cout << endl << "Bell state generator: " << endl;
	cmat circuit;
	circuit = gt.CTRL(gt.X, { 0 }, { 1 }, 2) * expandout(gt.H, 0, { 2, 2 });
	cmat z0(2, 1);
	z0 << 1, 0;
	cmat z1(2, 1);
	z1 << 0, 1;
	cmat input = kron(z0, z0);
	cmat output = circuit * input;
	cout << "Circuit matrix representation: " << endl;
	displn(circuit);
	cout << endl << "Output (|Bell_0> state) of the circuit on |00>: " << endl;
	displn(output);

	// 3-qubit repetion code
	cout << endl << "3-qubit repetition code: " << endl;
	cmat rep;
	rep = gt.CTRL(gt.X, { 0 }, { 2 }, 3) * gt.CTRL(gt.X, { 0 }, { 1 }, 3);
	input = kronlist<cmat>( { z1, z0, z0 });
	output = rep * input;
	cout << "Circuit acting on |000> produces |111>. Check: " << endl;
	displn(output);

	// Gram-Schmidt
	cout << endl << "Gram-Schmidt on matrix:" << endl;
	cmat A(3, 3);
	A << 1, 1, 0, 0, 2, 0, 0, 0, 0;
	displn(A);
	cmat Ags = grams(A);
	cout << endl << "Result:" << endl;
	displn(Ags);
	cout << endl << "Projector is:" << endl;
	displn(Ags * adjoint(Ags));

	// spectral decomposition test
	cout << endl << "Spectral decomposition tests." << endl;
	size_t D = 4;
	cmat rH = randH(D);
	cmat evalsH = hevals(rH);
	cmat evectsH = hevects(rH);
	cmat spec = cmat::Zero(D, D);
	for (size_t i = 0; i < D; i++)
		spec += evalsH(i) * proj(evectsH.col(i));
	cout << "Original matrix: " << endl;
	displn(rH);
	cout << endl << "Reconstructed from spectral decomposition: " << endl;
	displn(spec);
	cout << "Difference in norm: " << norm(spec - rH) << endl;

	// channel tests
	cout << endl << "Channel tests." << endl;
	size_t nk = 10, d = 2; // nk Kraus on d-dimensional system
	cout << "Generating a random channel with " << nk
			<< " Kraus operators on a " << d << " dimensional space..." << endl;
	std::vector<cmat> Ks = randkraus(nk, d);

	cmat rho_in = randrho(d); // input state
	cmat rho_out = channel(rho_in, Ks); // output state

	cout << "Computing its Choi matrix..." << endl;
	cmat choim = choi(Ks);
	cout << "Choi matrix:" << endl;
	displn(choim);
	cout << endl << "The eigenvalues of the Choi matrix are: " << endl;
	displn(transpose(hevals(choim)));
	cout << endl << "Their sum is: " << sum(hevals(choim)).real() << endl;
	std::vector<cmat> Kperps = choi2kraus(choim);
	cout << endl << "The Kraus rank of the channel is: " << Kperps.size()
			<< endl;
	cmat rho_out1 = channel(rho_in, Kperps);
	cout << endl << "Difference in norm on output states: "
			<< norm(rho_out1 - rho_out) << endl;
	cout << endl << "Superoperator matrix:" << endl;
	cmat smat = super(Ks);
	displn(smat);
	cout << endl << "The eigenvalues of the superoperator matrix are: " << endl;
	cmat evalsupop = evals(smat);
	displn(transpose(evalsupop));
	cout << endl << "Their absolute values are: " << endl;
	for (size_t i = 0; i < (size_t) evalsupop.size(); i++)
		cout << std::abs((cplx) evalsupop(i)) << " ";
	cout << endl << endl << "Diference in norm for superoperator action: ";
	cmat rho_out2 = transpose(
			reshape(smat * reshape(transpose(rho_in), d * d, 1), d, d));
	cout << norm(rho_out - rho_out2) << endl;

	// statistics tests
	cout << endl << "Statistics tests." << endl;
	std::vector<cplx> ampl = { 1. + ii, 1. - ii };
	cmat va(1, 4);
	va << 0.1, 1, 1. + ii, 1. + 2. * ii;
	DiscreteDistributionAbsSquare dc(va);
	cout << "The probabilities are: ";
	displn(dc.probabilities(), ", ", "{", "}");

	// other tests
	cout << endl << "Timing tests..." << endl;
	size_t n = 12; // number of qubits
	size_t N = std::pow(2, n);
	vector<size_t> dims; // local dimensions
	for (size_t i = 0; i < n; i++)
		dims.push_back(2);
	cout << "n = " << n << " qubits, matrix size " << N << " x " << N << "."
			<< endl;

	// TIMING
	Timer t, total; // start the timer, automatic tic() in the constructor

	// matrix initialization
	cout << endl << "Matrix initialization timing." << endl;
	cmat randcmat = cmat::Random(N, N);
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// lazy matrix product
	cout << endl << "Lazy matrix product timing." << endl;
	t.tic();
	auto lazyprod = randcmat * randcmat; // lazyprod has type GenMatProduct
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// matrix product
	cout << endl << "Matrix product timing." << endl;
	t.tic(); // reset the chronometer
	cmat prodmat = randcmat * randcmat; // explicit cmat now
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// ptrace2 timing
	cout << endl << "ptrace2 timing." << endl;
	t.tic(); // reset the chronometer
	// trace away half of the qubits
	ptrace2(randcmat, { (size_t) std::sqrt(N), (size_t) std::sqrt(N) });
	t.toc(); // read the time
	cout << "Took " << t << " seconds." << endl;

	// ptrace SLOW SLOW SLOW (because of syspermute, do it without)
	cout << endl << "ptrace timing." << endl;
	vector<size_t> subsys_ptrace = { 0 }; // trace away the first qubit
	cout << "Subsytem(s): ";
	displn(subsys_ptrace, ", ");
	t.tic();
	ptrace(randcmat, subsys_ptrace, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// ptranspose
	cout << endl << "ptranspose timing." << endl;
	vector<size_t> subsys_ptranspose; // partially transpose all subsystems
	for (size_t i = 0; i < n; i++)
		subsys_ptranspose.push_back(i);
	cout << "Subsytem(s): ";
	displn(subsys_ptranspose, ", ");
	t.tic();
	ptranspose(randcmat, subsys_ptranspose, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// syspermute SLOW SLOW SLOW
	cout << endl << "syspermute timing." << endl;
	vector<size_t> perm; // left-shift all subsystems by 1
	for (size_t i = 0; i < n; i++)
		perm.push_back((i + 1) % n);
	cout << "Subsytem(s): ";
	displn(perm, ", ");
	t.tic();
	syspermute(randcmat, perm, dims);
	t.toc();
	cout << "Took " << t << " seconds." << endl;

	// END TIMING
	total.toc(); // read the total running time
	cout << endl << "Total time: " << total.seconds() << " seconds.";

	cout << endl << "Exiting qpp..." << endl;
}
<|endoftext|>


<commit_before>#include "Arduino.h"
#include "usb_keyboard.h"

#define NUMCOLS 11
#define NUMROWS 4
#define NUMKEYS (NUMCOLS * NUMROWS)

static void scan_keyboard();
static void decode();

// the setup function runs once when you press reset or power the board
void setup() {
    // columns are on pins 0 .. 10, active low
    pinMode(0, INPUT_PULLUP);
    pinMode(1, INPUT_PULLUP);
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    pinMode(4, INPUT_PULLUP);
    pinMode(5, INPUT_PULLUP);
    pinMode(6, INPUT_PULLUP);
    pinMode(7, INPUT_PULLUP);
    pinMode(8, INPUT_PULLUP);
    pinMode(9, INPUT_PULLUP);
    pinMode(10,INPUT_PULLUP);

    // rows are on pins 14 .. 17, high to start with
    pinMode(14, OUTPUT);
    pinMode(15, OUTPUT);
    pinMode(16, OUTPUT);
    pinMode(17, OUTPUT);

    digitalWrite(14, HIGH);
    digitalWrite(15, HIGH);
    digitalWrite(16, HIGH);
    digitalWrite(17, HIGH);

#if 0
    // debugging aid: LED
    pinMode(13,OUTPUT);
    digitalWrite(13, 0);
#endif
}

// all the keys currently pressed (list of raw keycodes)
static int raw_count = 0;
static int raw_keys[NUMKEYS];

// Scan all keys for pressed keys
// Writes to raw_keys
static void scan_keyboard() {
    raw_count = 0;
    // Rows are on pins 14 .. 17 inclusive
    for(int row = 0; row < NUMROWS; ++row) {
        digitalWrite(14+row, LOW);
        delayMicroseconds(50);
        // Columns are on pins 0 .. 11 inclusive
        for(int col = 0; col < NUMCOLS; ++col) {
            if (!digitalRead(col)) {
                raw_keys[raw_count++] = row * NUMCOLS + col;
            }
        }
        digitalWrite(14+row, HIGH);
    }
}

// This macro relates the physical layout of the keys to their position
// in the key matrix
#define LAYER( \
    K00, K01, K02, K03, K04,           K05, K06, K07, K08, K09, \
    K10, K11, K12, K13, K14,           K15, K16, K17, K18, K19, \
    K20, K21, K22, K23, K24,           K25, K26, K27, K28, K29, \
    K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B  \
) { \
    K3B, K3A, K39, K38, K37, K36, K34, K33, K32, K31, K30, \
    K29, K28, K27, K26, K25, K35, K24, K23, K22, K21, K20, \
    K19, K18, K17, K16, K15, 0,   K14, K13, K12, K11, K10, \
    K09, K08, K07, K06, K05, 0,   K04, K03, K02, K01, K00  \
}

// Modifier numbers - in same order as MODIFIERKEY_* in Teensy library
#define LEFT_CTRL   0
#define LEFT_SHIFT  1
#define LEFT_ALT    2
#define LEFT_GUI    3
#define RIGHT_CTRL  4
#define RIGHT_SHIFT 5
#define RIGHT_ALT   6
#define RIGHT_GUI   7

// In the teensy firmware, keys are represented by a 16-bit number
// We extend this scheme by using some of the unused encodings
// - bit 15 - set if it is a modifier
//            bits 0-7  = 1 << M (M is modifier number)
// - bit 14 - set if it is a normal key
//            bits 0-7  = which key
// - bit 11 - set if it has a modifier
//            bits 0-7  = which key is held
//            bits 8-10 = which modifier is held
//            [This is not part of the Teensy firmware]
#define IS_MODIFIER(k) ((k) & 0x8000)
#define IS_NORMAL(k)   ((k) & 0x4000)
#define IS_MODKEY(k)   ((k) & 0x0800)

#define SHIFT(k) (0x0800 | (k) | (LEFT_SHIFT << 8))

#define KEY_BACKQUOTE   SHIFT(KEY_TILDE)
#define KEY_BANG        SHIFT(KEY_1)
#define KEY_SPLAT       SHIFT(KEY_2)
#define KEY_HASH        SHIFT(KEY_3)
#define KEY_DOLLAR      SHIFT(KEY_4)
#define KEY_PERCENT     SHIFT(KEY_5)
#define KEY_CARET       SHIFT(KEY_6)
#define KEY_AMPERSAND   SHIFT(KEY_7)
#define KEY_STAR        SHIFT(KEY_8)
#define KEY_LEFT_PAREN  SHIFT(KEY_9)
#define KEY_RIGHT_PAREN SHIFT(KEY_0)
#define KEY_PLUS        SHIFT(KEY_EQUAL)
#define KEY_UNDERSCORE  SHIFT(KEY_MINUS)
#define KEY_QUERY       SHIFT(KEY_SLASH)
#define KEY_PIPE        SHIFT(KEY_BACKSLASH)
#define KEY_LEFT_CURL   SHIFT(KEY_LEFT_BRACE)
#define KEY_RIGHT_CURL  SHIFT(KEY_RIGHT_BRACE)

#define LSHIFT MODIFIERKEY_LEFT_SHIFT
#define RSHIFT MODIFIERKEY_RIGHT_SHIFT
#define LCTRL MODIFIERKEY_LEFT_CTRL
#define RCTRL MODIFIERKEY_RIGHT_CTRL

static const KEYCODE_TYPE layers[][NUMKEYS] = {
    // Hardware Dvorak
    LAYER(
    KEY_QUOTE,     KEY_COMMA, KEY_PERIOD, KEY_P,         KEY_Y,                     KEY_F,     KEY_G,    KEY_C,    KEY_R,  KEY_L,
    KEY_A,         KEY_O,     KEY_E,      KEY_U,         KEY_I,                     KEY_D,     KEY_H,    KEY_T,    KEY_N,  KEY_S,
    KEY_SEMICOLON, KEY_Q,     KEY_J,      KEY_K,         KEY_X,                     KEY_B,     KEY_M,    KEY_W,    KEY_V,  KEY_Z,
    KEY_ESC,       KEY_TAB,   LCTRL,      KEY_BACKSPACE, KEY_ENTER, LSHIFT, RSHIFT, KEY_SPACE, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT
    ),
    // Qwerty / Software Dvorak
    LAYER(
    KEY_Q,         KEY_W,     KEY_E,      KEY_R,         KEY_T,                     KEY_Y,     KEY_U,    KEY_I,    KEY_O,  KEY_P,
    KEY_A,         KEY_S,     KEY_D,      KEY_F,         KEY_G,                     KEY_H,     KEY_J,    KEY_K,    KEY_L,  KEY_SEMICOLON,
    KEY_Z,         KEY_X,     KEY_C,      KEY_V,         KEY_B,                     KEY_N,     KEY_M,    KEY_COMMA,KEY_PERIOD,  KEY_SLASH,
    KEY_ESC,       KEY_TAB,   LCTRL,      KEY_BACKSPACE, KEY_ENTER, LSHIFT, RSHIFT, KEY_SPACE, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT
    )
};

static int current_layer = 1;

// decode and send keys to USB
static void decode() {
    int count = 0;
    keyboard_modifier_keys = 0;
    for(int i = 0; i < 6; ++i) {
        keyboard_keys[i] = 0;
    }
    for(int i = 0; i < raw_count; ++i) {
        int raw = raw_keys[i];
        KEYCODE_TYPE keycode = layers[current_layer][raw];
        if (IS_MODIFIER(keycode)) { // modifier key
            keyboard_modifier_keys |= (keycode & 0xff);
        } else if (IS_NORMAL(keycode)) { // normal key
            if (count < 6) {
                keyboard_keys[count++] = keycode & 0xff;
            }
        } else {
            // ignore anything else
        }
    }
}

// Record previous send - to avoid sending same message twice in a row
static uint8_t prev_modifiers;
static uint8_t prev_keys[6];

// the loop function runs over and over again forever
void loop() {
    scan_keyboard();
    decode();

    if (prev_modifiers != keyboard_modifier_keys
       || memcmp(prev_keys, keyboard_keys, 6)) {
        prev_modifiers = keyboard_modifier_keys;
        memcpy(prev_keys, keyboard_keys, 6);
        usb_keyboard_send();
    }

    delay(10); // sample at 100Hz
}
<commit_msg>Added debounce<commit_after>#include "Arduino.h"
#include "usb_keyboard.h"

#define NUMCOLS 11
#define NUMROWS 4
#define NUMKEYS (NUMCOLS * NUMROWS)

#define DEBOUNCE_TIMEOUT 1

static inline void raw_key_press(uint8_t key);
static boolean test_key(int rawkey);
static void scan_keyboard();
static void clear_keys();
static void press_key(uint8_t key);
static void release_key(uint8_t key);
static void send_keys();
static void decode();

// the setup function runs once when you press reset or power the board
void setup() {
    // columns are on pins 0 .. 10, active low
    pinMode(0, INPUT_PULLUP);
    pinMode(1, INPUT_PULLUP);
    pinMode(2, INPUT_PULLUP);
    pinMode(3, INPUT_PULLUP);
    pinMode(4, INPUT_PULLUP);
    pinMode(5, INPUT_PULLUP);
    pinMode(6, INPUT_PULLUP);
    pinMode(7, INPUT_PULLUP);
    pinMode(8, INPUT_PULLUP);
    pinMode(9, INPUT_PULLUP);
    pinMode(10,INPUT_PULLUP);

    // rows are on pins 14 .. 17, high to start with
    pinMode(14, OUTPUT);
    pinMode(15, OUTPUT);
    pinMode(16, OUTPUT);
    pinMode(17, OUTPUT);

    digitalWrite(14, HIGH);
    digitalWrite(15, HIGH);
    digitalWrite(16, HIGH);
    digitalWrite(17, HIGH);

#if 0
    // debugging aid: LED
    pinMode(13,OUTPUT);
    digitalWrite(13, 0);
#endif

    clear_keys();
}

// Keys are debounced by starting a timeout when a key is pressed.
// If the timeout is non-zero, we send a key press
// When the timeout counts down to zero, we send a key release
static uint8_t timeouts[NUMKEYS];

// list of keys that changed state in last scan (list of raw keycodes, bit 7 set if released)
static uint8_t raw_count = 0;
static uint16_t raw_keys[NUMKEYS];

static inline void raw_key_press(uint8_t key) {
    raw_keys[raw_count++] = key;
}

// Test if key is currently pressed
static boolean test_key(int rawkey) {
    for(int i = 0; i < raw_count; ++i) {
        if (raw_keys[i] == rawkey) {
            return true;
        }
    }
    return timeouts[rawkey] != 0;
}

// Scan all keys for pressed keys
// Writes to raw_keys
static void scan_keyboard() {
    raw_count = 0;
    // Rows are on pins 14 .. 17 inclusive
    for(int row = 0; row < NUMROWS; ++row) {
        digitalWrite(14+row, LOW);
        delayMicroseconds(50);
        // Columns are on pins 0 .. 11 inclusive
        for(int col = 0; col < NUMCOLS; ++col) {
            int key = row * NUMCOLS + col;
            int timeout = timeouts[key];
            if (!digitalRead(col)) { // pressed down
                if (timeout == 0) {
                    raw_key_press(key | 0x80); // newly pressed
                }
                timeouts[key] = DEBOUNCE_TIMEOUT;
            } else { // not pressed
                if (timeout > 0) { // previously pressed
                    --timeout;
                    timeouts[key] = timeout;
                    if (timeout == 0) {
                        raw_key_press(key); // newly released
                    }
                }
            }
        }
        digitalWrite(14+row, HIGH);
    }
}

// This macro relates the physical layout of the keys to their position
// in the key matrix
#define LAYER( \
    K00, K01, K02, K03, K04,           K05, K06, K07, K08, K09, \
    K10, K11, K12, K13, K14,           K15, K16, K17, K18, K19, \
    K20, K21, K22, K23, K24,           K25, K26, K27, K28, K29, \
    K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B  \
) { \
    K3B, K3A, K39, K38, K37, K36, K34, K33, K32, K31, K30, \
    K29, K28, K27, K26, K25, K35, K24, K23, K22, K21, K20, \
    K19, K18, K17, K16, K15, 0,   K14, K13, K12, K11, K10, \
    K09, K08, K07, K06, K05, 0,   K04, K03, K02, K01, K00  \
}

// Modifier numbers - in same order as MODIFIERKEY_* in Teensy library
#define LEFT_CTRL   0
#define LEFT_SHIFT  1
#define LEFT_ALT    2
#define LEFT_GUI    3
#define RIGHT_CTRL  4
#define RIGHT_SHIFT 5
#define RIGHT_ALT   6
#define RIGHT_GUI   7

// In the teensy firmware, keys are represented by a 16-bit number
// We extend this scheme by using some of the unused encodings
// - bit 15 - set if it is a modifier
//            bits 0-7  = 1 << M (M is modifier number)
// - bit 14 - set if it is a normal key
//            bits 0-7  = which key
// - bit 11 - set if it has a modifier
//            bits 0-7  = which key is held
//            bits 8-10 = which modifier is held
//            [This is not part of the Teensy firmware]
#define IS_MODIFIER(k) ((k) & 0x8000)
#define IS_NORMAL(k)   ((k) & 0x4000)
#define IS_MODKEY(k)   ((k) & 0x0800)

#define SHIFT(k) (0x0800 | (k) | (LEFT_SHIFT << 8))

#define KEY_BACKQUOTE   SHIFT(KEY_TILDE)
#define KEY_BANG        SHIFT(KEY_1)
#define KEY_SPLAT       SHIFT(KEY_2)
#define KEY_HASH        SHIFT(KEY_3)
#define KEY_DOLLAR      SHIFT(KEY_4)
#define KEY_PERCENT     SHIFT(KEY_5)
#define KEY_CARET       SHIFT(KEY_6)
#define KEY_AMPERSAND   SHIFT(KEY_7)
#define KEY_STAR        SHIFT(KEY_8)
#define KEY_LEFT_PAREN  SHIFT(KEY_9)
#define KEY_RIGHT_PAREN SHIFT(KEY_0)
#define KEY_PLUS        SHIFT(KEY_EQUAL)
#define KEY_UNDERSCORE  SHIFT(KEY_MINUS)
#define KEY_QUERY       SHIFT(KEY_SLASH)
#define KEY_PIPE        SHIFT(KEY_BACKSLASH)
#define KEY_LEFT_CURL   SHIFT(KEY_LEFT_BRACE)
#define KEY_RIGHT_CURL  SHIFT(KEY_RIGHT_BRACE)

#define LSHIFT MODIFIERKEY_LEFT_SHIFT
#define RSHIFT MODIFIERKEY_RIGHT_SHIFT
#define LCTRL MODIFIERKEY_LEFT_CTRL
#define RCTRL MODIFIERKEY_RIGHT_CTRL

static const KEYCODE_TYPE layers[][NUMKEYS] = {
    // Hardware Dvorak
    LAYER(
    KEY_QUOTE,     KEY_COMMA, KEY_PERIOD, KEY_P,         KEY_Y,                     KEY_F,     KEY_G,    KEY_C,    KEY_R,  KEY_L,
    KEY_A,         KEY_O,     KEY_E,      KEY_U,         KEY_I,                     KEY_D,     KEY_H,    KEY_T,    KEY_N,  KEY_S,
    KEY_SEMICOLON, KEY_Q,     KEY_J,      KEY_K,         KEY_X,                     KEY_B,     KEY_M,    KEY_W,    KEY_V,  KEY_Z,
    KEY_ESC,       KEY_TAB,   LCTRL,      KEY_BACKSPACE, KEY_ENTER, LSHIFT, RSHIFT, KEY_SPACE, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT
    ),
    // Qwerty / Software Dvorak
    LAYER(
    KEY_Q,         KEY_W,     KEY_E,      KEY_R,         KEY_T,                     KEY_Y,     KEY_U,    KEY_I,    KEY_O,  KEY_P,
    KEY_A,         KEY_S,     KEY_D,      KEY_F,         KEY_G,                     KEY_H,     KEY_J,    KEY_K,    KEY_L,  KEY_SEMICOLON,
    KEY_Z,         KEY_X,     KEY_C,      KEY_V,         KEY_B,                     KEY_N,     KEY_M,    KEY_COMMA,KEY_PERIOD,  KEY_SLASH,
    KEY_ESC,       KEY_TAB,   LCTRL,      KEY_BACKSPACE, KEY_ENTER, LSHIFT, RSHIFT, KEY_SPACE, KEY_LEFT, KEY_DOWN, KEY_UP, KEY_RIGHT
    )
};

static void clear_keys() {
    keyboard_modifier_keys = 0;
    for(int i = 0; i < 6; ++i) {
        keyboard_keys[i] = 0;
    }
}

static void press_key(uint8_t key) {
    for(int i = 0; i < 6; ++i) {
        if (keyboard_keys[i] == 0) {
            keyboard_keys[i] = key;
            return;
        }
    }
}

static void release_key(uint8_t key) {
    for(int i = 0; i < 6; ++i) {
        if (keyboard_keys[i] == key) {
            keyboard_keys[i] = 0;
        }
    }
}

static void send_keys() {
    usb_keyboard_send();
}

static int current_layer = 1;

// decode and send keys to USB
static void decode() {
    for(int i = 0; i < raw_count; ++i) {
        int raw = raw_keys[i];
        boolean down = raw & 0x80;
        raw = raw & 0x7f;
        KEYCODE_TYPE keycode = layers[current_layer][raw];
        if (IS_MODIFIER(keycode)) { // modifier key
            if (down) {
                keyboard_modifier_keys |= (keycode & 0xff);
            } else {
                keyboard_modifier_keys &= ~(keycode & 0xff);
            }
        } else if (IS_NORMAL(keycode)) { // normal key
            if (down) {
                press_key(keycode & 0xff);
            } else {
                release_key(keycode & 0xff);
            }
        } else {
            // ignore anything else
        }
    }
}

// Record previous send - to avoid sending same message twice in a row
static uint8_t prev_modifiers;
static uint8_t prev_keys[6];

// the loop function runs over and over again forever
void loop() {
    scan_keyboard();
    decode();

#if 0
    if (prev_modifiers != keyboard_modifier_keys
       || memcmp(prev_keys, keyboard_keys, 6)) {
        prev_modifiers = keyboard_modifier_keys;
        memcpy(prev_keys, keyboard_keys, 6);
        usb_keyboard_send();
    }
#else
    send_keys();
#endif

    delay(10); // sample at 100Hz
}
<|endoftext|>


<commit_before>// Copyright 2008 Paul Hodge

#include "tests/common.h"
#include "common_headers.h"
#include "branch.h"
#include "builtins.h"
#include "operations.h"
#include "parser.h"
#include "type.h"

namespace circa {
namespace type_tests {

void bootstrapped_objects()
{
    /*
    //FIXME test_assert(get_parent_type(COMPOUND_TYPE) == TYPE_TYPE);
    //FIXME test_assert(get_parent(COMPOUND_TYPE)->type == TYPE_TYPE);

    test_assert(get_as(COMPOUND_TYPE, COMPOUND_TYPE) == COMPOUND_TYPE);

    test_assert(get_as(COMPOUND_TYPE, TYPE_TYPE) != NULL);
    test_assert(get_as(COMPOUND_TYPE, TYPE_TYPE)->type == TYPE_TYPE);

    test_assert(as_type(COMPOUND_TYPE) != NULL);

    //FIXME test_assert(get_field(COMPOUND_TYPE, "parent") == get_parent(COMPOUND_TYPE));
    test_assert(get_field(COMPOUND_TYPE, "fields") != NULL);

    //std::cout << "COMPOUND_TYPE = " << COMPOUND_TYPE->toString() << std::endl;

    Branch branch;
    Term* typeA = eval_statement(branch, "typeA = CompoundType()");

    eval_statement(branch, "compound-type-append-field(@typeA, int, 'I)");
    typeA = eval_statement(branch, "compound-type-append-field(@typeA, string, 'S)");

    //std::cout << "typeA = " << typeA->toString() << std::endl;

    Term* typeAinstance = eval_statement(branch, "typeAinstance = typeA()");

    //std::cout << "typeAinstance = " << typeAinstance->toString() << std::endl;
    */
}

void compound_types()
{
    Branch branch;

    Term* type1 = eval_statement(branch, "type1 = create-compound-type('type1)");
    test_assert(type1 != NULL);
    test_assert(get_field(type1, "parent")->type == TYPE_TYPE);
    test_assert(get_field(type1, "fields")->type == LIST_TYPE);
    test_assert(is_type(type1));

    Term* type2 = eval_statement(branch, "type2 = create-compound-type('type2)");
    test_assert(type2 != NULL);
    test_assert(get_field(type2, "parent")->type == TYPE_TYPE);
    test_assert(get_field(type2, "fields")->type == LIST_TYPE);
    test_assert(get_field(type1, "parent") != get_field(type2, "parent"));
    test_assert(get_field(type1, "fields") != get_field(type2, "fields"));

    test_assert(is_type(type1));
    //std::cout << type1->toString() << std::endl;
    type1 = eval_statement(branch, "compound-type-append-field(@type1, int, 'myint)");
    //std::cout << type1->toString() << std::endl;
    test_assert(is_type(type1));
    type1 = eval_statement(branch, "compound-type-append-field(@type1, string, 'mystring)");
    test_assert(is_type(type1));

    Term* inst1 = eval_statement(branch, "inst1 = type1()");
    test_assert(get_field(inst1, "myint") != NULL);
    test_assert(get_field(inst1, "myint")->type == INT_TYPE);
    test_assert(get_field(inst1, "mystring") != NULL);
    test_assert(get_field(inst1, "mystring")->type == STRING_TYPE);
}

} // namespace type_tests

void register_type_tests()
{
    //FIXME REGISTER_TEST_CASE(type_tests::bootstrapped_objects);
    //FIXME REGISTER_TEST_CASE(type_tests::compound_types);
}

} // namespace circa
<commit_msg>Added some (failing) tests for compound types<commit_after>// Copyright 2008 Paul Hodge

#include "tests/common.h"
#include "common_headers.h"
#include "branch.h"
#include "builtins.h"
#include "operations.h"
#include "parser.h"
#include "type.h"

namespace circa {
namespace type_tests {

void compound_types()
{
    Branch branch;

    Term* type1 = eval_statement(branch, "type1 = create-compound-type('type1)");
    test_assert(type1 != NULL);
    test_assert(is_type(type1));

    type1 = eval_statement(branch, "compound-type-append-field(@type1, int, 'myint)");
    test_assert(is_type(type1));
    test_assert(as_type(type1)->fields.size() == 1);
    test_assert(as_type(type1)->fields[0].name == "myint");
    test_assert(as_type(type1)->fields[0].type == INT_TYPE);

    type1 = eval_statement(branch, "compound-type-append-field(@type1, string, 'astr)");
    test_assert(is_type(type1));
    test_assert(as_type(type1)->fields.size() == 2);
    test_assert(as_type(type1)->fields[1].name == "astr");
    test_assert(as_type(type1)->fields[1].type == STRING_TYPE);

    Term* inst1 = eval_statement(branch, "inst1 = type1()");

    // test get-field function
    Term* inst1_myint = eval_statement(branch, "get-field(inst1, 'myint)");
    test_assert(inst1_myint != NULL);
    //test_assert(is_int(inst1_myint));

    Term* inst1_astr = eval_statement(branch, "get-field(inst1, 'astr)");
    test_assert(inst1_myint != NULL);
    //test_assert(is_string(inst1_myint));

    // test Term::field
    test_assert(inst1->field("myint") == inst1_myint);

    inst1->field("myint")->asInt() = 5;

    Term* inst2 = eval_statement(branch, "inst2 = type1()");

    test_assert(inst1->field("myint") != inst2->field("myint"));
    inst2->field("myint")->asInt() = 7;
    test_assert(inst1->field("myint")->asInt() == 5);
}

} // namespace type_tests

void register_type_tests()
{
    REGISTER_TEST_CASE(type_tests::compound_types);
}

} // namespace circa
<|endoftext|>