<commit_before>// Copyright 2020 Global Phasing Ltd.
//
// A function that generates biological assemblies by applying operations
// from struct Assembly to a Model.
// And chain (re)naming utilities.

#ifndef GEMMI_ASSEMBLY_HPP_
#define GEMMI_ASSEMBLY_HPP_

#include <ostream>      // std::ostream
#include "model.hpp"
#include "util.hpp"

namespace gemmi {

enum class HowToNameCopiedChains { Short, AddNumber, Dup };

struct ChainNameGenerator {
  using How = HowToNameCopiedChains;
  How how;
  std::vector<std::string> used_names;

  ChainNameGenerator(How how_) : how(how_) {}
  ChainNameGenerator(const Model& model, How how_) : how(how_) {
    if (how != How::Dup)
      for (const Chain& chain : model.chains)
        used_names.push_back(chain.name);
  }
  bool has(const std::string& name) const {
    return in_vector(name, used_names);
  }
  const std::string& added(const std::string& name) {
    used_names.push_back(name);
    return name;
  }

  std::string make_short_name(const std::string& preferred) {
    static const char symbols[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                  "abcdefghijklmnopqrstuvwxyz0123456789";
    if (!has(preferred))
      return added(preferred);
    std::string name(1, 'A');
    for (char symbol : symbols) {
      name[0] = symbol;
      if (!has(name))
        return added(name);
    }
    name += 'A';
    for (char symbol1 : symbols) {
      name[0] = symbol1;
      for (char symbol2 : symbols) {
        name[1] = symbol2;
        if (!has(name))
          return added(name);
      }
    }
    fail("run out of 1- and 2-letter chain names");
  }

  std::string make_name_with_numeric_postfix(const std::string& base, int n) {
    std::string name = base;
    name += std::to_string(n);
    while (has(name)) {
      name.resize(base.size());
      name += std::to_string(++n);
    }
    return added(name);
  }

  std::string make_new_name(const std::string& old, int n) {
    switch (how) {
      case How::Short: return make_short_name(old);
      case How::AddNumber: return make_name_with_numeric_postfix(old, n);
      case How::Dup: return old;
    }
    unreachable();
  }
};

inline Model make_assembly(const Assembly& assembly, const Model& model,
                           HowToNameCopiedChains how, std::ostream* out) {
  Model new_model(model.name);
  ChainNameGenerator namegen(how);
  std::map<std::string, std::string> subs = model.subchain_to_chain();
  for (const Assembly::Gen& gen : assembly.generators)
    for (const Assembly::Operator& oper : gen.operators) {
      if (out) {
        *out << "Applying " << oper.name << " to";
        if (!gen.chains.empty())
          *out << " chains: " << join_str(gen.chains, ',');
        else if (!gen.subchains.empty())
          *out << " subchains: " << join_str(gen.subchains, ',');
        *out << std::endl;
        for (const std::string& chain_name : gen.chains)
          if (!model.find_chain(chain_name))
            *out << "Warning: no chain " << chain_name << std::endl;
        for (const std::string& subchain_name : gen.subchains)
          if (subs.find(subchain_name) == subs.end())
            *out << "Warning: no subchain " << subchain_name << std::endl;
      }
      // PDB files specify bioassemblies in terms of chains,
      // mmCIF files in terms of subchains. We handle the two cases separately.
      if (!gen.chains.empty()) {
        // chains are not merged here, multiple chains may have the same name
        std::map<std::string, std::string> new_names;
        for (size_t i = 0; i != model.chains.size(); ++i) {
          if (in_vector(model.chains[i].name, gen.chains)) {
            new_model.chains.push_back(model.chains[i]);
            Chain& new_chain = new_model.chains.back();
            auto name_iter = new_names.find(model.chains[i].name);
            if (name_iter == new_names.end()) {
              new_chain.name = namegen.make_new_name(new_chain.name, 1);
              new_names.emplace(model.chains[i].name, new_chain.name);
            } else {
              new_chain.name = name_iter->second;
            }
            for (Residue& res : new_chain.residues) {
              for (Atom& a : res.atoms)
                a.pos = Position(oper.transform.apply(a.pos));
              if (!res.subchain.empty())
                res.subchain = new_chain.name + ":" + res.subchain;
            }
          }
        }
      } else if (!gen.subchains.empty()) {
        std::map<std::string, std::string> new_names;
        for (const std::string& subchain_name : gen.subchains) {
          auto sub_iter = subs.find(subchain_name);
          if (sub_iter == subs.end())
            continue;
          auto name_iter = new_names.find(sub_iter->second);
          Chain* new_chain;
          if (name_iter == new_names.end()) {
            std::string new_name = namegen.make_new_name(sub_iter->second, 1);
            new_names.emplace(sub_iter->second, new_name);
            new_model.chains.emplace_back(new_name);
            new_chain = &new_model.chains.back();
          } else {
            new_chain = new_model.find_chain(name_iter->second);
          }
          for (const Residue& res : model.get_subchain(subchain_name)) {
            new_chain->residues.push_back(res);
            Residue& new_res = new_chain->residues.back();
            new_res.subchain = new_chain->name + ":" + res.subchain;
            for (Atom& a : new_res.atoms)
              a.pos = Position(oper.transform.apply(a.pos));
          }
        }
      }
    }
  return new_model;
}

inline void change_to_assembly(Structure& st, const std::string& assembly_name,
                               HowToNameCopiedChains how, std::ostream* out) {
  Assembly* assembly = st.find_assembly(assembly_name);
  if (!assembly) {
    if (st.assemblies.empty())
      fail("no bioassemblies are listed for this structure");
    fail("wrong assembly name, use one of: " +
        join_str(st.assemblies, ' ', [](const Assembly& a) { return a.name; }));
  }
  for (Model& model : st.models)
    model = make_assembly(*assembly, model, how, out);
  st.connections.clear();
}

// chain is assumed to be from st.models[0]
inline void rename_chain(Structure& st, Chain& chain,
                         const std::string& new_name) {
  auto rename_if_matches = [&](AtomAddress& aa) {
    if (aa.chain_name == chain.name)
      aa.chain_name = new_name;
  };
  for (Connection& con : st.connections) {
    rename_if_matches(con.partner1);
    rename_if_matches(con.partner2);
  }
  for (Helix& helix : st.helices) {
    rename_if_matches(helix.start);
    rename_if_matches(helix.end);
  }
  for (Sheet& sheet : st.sheets)
    for (Sheet::Strand& strand : sheet.strands) {
      rename_if_matches(strand.start);
      rename_if_matches(strand.end);
      rename_if_matches(strand.hbond_atom2);
      rename_if_matches(strand.hbond_atom1);
    }
  for (RefinementInfo& ri : st.meta.refinement)
    for (TlsGroup& tls : ri.tls_groups)
      for (TlsGroup::Selection& sel : tls.selections)
        if (sel.chain == chain.name)
          sel.chain = new_name;
  for (auto it = st.models.begin() + 1; it != st.models.end(); ++it)
    if (Chain* ch = it->find_chain(chain.name))
      ch->name = new_name;
  chain.name = new_name;
}

inline void shorten_chain_names(Structure& st) {
  ChainNameGenerator namegen(HowToNameCopiedChains::Short);
  Model& model0 = st.models[0];
  size_t max_len = model0.chains.size() < 63 ? 1 : 2;
  for (const Chain& chain : model0.chains)
    if (chain.name.length() <= max_len)
      namegen.used_names.push_back(chain.name);
  for (Chain& chain : model0.chains)
    if (chain.name.length() > max_len)
      rename_chain(st, chain,
                   namegen.make_short_name(chain.name.substr(0, max_len)));
}

inline void expand_ncs(gemmi::Structure& st, HowToNameCopiedChains how) {
  for (gemmi::Model& model : st.models) {
    size_t orig_size = model.chains.size();
    gemmi::ChainNameGenerator namegen(model, how);
    for (const gemmi::NcsOp& op : st.ncs)
      if (!op.given) {
        for (size_t i = 0; i != orig_size; ++i) {
          if (how == HowToNameCopiedChains::Dup)
            for (gemmi::Residue& res : model.chains[i].residues)
              res.segment = "0";

          model.chains.push_back(model.chains[i]);
          gemmi::Chain& new_chain = model.chains.back();
          new_chain.name = namegen.make_new_name(new_chain.name, (int)i+1);

          for (gemmi::Residue& res : new_chain.residues) {
            for (gemmi::Atom& a : res.atoms)
              a.pos = op.apply(a.pos);
            if (!res.subchain.empty())
              res.subchain = new_chain.name + ":" + res.subchain;
            if (how == HowToNameCopiedChains::Dup)
              res.segment = op.id;
          }
        }
      }
  }
  for (gemmi::NcsOp& op : st.ncs)
    op.given = true;
  st.setup_cell_images();
}

} // namespace gemmi
#endif
<commit_msg>Apply ncs operator to aniso<commit_after>// Copyright 2020 Global Phasing Ltd.
//
// A function that generates biological assemblies by applying operations
// from struct Assembly to a Model.
// And chain (re)naming utilities.

#ifndef GEMMI_ASSEMBLY_HPP_
#define GEMMI_ASSEMBLY_HPP_

#include <ostream>      // std::ostream
#include "model.hpp"
#include "util.hpp"

namespace gemmi {

enum class HowToNameCopiedChains { Short, AddNumber, Dup };

struct ChainNameGenerator {
  using How = HowToNameCopiedChains;
  How how;
  std::vector<std::string> used_names;

  ChainNameGenerator(How how_) : how(how_) {}
  ChainNameGenerator(const Model& model, How how_) : how(how_) {
    if (how != How::Dup)
      for (const Chain& chain : model.chains)
        used_names.push_back(chain.name);
  }
  bool has(const std::string& name) const {
    return in_vector(name, used_names);
  }
  const std::string& added(const std::string& name) {
    used_names.push_back(name);
    return name;
  }

  std::string make_short_name(const std::string& preferred) {
    static const char symbols[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                  "abcdefghijklmnopqrstuvwxyz0123456789";
    if (!has(preferred))
      return added(preferred);
    std::string name(1, 'A');
    for (char symbol : symbols) {
      name[0] = symbol;
      if (!has(name))
        return added(name);
    }
    name += 'A';
    for (char symbol1 : symbols) {
      name[0] = symbol1;
      for (char symbol2 : symbols) {
        name[1] = symbol2;
        if (!has(name))
          return added(name);
      }
    }
    fail("run out of 1- and 2-letter chain names");
  }

  std::string make_name_with_numeric_postfix(const std::string& base, int n) {
    std::string name = base;
    name += std::to_string(n);
    while (has(name)) {
      name.resize(base.size());
      name += std::to_string(++n);
    }
    return added(name);
  }

  std::string make_new_name(const std::string& old, int n) {
    switch (how) {
      case How::Short: return make_short_name(old);
      case How::AddNumber: return make_name_with_numeric_postfix(old, n);
      case How::Dup: return old;
    }
    unreachable();
  }
};

inline Model make_assembly(const Assembly& assembly, const Model& model,
                           HowToNameCopiedChains how, std::ostream* out) {
  Model new_model(model.name);
  ChainNameGenerator namegen(how);
  std::map<std::string, std::string> subs = model.subchain_to_chain();
  for (const Assembly::Gen& gen : assembly.generators)
    for (const Assembly::Operator& oper : gen.operators) {
      if (out) {
        *out << "Applying " << oper.name << " to";
        if (!gen.chains.empty())
          *out << " chains: " << join_str(gen.chains, ',');
        else if (!gen.subchains.empty())
          *out << " subchains: " << join_str(gen.subchains, ',');
        *out << std::endl;
        for (const std::string& chain_name : gen.chains)
          if (!model.find_chain(chain_name))
            *out << "Warning: no chain " << chain_name << std::endl;
        for (const std::string& subchain_name : gen.subchains)
          if (subs.find(subchain_name) == subs.end())
            *out << "Warning: no subchain " << subchain_name << std::endl;
      }
      // PDB files specify bioassemblies in terms of chains,
      // mmCIF files in terms of subchains. We handle the two cases separately.
      if (!gen.chains.empty()) {
        // chains are not merged here, multiple chains may have the same name
        std::map<std::string, std::string> new_names;
        for (size_t i = 0; i != model.chains.size(); ++i) {
          if (in_vector(model.chains[i].name, gen.chains)) {
            new_model.chains.push_back(model.chains[i]);
            Chain& new_chain = new_model.chains.back();
            auto name_iter = new_names.find(model.chains[i].name);
            if (name_iter == new_names.end()) {
              new_chain.name = namegen.make_new_name(new_chain.name, 1);
              new_names.emplace(model.chains[i].name, new_chain.name);
            } else {
              new_chain.name = name_iter->second;
            }
            for (Residue& res : new_chain.residues) {
              for (Atom& a : res.atoms)
                a.pos = Position(oper.transform.apply(a.pos));
              if (!res.subchain.empty())
                res.subchain = new_chain.name + ":" + res.subchain;
            }
          }
        }
      } else if (!gen.subchains.empty()) {
        std::map<std::string, std::string> new_names;
        for (const std::string& subchain_name : gen.subchains) {
          auto sub_iter = subs.find(subchain_name);
          if (sub_iter == subs.end())
            continue;
          auto name_iter = new_names.find(sub_iter->second);
          Chain* new_chain;
          if (name_iter == new_names.end()) {
            std::string new_name = namegen.make_new_name(sub_iter->second, 1);
            new_names.emplace(sub_iter->second, new_name);
            new_model.chains.emplace_back(new_name);
            new_chain = &new_model.chains.back();
          } else {
            new_chain = new_model.find_chain(name_iter->second);
          }
          for (const Residue& res : model.get_subchain(subchain_name)) {
            new_chain->residues.push_back(res);
            Residue& new_res = new_chain->residues.back();
            new_res.subchain = new_chain->name + ":" + res.subchain;
            for (Atom& a : new_res.atoms)
              a.pos = Position(oper.transform.apply(a.pos));
          }
        }
      }
    }
  return new_model;
}

inline void change_to_assembly(Structure& st, const std::string& assembly_name,
                               HowToNameCopiedChains how, std::ostream* out) {
  Assembly* assembly = st.find_assembly(assembly_name);
  if (!assembly) {
    if (st.assemblies.empty())
      fail("no bioassemblies are listed for this structure");
    fail("wrong assembly name, use one of: " +
        join_str(st.assemblies, ' ', [](const Assembly& a) { return a.name; }));
  }
  for (Model& model : st.models)
    model = make_assembly(*assembly, model, how, out);
  st.connections.clear();
}

// chain is assumed to be from st.models[0]
inline void rename_chain(Structure& st, Chain& chain,
                         const std::string& new_name) {
  auto rename_if_matches = [&](AtomAddress& aa) {
    if (aa.chain_name == chain.name)
      aa.chain_name = new_name;
  };
  for (Connection& con : st.connections) {
    rename_if_matches(con.partner1);
    rename_if_matches(con.partner2);
  }
  for (Helix& helix : st.helices) {
    rename_if_matches(helix.start);
    rename_if_matches(helix.end);
  }
  for (Sheet& sheet : st.sheets)
    for (Sheet::Strand& strand : sheet.strands) {
      rename_if_matches(strand.start);
      rename_if_matches(strand.end);
      rename_if_matches(strand.hbond_atom2);
      rename_if_matches(strand.hbond_atom1);
    }
  for (RefinementInfo& ri : st.meta.refinement)
    for (TlsGroup& tls : ri.tls_groups)
      for (TlsGroup::Selection& sel : tls.selections)
        if (sel.chain == chain.name)
          sel.chain = new_name;
  for (auto it = st.models.begin() + 1; it != st.models.end(); ++it)
    if (Chain* ch = it->find_chain(chain.name))
      ch->name = new_name;
  chain.name = new_name;
}

inline void shorten_chain_names(Structure& st) {
  ChainNameGenerator namegen(HowToNameCopiedChains::Short);
  Model& model0 = st.models[0];
  size_t max_len = model0.chains.size() < 63 ? 1 : 2;
  for (const Chain& chain : model0.chains)
    if (chain.name.length() <= max_len)
      namegen.used_names.push_back(chain.name);
  for (Chain& chain : model0.chains)
    if (chain.name.length() > max_len)
      rename_chain(st, chain,
                   namegen.make_short_name(chain.name.substr(0, max_len)));
}

inline void expand_ncs(gemmi::Structure& st, HowToNameCopiedChains how) {
  for (gemmi::Model& model : st.models) {
    size_t orig_size = model.chains.size();
    gemmi::ChainNameGenerator namegen(model, how);
    for (const gemmi::NcsOp& op : st.ncs)
      if (!op.given) {
        for (size_t i = 0; i != orig_size; ++i) {
          if (how == HowToNameCopiedChains::Dup)
            for (gemmi::Residue& res : model.chains[i].residues)
              res.segment = "0";

          model.chains.push_back(model.chains[i]);
          gemmi::Chain& new_chain = model.chains.back();
          new_chain.name = namegen.make_new_name(new_chain.name, (int)i+1);

          for (gemmi::Residue& res : new_chain.residues) {
            for (gemmi::Atom& a : res.atoms) {
              a.pos = op.apply(a.pos);
              if (a.aniso.nonzero()) {
                SMat33<double> u = a.aniso.transformed_by(op.tr.mat);
                a.aniso = {static_cast<float>(u.u11), static_cast<float>(u.u22), static_cast<float>(u.u33),
                           static_cast<float>(u.u12), static_cast<float>(u.u13), static_cast<float>(u.u23)};
              }
            }
            if (!res.subchain.empty())
              res.subchain = new_chain.name + ":" + res.subchain;
            if (how == HowToNameCopiedChains::Dup)
              res.segment = op.id;
          }
        }
      }
  }
  for (gemmi::NcsOp& op : st.ncs)
    op.given = true;
  st.setup_cell_images();
}

} // namespace gemmi
#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_RSS_HPP_INCLUDED
#define TORRENT_RSS_HPP_INCLUDED

#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/size_type.hpp"

#include <boost/enable_shared_from_this.hpp>
#include <string>

namespace libtorrent
{
	namespace aux
	{ struct session_impl; }

	struct feed_item
	{
		feed_item(): size(-1) {}
		std::string url;
		std::string uuid;
		std::string title;
		std::string description;
		std::string comment;
		std::string category;
		size_type size;
		torrent_handle handle;
		sha1_hash info_hash;
	};

#ifndef BOOST_NO_EXCEPTIONS
	torrent_handle add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p);
#endif

	torrent_handle add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p, error_code& ec);

	// the feed_settings object is all the information
	// and configuration for a specific feed. All of
	// these settings can be changed by the user
	// after adding the feed
	struct feed_settings
	{
		feed_settings()
			: auto_download(true)
			, default_ttl(30)
		{}

   	std::string url;

		bool auto_download;

		// in minutes
		int default_ttl;

		// used when adding torrents
		add_torrent_params add_args;
	};

	struct feed_status
	{
		feed_status(): last_update(0), next_update(0)
			, updating(false), ttl(0) {}
		std::string url;
		std::string title;
		std::string description;
		time_t last_update;
		int next_update;
		bool updating;
		std::vector<feed_item> items;
		error_code error;
		int ttl;
	};

	struct feed;

	struct feed_handle
	{
		feed_handle() {}
		void update_feed();
		feed_status get_feed_status() const;
		void set_settings(feed_settings const& s);
		feed_settings settings() const;
	private:
		friend struct aux::session_impl;
		friend struct feed;
		feed_handle(boost::weak_ptr<feed> const& p);
		boost::weak_ptr<feed> m_feed_ptr;
	};

	struct feed_state;
	class http_parser;

	boost::shared_ptr<feed> new_feed(aux::session_impl& ses, feed_settings const& sett);

	// this is the internal object holding all state about an
	// RSS feed. All user interaction with this object
	// goes through the feed_handle, which makes sure all calls
	// are posted to the network thread
	struct feed : boost::enable_shared_from_this<feed>
	{
		friend void parse_feed(feed_state& f, int token, char const* name, char const* val);

		feed(aux::session_impl& ses, feed_settings const& feed);

		void on_feed(error_code const& ec, http_parser const& parser
			, char const* data, int size);

		void update_feed();

		aux::session_impl& session() const { return m_ses; }

		void set_settings(feed_settings const& s);
		void get_settings(feed_settings* s) const;
   	void get_feed_status(feed_status* ret) const;

		int next_update(time_t now) const;

		void load_state(lazy_entry const& rd);
		void save_state(entry& rd) const;

//	private:

		feed_handle my_handle();

		error_code m_error;
		std::vector<feed_item> m_items;
		std::string m_title;
   	std::string m_description;
		time_t m_last_attempt;
   	time_t m_last_update;
		// refresh rate of this feed in minutes
		int m_ttl;
		// true while waiting for the server to respond
		bool m_updating;
		feed_settings m_settings;

		aux::session_impl& m_ses;
	};

};

#endif

<commit_msg>add export macros<commit_after>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_RSS_HPP_INCLUDED
#define TORRENT_RSS_HPP_INCLUDED

#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/add_torrent_params.hpp"
#include "libtorrent/size_type.hpp"

#include <boost/enable_shared_from_this.hpp>
#include <string>

namespace libtorrent
{
	namespace aux
	{ struct session_impl; }

	struct feed_item
	{
		feed_item(): size(-1) {}
		std::string url;
		std::string uuid;
		std::string title;
		std::string description;
		std::string comment;
		std::string category;
		size_type size;
		torrent_handle handle;
		sha1_hash info_hash;
	};

#ifndef BOOST_NO_EXCEPTIONS
	torrent_handle TORRENT_EXPORT add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p);
#endif

	torrent_handle TORRENT_EXPORT add_feed_item(session& s, feed_item const& fi
		, add_torrent_params const& p, error_code& ec);

	// the feed_settings object is all the information
	// and configuration for a specific feed. All of
	// these settings can be changed by the user
	// after adding the feed
	struct feed_settings
	{
		feed_settings()
			: auto_download(true)
			, default_ttl(30)
		{}

   	std::string url;

		bool auto_download;

		// in minutes
		int default_ttl;

		// used when adding torrents
		add_torrent_params add_args;
	};

	struct feed_status
	{
		feed_status(): last_update(0), next_update(0)
			, updating(false), ttl(0) {}
		std::string url;
		std::string title;
		std::string description;
		time_t last_update;
		int next_update;
		bool updating;
		std::vector<feed_item> items;
		error_code error;
		int ttl;
	};

	struct feed;

	struct TORRENT_EXPORT feed_handle
	{
		feed_handle() {}
		void update_feed();
		feed_status get_feed_status() const;
		void set_settings(feed_settings const& s);
		feed_settings settings() const;
	private:
		friend struct aux::session_impl;
		friend struct feed;
		feed_handle(boost::weak_ptr<feed> const& p);
		boost::weak_ptr<feed> m_feed_ptr;
	};

	struct feed_state;
	class http_parser;

	boost::shared_ptr<feed> new_feed(aux::session_impl& ses, feed_settings const& sett);

	// this is the internal object holding all state about an
	// RSS feed. All user interaction with this object
	// goes through the feed_handle, which makes sure all calls
	// are posted to the network thread
	struct TORRENT_EXPORT feed : boost::enable_shared_from_this<feed>
	{
		friend void parse_feed(feed_state& f, int token, char const* name, char const* val);

		feed(aux::session_impl& ses, feed_settings const& feed);

		void on_feed(error_code const& ec, http_parser const& parser
			, char const* data, int size);

		void update_feed();

		aux::session_impl& session() const { return m_ses; }

		void set_settings(feed_settings const& s);
		void get_settings(feed_settings* s) const;
   	void get_feed_status(feed_status* ret) const;

		int next_update(time_t now) const;

		void load_state(lazy_entry const& rd);
		void save_state(entry& rd) const;

//	private:

		feed_handle my_handle();

		error_code m_error;
		std::vector<feed_item> m_items;
		std::string m_title;
   	std::string m_description;
		time_t m_last_attempt;
   	time_t m_last_update;
		// refresh rate of this feed in minutes
		int m_ttl;
		// true while waiting for the server to respond
		bool m_updating;
		feed_settings m_settings;

		aux::session_impl& m_ses;
	};

};

#endif

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/

#ifndef MAPNIK_VERSION_HPP
#define MAPNIK_VERSION_HPP

#define MAPNIK_VERSION_IS_RELEASE 0

#define MAPNIK_MAJOR_VERSION 3
#define MAPNIK_MINOR_VERSION 0
#define MAPNIK_PATCH_VERSION 0

// translates to 300000
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)

#ifndef MAPNIK_STRINGIFY
#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n)
#define MAPNIK_STRINGIFY_HELPER(n) #n
#endif

#if MAPNIK_VERSION_IS_RELEASE
#define MAPNIK_VERSION_STRING   MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION)

#else
#define MAPNIK_VERSION_STRING   MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) "-pre"
#endif

#endif // MAPNIK_VERSION_HPP
<commit_msg>setting up for mapnik v3.0.0 release<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 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
 *
 *****************************************************************************/

#ifndef MAPNIK_VERSION_HPP
#define MAPNIK_VERSION_HPP

#define MAPNIK_VERSION_IS_RELEASE 1

#define MAPNIK_MAJOR_VERSION 3
#define MAPNIK_MINOR_VERSION 0
#define MAPNIK_PATCH_VERSION 0

// translates to 300000
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)

#ifndef MAPNIK_STRINGIFY
#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n)
#define MAPNIK_STRINGIFY_HELPER(n) #n
#endif

#if MAPNIK_VERSION_IS_RELEASE
#define MAPNIK_VERSION_STRING   MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION)

#else
#define MAPNIK_VERSION_STRING   MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
                                MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) "-pre"
#endif

#endif // MAPNIK_VERSION_HPP
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_VALUES_HH__
#define __MINIZINC_VALUES_HH__

#include <minizinc/gc.hh>
#include <minizinc/exception.hh>
#include <minizinc/stl_map_set.hh>
#include <minizinc/thirdparty/SafeInt3.hpp>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>

namespace MiniZinc {
  class IntVal;
}
namespace std {
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x);
}

#ifdef _MSC_VER
#define MZN_NORETURN __declspec(noreturn)
#define MZN_NORETURN_ATTR
#else
#define MZN_NORETURN
#define MZN_NORETURN_ATTR __attribute__((__noreturn__))
#endif

namespace MiniZinc {

  class MiniZincSafeIntExceptionHandler
  {
  public:
    static MZN_NORETURN void SafeIntOnOverflow() MZN_NORETURN_ATTR
    {
      throw ArithmeticError( "integer overflow" );
    }

    static MZN_NORETURN void SafeIntOnDivZero() MZN_NORETURN_ATTR
    {
      throw ArithmeticError( "integer division by zero" );
    }
  };
}

#undef MZN_NORETURN

namespace MiniZinc {

  class IntVal {
    friend IntVal operator +(const IntVal& x, const IntVal& y);
    friend IntVal operator -(const IntVal& x, const IntVal& y);
    friend IntVal operator *(const IntVal& x, const IntVal& y);
    friend IntVal operator /(const IntVal& x, const IntVal& y);
    friend IntVal operator %(const IntVal& x, const IntVal& y);
    friend IntVal std::abs(const MiniZinc::IntVal& x);
    friend bool operator ==(const IntVal& x, const IntVal& y);
  private:
    long long int _v;
    bool _infinity;
    IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {}
    typedef SafeInt<long long int, MiniZincSafeIntExceptionHandler> SI;
    SI toSafeInt(void) const { return _v; }
    IntVal(SI v) : _v(v), _infinity(false) {}
  public:
    IntVal(void) : _v(0), _infinity(false) {}
    IntVal(long long int v) : _v(v), _infinity(false) {}

    long long int toInt(void) const {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      return _v;
    }

    bool isFinite(void) const { return !_infinity; }
    bool isPlusInfinity(void) const { return _infinity && _v==1; }
    bool isMinusInfinity(void) const { return _infinity && _v==-1; }

    IntVal& operator +=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v += x._v;
      return *this;
    }
    IntVal& operator -=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v -= x._v;
      return *this;
    }
    IntVal& operator *=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v *= x._v;
      return *this;
    }
    IntVal& operator /=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v /= x._v;
      return *this;
    }
    IntVal operator -() const {
      IntVal r = *this;
      r._v = -r._v;
      return r;
    }
    void operator ++() {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      ++_v;
    }
    void operator ++(int) {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      ++_v;
    }
    void operator --() {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      --_v;
    }
    void operator --(int) {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      --_v;
    }
    static const IntVal minint;
    static const IntVal maxint;
    static const IntVal infinity;

    /// Infinity-safe addition
    IntVal plus(int x) {
      if (isFinite())
        return toSafeInt()+x;
      else
        return *this;
    }
    /// Infinity-safe subtraction
    IntVal minus(int x) {
      if (isFinite())
        return toSafeInt()-x;
      else
        return *this;
    }
  };

  inline
  bool operator ==(const IntVal& x, const IntVal& y) {
    return x.isFinite()==y.isFinite() && x._v == y._v;
  }
  inline
  bool operator <=(const IntVal& x, const IntVal& y) {
    return y.isPlusInfinity() || x.isMinusInfinity() || (x.isFinite() && y.isFinite() && x.toInt() <= y.toInt());
  }
  inline
  bool operator <(const IntVal& x, const IntVal& y) {
    return
      (y.isPlusInfinity() && !x.isPlusInfinity()) ||
      (x.isMinusInfinity() && !y.isMinusInfinity()) ||
      (x.isFinite() && y.isFinite() && x.toInt() < y.toInt());
  }
  inline
  bool operator >=(const IntVal& x, const IntVal& y) {
    return y <= x;
  }
  inline
  bool operator >(const IntVal& x, const IntVal& y) {
    return y < x;
  }
  inline
  bool operator !=(const IntVal& x, const IntVal& y) {
    return !(x==y);
  }
  inline
  IntVal operator +(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()+y.toSafeInt();
  }
  inline
  IntVal operator -(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()-y.toSafeInt();
  }
  inline
  IntVal operator *(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()*y.toSafeInt();
  }
  inline
  IntVal operator /(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toInt()/y.toInt();
  }
  inline
  IntVal operator %(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toInt()%y.toInt();
  }
  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntVal& s) {
    if (s.isMinusInfinity())
      return os << "-infinity";
    else if (s.isPlusInfinity())
      return os << "infinity";
    else
      return os << s.toInt();
  }
}

namespace std {
  inline
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
    if (!x.isFinite()) return MiniZinc::IntVal::infinity;
    MiniZinc::IntVal::SI y(x.toInt());
    return y < 0 ? MiniZinc::IntVal(static_cast<long long int>(-y)) : x;
  }

  inline
  MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return x <= y ? x : y;
  }
  inline
  MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return x >= y ? x : y;
  }

  template<>
  struct equal_to<MiniZinc::IntVal> {
  public:
    bool operator()(const MiniZinc::IntVal& s0,
                    const MiniZinc::IntVal& s1) const {
      return s0==s1;
    }
  };
}

OPEN_HASH_NAMESPACE {
  template<>
  struct hash<MiniZinc::IntVal> {
  public:
    size_t operator()(const MiniZinc::IntVal& s) const {
      HASH_NAMESPACE::hash<long long int> longhash;
      size_t h;
      if (s.isPlusInfinity())
        h = longhash(LONG_MAX);
      else if (s.isMinusInfinity())
        h = longhash(LONG_MIN);
      else
        h = longhash(s.toInt());
      HASH_NAMESPACE::hash<bool> boolhash;
      h ^= boolhash(s.isFinite()) + 0x9e3779b9 + (h << 6) + (h >> 2);
      return h;
    }
  };
CLOSE_HASH_NAMESPACE }

namespace MiniZinc {

  typedef unsigned long long int UIntVal;

  typedef double FloatVal;

  /// An integer set value
  class IntSetVal : public ASTChunk {
  public:
    /// Contiguous range
    struct Range {
      /// Range minimum
      IntVal min;
      /// Range maximum
      IntVal max;
      /// Construct range from \a m to \a n
      Range(IntVal m, IntVal n) : min(m), max(n) {}
      /// Default constructor
      Range(void) {}
    };
  private:
    /// Return range at position \a i
    Range& get(int i) {
      return reinterpret_cast<Range*>(_data)[i];
    }
    /// Return range at position \a i
    const Range& get(int i) const {
      return reinterpret_cast<const Range*>(_data)[i];
    }
    /// Construct empty set
    IntSetVal(void) : ASTChunk(0) {}
    /// Construct set of single range
    IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) {
      get(0).min = m;
      get(0).max = n;
    }
    /// Construct set from \a s
    IntSetVal(const std::vector<Range>& s)
      : ASTChunk(sizeof(Range)*s.size()) {
      for (unsigned int i=s.size(); i--;)
        get(i) = s[i];
    }

    /// Disabled
    IntSetVal(const IntSetVal& r);
    /// Disabled
    IntSetVal& operator =(const IntSetVal& r);
  public:
    /// Return number of ranges
    int size(void) const { return _size / sizeof(Range); }
    /// Return minimum, or infinity if set is empty
    IntVal min(void) const { return size()==0 ? IntVal::infinity : get(0).min; }
    /// Return maximum, or minus infinity if set is empty
    IntVal max(void) const { return size()==0 ? -IntVal::infinity : get(size()-1).max; }
    /// Return minimum of range \a i
    IntVal min(int i) const { assert(i<size()); return get(i).min; }
    /// Return maximum of range \a i
    IntVal max(int i) const { assert(i<size()); return get(i).max; }
    /// Return width of range \a i
    IntVal width(int i) const {
      assert(i<size());
      if (min(i).isFinite() && max(i).isFinite())
        return max(i)-min(i)+1;
      else
        return IntVal::infinity;
    }
    /// Return cardinality
    IntVal card(void) const {
      IntVal c = 0;
      for (unsigned int i=size(); i--;) {
        if (width(i).isFinite())
          c += width(i);
        else
          return IntVal::infinity;
      }
      return c;
    }

    /// Allocate empty set from context
    static IntSetVal* a(void) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
      new (r) IntSetVal();
      return r;
    }

    /// Allocate set \f$\{m,n\}\f$ from context
    static IntSetVal* a(IntVal m, IntVal n) {
      if (m>n) {
        return a();
      } else {
        IntSetVal* r =
          static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
        new (r) IntSetVal(m,n);
        return r;
      }
    }

    /// Allocate set using iterator \a i
    template<class I>
    static IntSetVal* ai(I& i) {
      std::vector<Range> s;
      for (; i(); ++i)
        s.push_back(Range(i.min(),i.max()));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*s.size()));
      new (r) IntSetVal(s);
      return r;
    }

    /// Allocate set from vector \a s0 (may contain duplicates)
    static IntSetVal* a(const std::vector<IntVal>& s0) {
      if (s0.size()==0)
        return a();
      std::vector<IntVal> s=s0;
      std::sort(s.begin(),s.end());
      std::vector<Range> ranges;
      IntVal min=s[0];
      IntVal max=min;
      for (unsigned int i=1; i<s.size(); i++) {
        if (s[i]>max+1) {
          ranges.push_back(Range(min,max));
          min=s[i]; max=min;
        } else {
          max=s[i];
        }
      }
      ranges.push_back(Range(min,max));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }
    static IntSetVal* a(const std::vector<Range>& ranges) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }

    /// Check if set contains \a v
    bool contains(const IntVal& v) {
      for (int i=0; i<size(); i++) {
        if (v < min(i))
          return false;
        if (v <= max(i))
          return true;
      }
      return false;
    }

    /// Check if it is equal to \a s
    bool equal(const IntSetVal* s) {
      if (size()!=s->size())
        return false;
      for (int i=0; i<size(); i++)
        if (min(i)!=s->min(i) || max(i)!=s->max(i))
          return false;
      return true;
    }

    /// Mark for garbage collection
    void mark(void) {
      _gc_mark = 1;
    }
  };

  /// Iterator over an IntSetVal
  class IntSetRanges {
    /// The set value
    const IntSetVal* rs;
    /// The current range
    int n;
  public:
    /// Constructor
    IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
    /// Check if iterator is still valid
    bool operator()(void) const { return n<rs->size(); }
    /// Move to next range
    void operator++(void) { ++n; }
    /// Return minimum of current range
    IntVal min(void) const { return rs->min(n); }
    /// Return maximum of current range
    IntVal max(void) const { return rs->max(n); }
    /// Return width of current range
    IntVal width(void) const { return rs->width(n); }
  };

  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntSetVal& s) {
    for (IntSetRanges isr(&s); isr(); ++isr)
      os << isr.min() << ".." << isr.max() << " ";
    return os;
  }

}

#endif
<commit_msg>added limits.h to values.hh so compiles with gcc<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_VALUES_HH__
#define __MINIZINC_VALUES_HH__

#include <minizinc/gc.hh>
#include <minizinc/exception.hh>
#include <minizinc/stl_map_set.hh>
#include <minizinc/thirdparty/SafeInt3.hpp>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>
#include <limits.h>

namespace MiniZinc {
  class IntVal;
}
namespace std {
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x);
}

#ifdef _MSC_VER
#define MZN_NORETURN __declspec(noreturn)
#define MZN_NORETURN_ATTR
#else
#define MZN_NORETURN
#define MZN_NORETURN_ATTR __attribute__((__noreturn__))
#endif

namespace MiniZinc {

  class MiniZincSafeIntExceptionHandler
  {
  public:
    static MZN_NORETURN void SafeIntOnOverflow() MZN_NORETURN_ATTR
    {
      throw ArithmeticError( "integer overflow" );
    }

    static MZN_NORETURN void SafeIntOnDivZero() MZN_NORETURN_ATTR
    {
      throw ArithmeticError( "integer division by zero" );
    }
  };
}

#undef MZN_NORETURN

namespace MiniZinc {

  class IntVal {
    friend IntVal operator +(const IntVal& x, const IntVal& y);
    friend IntVal operator -(const IntVal& x, const IntVal& y);
    friend IntVal operator *(const IntVal& x, const IntVal& y);
    friend IntVal operator /(const IntVal& x, const IntVal& y);
    friend IntVal operator %(const IntVal& x, const IntVal& y);
    friend IntVal std::abs(const MiniZinc::IntVal& x);
    friend bool operator ==(const IntVal& x, const IntVal& y);
  private:
    long long int _v;
    bool _infinity;
    IntVal(long long int v, bool infinity) : _v(v), _infinity(infinity) {}
    typedef SafeInt<long long int, MiniZincSafeIntExceptionHandler> SI;
    SI toSafeInt(void) const { return _v; }
    IntVal(SI v) : _v(v), _infinity(false) {}
  public:
    IntVal(void) : _v(0), _infinity(false) {}
    IntVal(long long int v) : _v(v), _infinity(false) {}

    long long int toInt(void) const {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      return _v;
    }

    bool isFinite(void) const { return !_infinity; }
    bool isPlusInfinity(void) const { return _infinity && _v==1; }
    bool isMinusInfinity(void) const { return _infinity && _v==-1; }

    IntVal& operator +=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v += x._v;
      return *this;
    }
    IntVal& operator -=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v -= x._v;
      return *this;
    }
    IntVal& operator *=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v *= x._v;
      return *this;
    }
    IntVal& operator /=(const IntVal& x) {
      if (! (isFinite() && x.isFinite()))
        throw ArithmeticError("arithmetic operation on infinite value");
      _v /= x._v;
      return *this;
    }
    IntVal operator -() const {
      IntVal r = *this;
      r._v = -r._v;
      return r;
    }
    void operator ++() {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      ++_v;
    }
    void operator ++(int) {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      ++_v;
    }
    void operator --() {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      --_v;
    }
    void operator --(int) {
      if (!isFinite())
        throw ArithmeticError("arithmetic operation on infinite value");
      --_v;
    }
    static const IntVal minint;
    static const IntVal maxint;
    static const IntVal infinity;

    /// Infinity-safe addition
    IntVal plus(int x) {
      if (isFinite())
        return toSafeInt()+x;
      else
        return *this;
    }
    /// Infinity-safe subtraction
    IntVal minus(int x) {
      if (isFinite())
        return toSafeInt()-x;
      else
        return *this;
    }
  };

  inline
  bool operator ==(const IntVal& x, const IntVal& y) {
    return x.isFinite()==y.isFinite() && x._v == y._v;
  }
  inline
  bool operator <=(const IntVal& x, const IntVal& y) {
    return y.isPlusInfinity() || x.isMinusInfinity() || (x.isFinite() && y.isFinite() && x.toInt() <= y.toInt());
  }
  inline
  bool operator <(const IntVal& x, const IntVal& y) {
    return
      (y.isPlusInfinity() && !x.isPlusInfinity()) ||
      (x.isMinusInfinity() && !y.isMinusInfinity()) ||
      (x.isFinite() && y.isFinite() && x.toInt() < y.toInt());
  }
  inline
  bool operator >=(const IntVal& x, const IntVal& y) {
    return y <= x;
  }
  inline
  bool operator >(const IntVal& x, const IntVal& y) {
    return y < x;
  }
  inline
  bool operator !=(const IntVal& x, const IntVal& y) {
    return !(x==y);
  }
  inline
  IntVal operator +(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()+y.toSafeInt();
  }
  inline
  IntVal operator -(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()-y.toSafeInt();
  }
  inline
  IntVal operator *(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toSafeInt()*y.toSafeInt();
  }
  inline
  IntVal operator /(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toInt()/y.toInt();
  }
  inline
  IntVal operator %(const IntVal& x, const IntVal& y) {
    if (! (x.isFinite() && y.isFinite()))
      throw ArithmeticError("arithmetic operation on infinite value");
    return x.toInt()%y.toInt();
  }
  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntVal& s) {
    if (s.isMinusInfinity())
      return os << "-infinity";
    else if (s.isPlusInfinity())
      return os << "infinity";
    else
      return os << s.toInt();
  }
}

namespace std {
  inline
  MiniZinc::IntVal abs(const MiniZinc::IntVal& x) {
    if (!x.isFinite()) return MiniZinc::IntVal::infinity;
    MiniZinc::IntVal::SI y(x.toInt());
    return y < 0 ? MiniZinc::IntVal(static_cast<long long int>(-y)) : x;
  }

  inline
  MiniZinc::IntVal min(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return x <= y ? x : y;
  }
  inline
  MiniZinc::IntVal max(const MiniZinc::IntVal& x, const MiniZinc::IntVal& y) {
    return x >= y ? x : y;
  }

  template<>
  struct equal_to<MiniZinc::IntVal> {
  public:
    bool operator()(const MiniZinc::IntVal& s0,
                    const MiniZinc::IntVal& s1) const {
      return s0==s1;
    }
  };
}

OPEN_HASH_NAMESPACE {
  template<>
  struct hash<MiniZinc::IntVal> {
  public:
    size_t operator()(const MiniZinc::IntVal& s) const {
      HASH_NAMESPACE::hash<long long int> longhash;
      size_t h;
      if (s.isPlusInfinity())
        h = longhash(LONG_MAX);
      else if (s.isMinusInfinity())
        h = longhash(LONG_MIN);
      else
        h = longhash(s.toInt());
      HASH_NAMESPACE::hash<bool> boolhash;
      h ^= boolhash(s.isFinite()) + 0x9e3779b9 + (h << 6) + (h >> 2);
      return h;
    }
  };
CLOSE_HASH_NAMESPACE }

namespace MiniZinc {

  typedef unsigned long long int UIntVal;

  typedef double FloatVal;

  /// An integer set value
  class IntSetVal : public ASTChunk {
  public:
    /// Contiguous range
    struct Range {
      /// Range minimum
      IntVal min;
      /// Range maximum
      IntVal max;
      /// Construct range from \a m to \a n
      Range(IntVal m, IntVal n) : min(m), max(n) {}
      /// Default constructor
      Range(void) {}
    };
  private:
    /// Return range at position \a i
    Range& get(int i) {
      return reinterpret_cast<Range*>(_data)[i];
    }
    /// Return range at position \a i
    const Range& get(int i) const {
      return reinterpret_cast<const Range*>(_data)[i];
    }
    /// Construct empty set
    IntSetVal(void) : ASTChunk(0) {}
    /// Construct set of single range
    IntSetVal(IntVal m, IntVal n) : ASTChunk(sizeof(Range)) {
      get(0).min = m;
      get(0).max = n;
    }
    /// Construct set from \a s
    IntSetVal(const std::vector<Range>& s)
      : ASTChunk(sizeof(Range)*s.size()) {
      for (unsigned int i=s.size(); i--;)
        get(i) = s[i];
    }

    /// Disabled
    IntSetVal(const IntSetVal& r);
    /// Disabled
    IntSetVal& operator =(const IntSetVal& r);
  public:
    /// Return number of ranges
    int size(void) const { return _size / sizeof(Range); }
    /// Return minimum, or infinity if set is empty
    IntVal min(void) const { return size()==0 ? IntVal::infinity : get(0).min; }
    /// Return maximum, or minus infinity if set is empty
    IntVal max(void) const { return size()==0 ? -IntVal::infinity : get(size()-1).max; }
    /// Return minimum of range \a i
    IntVal min(int i) const { assert(i<size()); return get(i).min; }
    /// Return maximum of range \a i
    IntVal max(int i) const { assert(i<size()); return get(i).max; }
    /// Return width of range \a i
    IntVal width(int i) const {
      assert(i<size());
      if (min(i).isFinite() && max(i).isFinite())
        return max(i)-min(i)+1;
      else
        return IntVal::infinity;
    }
    /// Return cardinality
    IntVal card(void) const {
      IntVal c = 0;
      for (unsigned int i=size(); i--;) {
        if (width(i).isFinite())
          c += width(i);
        else
          return IntVal::infinity;
      }
      return c;
    }

    /// Allocate empty set from context
    static IntSetVal* a(void) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(0));
      new (r) IntSetVal();
      return r;
    }

    /// Allocate set \f$\{m,n\}\f$ from context
    static IntSetVal* a(IntVal m, IntVal n) {
      if (m>n) {
        return a();
      } else {
        IntSetVal* r =
          static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)));
        new (r) IntSetVal(m,n);
        return r;
      }
    }

    /// Allocate set using iterator \a i
    template<class I>
    static IntSetVal* ai(I& i) {
      std::vector<Range> s;
      for (; i(); ++i)
        s.push_back(Range(i.min(),i.max()));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*s.size()));
      new (r) IntSetVal(s);
      return r;
    }

    /// Allocate set from vector \a s0 (may contain duplicates)
    static IntSetVal* a(const std::vector<IntVal>& s0) {
      if (s0.size()==0)
        return a();
      std::vector<IntVal> s=s0;
      std::sort(s.begin(),s.end());
      std::vector<Range> ranges;
      IntVal min=s[0];
      IntVal max=min;
      for (unsigned int i=1; i<s.size(); i++) {
        if (s[i]>max+1) {
          ranges.push_back(Range(min,max));
          min=s[i]; max=min;
        } else {
          max=s[i];
        }
      }
      ranges.push_back(Range(min,max));
      IntSetVal* r = static_cast<IntSetVal*>(
          ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }
    static IntSetVal* a(const std::vector<Range>& ranges) {
      IntSetVal* r = static_cast<IntSetVal*>(ASTChunk::alloc(sizeof(Range)*ranges.size()));
      new (r) IntSetVal(ranges);
      return r;
    }

    /// Check if set contains \a v
    bool contains(const IntVal& v) {
      for (int i=0; i<size(); i++) {
        if (v < min(i))
          return false;
        if (v <= max(i))
          return true;
      }
      return false;
    }

    /// Check if it is equal to \a s
    bool equal(const IntSetVal* s) {
      if (size()!=s->size())
        return false;
      for (int i=0; i<size(); i++)
        if (min(i)!=s->min(i) || max(i)!=s->max(i))
          return false;
      return true;
    }

    /// Mark for garbage collection
    void mark(void) {
      _gc_mark = 1;
    }
  };

  /// Iterator over an IntSetVal
  class IntSetRanges {
    /// The set value
    const IntSetVal* rs;
    /// The current range
    int n;
  public:
    /// Constructor
    IntSetRanges(const IntSetVal* r) : rs(r), n(0) {}
    /// Check if iterator is still valid
    bool operator()(void) const { return n<rs->size(); }
    /// Move to next range
    void operator++(void) { ++n; }
    /// Return minimum of current range
    IntVal min(void) const { return rs->min(n); }
    /// Return maximum of current range
    IntVal max(void) const { return rs->max(n); }
    /// Return width of current range
    IntVal width(void) const { return rs->width(n); }
  };

  template<class Char, class Traits>
  std::basic_ostream<Char,Traits>&
  operator <<(std::basic_ostream<Char,Traits>& os, const IntSetVal& s) {
    for (IntSetRanges isr(&s); isr(); ++isr)
      os << isr.min() << ".." << isr.max() << " ";
    return os;
  }

}

#endif
<|endoftext|>


<commit_before>/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
algorithmic contributors may be used tactual or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <iostream>
#include <memory>
#include <algorithm>

#include "loop-analysis/tiling.hpp"
#include "loop-analysis/tiling-tile-info.hpp"
#include "loop-analysis/nest-analysis.hpp"
#include "mapping/nest.hpp"
#include "mapping/mapping.hpp"
#include "model/level.hpp"
#include "model/arithmetic.hpp"
#include "model/buffer.hpp"
#include "compound-config/compound-config.hpp"
#include "network.hpp"
#include "network-legacy.hpp"
#include "sparse-optimization-info.hpp"

namespace model
{

// mapping between architectural action names and accelergy's ERT name
// this mapping can be moved out as a separate yaml file that can be read in by timeloop to allow more flexibility
// NOTE: the keys in each map MUST MATCH the operation type names in loop-analysis/operation-type.hpp
// FIXME: regarding the note above: cleanup the setup more so that a unified set of names are used

// format {timeloop_action_name: [priority list of ERT action names]}
static std::map <std::string, std::vector<std::string>> arithmeticOperationMappings
  = {{"random_compute", {"mac_random", "mult_random", "mac", "mult"}},
     {"skipped_compute", {"mac_skipped", "mult_skipped", "mac_gated", "mult_gated", "mac", "mult"}},
     {"gated_compute", {"mac_gated", "mult_gated", "mac", "mult"}}
  };

static std::map <std::string, std::vector<std::string>> storageOperationMappings
  = {{"random_read", {"random_read", "read"}},
     {"random_fill", {"random_fill", "write"}},
     {"random_update", {"random_fill", "write"}},
     {"gated_read", {"gated_read", "idle", "read"}},
     {"gated_fill", {"gated_write", "gated_write", "idle", "write"}},
     {"gated_update", {"gated_write", "gated_write", "idle", "write"}},
     {"skipped_read", {"skipped_read", "gated_read", "idle", "read"}},
     {"skipped_fill", {"skipped_fill", "skipped_write", "gated_write", "idle", "write"}},
     {"skipped_update", {"skipped_update", "skipped_write", "gated_write", "idle", "write"}},
     {"random_metadata_read", {"metadata_read", "metadata_idle", "idle"}},
     {"gated_metadata_read", {"gated_metadata_read", "metadata_idle", "metadata_read"}},
     {"skipped_metadata_read", {"skipped_metadata_read", "metadata_idle", "metadata_read"}},
     {"random_metadata_fill", {"metadata_write", "metadata_idle", "idle"}},
     {"gated_metadata_fill", {"gated_metadata_write", "metadata_idle", "metadata_write"}},
     {"skipped_metadata_fill", {"skipped_metadata_write", "metadata_idle", "metadata_write"}},
     {"random_metadata_update", {"metadata_write", "metadata_idle", "idle"}},
     {"gated_metadata_update", {"gated_metadata_write", "metadata_idle", "metadata_write"}},
     {"skipped_metadata_update", {"skipped_metadata_write", "metadata_idle", "metadata_write"}},
     {"decompression_count", {"decompression_count"}},
     {"compression_count", {"compression_count"}}
  };

static std::string bufferClasses[5] = { "DRAM",
                                        "SRAM",
                                        "regfile",
                                        "smartbuffer",
                                        "storage"};

static std::string computeClasses[4] = { "mac",
                                         "intmac",
                                         "fpmac",
                                         "compute" };

// FIXME: derive these from a statically-instantiated list of class names that
// are auto-populated by each Network class at program init time.
static std::string networkClasses[] = { "XY_NoC",
                                        "Legacy",
                                        "ReductionTree",
                                        "SimpleMulticast"};

bool isBufferClass(std::string className);
bool isComputeClass(std::string className);
bool isNetworkClass(std::string className);

class Topology : public Module
{
 public:

  //
  // Specs.
  //
  class Specs
  {
   private:
    std::vector<std::shared_ptr<LevelSpecs>> levels;
    std::vector<std::shared_ptr<LegacyNetwork::Specs>> inferred_networks;
    std::vector<std::shared_ptr<NetworkSpecs>> networks;
    std::map<unsigned, unsigned> storage_map;
    unsigned arithmetic_map;

   public:
    // Constructors and assignment operators.
    Specs() = default;
    ~Specs() = default;

    // We need an explicit deep-copy constructor because of shared_ptrs.
    Specs(const Specs& other)
    {
      for (auto& level_p: other.levels)
        levels.push_back(level_p->Clone());

      for (auto& inferred_network_p: other.inferred_networks)
        inferred_networks.push_back(std::make_shared<LegacyNetwork::Specs>(*inferred_network_p));

      for (auto& network_p: other.networks)
        networks.push_back(network_p->Clone());

      storage_map = other.storage_map;
      arithmetic_map = other.arithmetic_map;
    }

    // Copy-and-swap idiom.
    friend void swap(Specs& first, Specs& second)
    {
      using std::swap;
      swap(first.levels, second.levels);
      swap(first.inferred_networks, second.inferred_networks);
      swap(first.networks, second.networks);
      swap(first.storage_map, second.storage_map);
      swap(first.arithmetic_map, second.arithmetic_map);
    }

    Specs& operator = (Specs other)
    {
      swap(*this, other);
      return *this;
    }

    unsigned NumLevels() const;
    unsigned NumStorageLevels() const;
    unsigned NumNetworks() const;

    std::vector<std::string> LevelNames() const;
    std::vector<std::string> StorageLevelNames() const;

    void ParseAccelergyERT(config::CompoundConfigNode ert);
    void ParseAccelergyART(config::CompoundConfigNode art);

    void AddLevel(unsigned typed_id, std::shared_ptr<LevelSpecs> level_specs);
    void AddInferredNetwork(std::shared_ptr<LegacyNetwork::Specs> specs);
    void AddNetwork(std::shared_ptr<NetworkSpecs> specs);

    unsigned StorageMap(unsigned i) const { return storage_map.at(i); }
    unsigned ArithmeticMap() const { return arithmetic_map; }

    std::shared_ptr<LevelSpecs> GetLevel(unsigned level_id) const;
    std::shared_ptr<BufferLevel::Specs> GetStorageLevel(unsigned storage_level_id) const;
    std::shared_ptr<ArithmeticUnits::Specs> GetArithmeticLevel() const;
    std::shared_ptr<LegacyNetwork::Specs> GetInferredNetwork(unsigned network_id) const;
    std::shared_ptr<NetworkSpecs> GetNetwork(unsigned network_id) const;
  };

  //
  // Stats.
  //
  struct Stats
  {
    double energy;
    double area;
    std::uint64_t cycles;
    double utilization;
    std::vector<problem::PerDataSpace<std::uint64_t>> tile_sizes;
    std::vector<problem::PerDataSpace<std::uint64_t>> utilized_capacities;
    std::vector<problem::PerDataSpace<std::uint64_t>> utilized_instances;
    std::uint64_t algorithmic_computes;
    std::uint64_t actual_computes;
    std::uint64_t last_level_accesses;
  };

 private:
  std::vector<std::shared_ptr<Level>> levels_;
  std::map<std::string, std::shared_ptr<Network>> networks_;

  // Maps to store the binding relationship between architectural tiling level
  // to actual micro-architecture. The key here is a temporal/spatial tiling
  // level id, and the value is the pointer to the actual micro-architecture
  // (buffer/network) for the tiling level. We might deprecate the above two
  // members in the future.

  // Level map
  std::map<unsigned, std::shared_ptr<Level>> level_map_;
  // Network map. The pair of network connecting two storage levels should
  // share the same spatial tiling id. Note that these read_fill network and
  // drain_update_network can be the same network.
  struct Connection
  {
    std::shared_ptr<Network> read_fill_network;
    std::shared_ptr<Network> drain_update_network;
  };
  std::map<unsigned, Connection> connection_map_;

  std::map<unsigned, double> tile_area_;

  Specs specs_;
  Stats stats_;

  // Serialization
  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version = 0)
  {
    if (version == 0)
    {
      ar& BOOST_SERIALIZATION_NVP(levels_);
      ar& BOOST_SERIALIZATION_NVP(networks_);
    }
  }

 private:
  std::shared_ptr<Level> GetLevel(unsigned level_id) const;
  std::shared_ptr<BufferLevel> GetStorageLevel(unsigned storage_level_id) const;
  std::shared_ptr<ArithmeticUnits> GetArithmeticLevel() const;
  void FloorPlan();
  void ComputeStats(bool eval_success);

 public:

  // Constructors and assignment operators.
  Topology() = default;
  ~Topology() = default;

  // We need an explicit deep-copy constructor because of shared_ptrs.
  Topology(const Topology& other)
  {
    is_specced_ = other.is_specced_;
    is_evaluated_ = other.is_evaluated_;

    for (auto& level_p: other.levels_)
      levels_.push_back(level_p->Clone());

    for (auto& network_kv: other.networks_)
      networks_[network_kv.first] = network_kv.second->Clone();

    tile_area_ = other.tile_area_;
    specs_ = other.specs_;
    stats_ = other.stats_;
  }

  // Copy-and-swap idiom.
  friend void swap(Topology& first, Topology& second)
  {
    using std::swap;
    swap(first.is_specced_, second.is_specced_);
    swap(first.is_evaluated_, second.is_evaluated_);
    swap(first.levels_, second.levels_);
    swap(first.networks_, second.networks_);
    swap(first.tile_area_, second.tile_area_);
    swap(first.specs_, second.specs_);
    swap(first.stats_, second.stats_);
  }

  Topology& operator = (Topology other)
  {
    swap(*this, other);
    return *this;
  }

  // The hierarchical ParseSpecs functions are static and do not
  // affect the internal specs_ data structure, which is set by
  // the dynamic Spec() call later.
  static Specs ParseSpecs(config::CompoundConfigNode setting, config::CompoundConfigNode arithmetic_specs, bool is_sparse_topology);
  static Specs ParseTreeSpecs(config::CompoundConfigNode designRoot, bool is_sparse_topology);

  void Spec(const Specs& specs);
  void Reset();
  unsigned NumLevels() const;
  unsigned NumStorageLevels() const;
  unsigned NumNetworks() const;

  std::vector<EvalStatus> PreEvaluationCheck(const Mapping& mapping, analysis::NestAnalysis* analysis, sparse::SparseOptimizationInfo* sparse_optimizations, bool break_on_failure);
  std::vector<EvalStatus> Evaluate(Mapping& mapping, analysis::NestAnalysis* analysis, sparse::SparseOptimizationInfo* sparse_optimizations, bool break_on_failure);

  const Stats& GetStats() const { return stats_; }
  const Specs& GetSpecs() const {return specs_;}

  // FIXME: these stat-specific accessors are deprecated and only exist for
  // backwards-compatibility with some applications.
  double Energy() const { return stats_.energy; }
  double Area() const { return stats_.area; }
  std::uint64_t Cycles() const { return stats_.cycles; }
  double Utilization() const { return stats_.utilization; }
  std::vector<problem::PerDataSpace<std::uint64_t>> TileSizes() const { return stats_.tile_sizes; }
  std::vector<problem::PerDataSpace<std::uint64_t>> UtilizedCapacities() const { return stats_.utilized_capacities; }
  std::vector<problem::PerDataSpace<std::uint64_t>> UtilizedInstances() const { return stats_.utilized_instances; }
  std::uint64_t AlgorithmicComputes() const { return stats_.algorithmic_computes; }
  std::uint64_t ActualComputes() const { return stats_.actual_computes; }
  std::uint64_t LastLevelAccesses() const { return stats_.last_level_accesses; }

  friend std::ostream& operator<<(std::ostream& out, const Topology& sh);
};

}  // namespace model
<commit_msg>add compute as an arithmetic action name<commit_after>/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
algorithmic contributors may be used tactual or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <iostream>
#include <memory>
#include <algorithm>

#include "loop-analysis/tiling.hpp"
#include "loop-analysis/tiling-tile-info.hpp"
#include "loop-analysis/nest-analysis.hpp"
#include "mapping/nest.hpp"
#include "mapping/mapping.hpp"
#include "model/level.hpp"
#include "model/arithmetic.hpp"
#include "model/buffer.hpp"
#include "compound-config/compound-config.hpp"
#include "network.hpp"
#include "network-legacy.hpp"
#include "sparse-optimization-info.hpp"

namespace model
{

// mapping between architectural action names and accelergy's ERT name
// this mapping can be moved out as a separate yaml file that can be read in by timeloop to allow more flexibility
// NOTE: the keys in each map MUST MATCH the operation type names in loop-analysis/operation-type.hpp
// FIXME: regarding the note above: cleanup the setup more so that a unified set of names are used

// format {timeloop_action_name: [priority list of ERT action names]}
static std::map <std::string, std::vector<std::string>> arithmeticOperationMappings
  = {{"random_compute", {"mac_random", "mult_random", "mac", "mult", "compute"}},
     {"skipped_compute", {"mac_skipped", "mult_skipped","compute_skipped", "mac_gated", "mult_gated", "compute_gated", "mac", "mult", "compute"}},
     {"gated_compute", {"mac_gated", "mult_gated", "compute_gated", "mac", "mult", "compute"}}
  };

static std::map <std::string, std::vector<std::string>> storageOperationMappings
  = {{"random_read", {"random_read", "read"}},
     {"random_fill", {"random_fill", "write"}},
     {"random_update", {"random_fill", "write"}},
     {"gated_read", {"gated_read", "idle", "read"}},
     {"gated_fill", {"gated_write", "gated_write", "idle", "write"}},
     {"gated_update", {"gated_write", "gated_write", "idle", "write"}},
     {"skipped_read", {"skipped_read", "gated_read", "idle", "read"}},
     {"skipped_fill", {"skipped_fill", "skipped_write", "gated_write", "idle", "write"}},
     {"skipped_update", {"skipped_update", "skipped_write", "gated_write", "idle", "write"}},
     {"random_metadata_read", {"metadata_read", "metadata_idle", "idle"}},
     {"gated_metadata_read", {"gated_metadata_read", "metadata_idle", "metadata_read"}},
     {"skipped_metadata_read", {"skipped_metadata_read", "metadata_idle", "metadata_read"}},
     {"random_metadata_fill", {"metadata_write", "metadata_idle", "idle"}},
     {"gated_metadata_fill", {"gated_metadata_write", "metadata_idle", "metadata_write"}},
     {"skipped_metadata_fill", {"skipped_metadata_write", "metadata_idle", "metadata_write"}},
     {"random_metadata_update", {"metadata_write", "metadata_idle", "idle"}},
     {"gated_metadata_update", {"gated_metadata_write", "metadata_idle", "metadata_write"}},
     {"skipped_metadata_update", {"skipped_metadata_write", "metadata_idle", "metadata_write"}},
     {"decompression_count", {"decompression_count"}},
     {"compression_count", {"compression_count"}}
  };

static std::string bufferClasses[5] = { "DRAM",
                                        "SRAM",
                                        "regfile",
                                        "smartbuffer",
                                        "storage"};

static std::string computeClasses[4] = { "mac",
                                         "intmac",
                                         "fpmac",
                                         "compute" };

// FIXME: derive these from a statically-instantiated list of class names that
// are auto-populated by each Network class at program init time.
static std::string networkClasses[] = { "XY_NoC",
                                        "Legacy",
                                        "ReductionTree",
                                        "SimpleMulticast"};

bool isBufferClass(std::string className);
bool isComputeClass(std::string className);
bool isNetworkClass(std::string className);

class Topology : public Module
{
 public:

  //
  // Specs.
  //
  class Specs
  {
   private:
    std::vector<std::shared_ptr<LevelSpecs>> levels;
    std::vector<std::shared_ptr<LegacyNetwork::Specs>> inferred_networks;
    std::vector<std::shared_ptr<NetworkSpecs>> networks;
    std::map<unsigned, unsigned> storage_map;
    unsigned arithmetic_map;

   public:
    // Constructors and assignment operators.
    Specs() = default;
    ~Specs() = default;

    // We need an explicit deep-copy constructor because of shared_ptrs.
    Specs(const Specs& other)
    {
      for (auto& level_p: other.levels)
        levels.push_back(level_p->Clone());

      for (auto& inferred_network_p: other.inferred_networks)
        inferred_networks.push_back(std::make_shared<LegacyNetwork::Specs>(*inferred_network_p));

      for (auto& network_p: other.networks)
        networks.push_back(network_p->Clone());

      storage_map = other.storage_map;
      arithmetic_map = other.arithmetic_map;
    }

    // Copy-and-swap idiom.
    friend void swap(Specs& first, Specs& second)
    {
      using std::swap;
      swap(first.levels, second.levels);
      swap(first.inferred_networks, second.inferred_networks);
      swap(first.networks, second.networks);
      swap(first.storage_map, second.storage_map);
      swap(first.arithmetic_map, second.arithmetic_map);
    }

    Specs& operator = (Specs other)
    {
      swap(*this, other);
      return *this;
    }

    unsigned NumLevels() const;
    unsigned NumStorageLevels() const;
    unsigned NumNetworks() const;

    std::vector<std::string> LevelNames() const;
    std::vector<std::string> StorageLevelNames() const;

    void ParseAccelergyERT(config::CompoundConfigNode ert);
    void ParseAccelergyART(config::CompoundConfigNode art);

    void AddLevel(unsigned typed_id, std::shared_ptr<LevelSpecs> level_specs);
    void AddInferredNetwork(std::shared_ptr<LegacyNetwork::Specs> specs);
    void AddNetwork(std::shared_ptr<NetworkSpecs> specs);

    unsigned StorageMap(unsigned i) const { return storage_map.at(i); }
    unsigned ArithmeticMap() const { return arithmetic_map; }

    std::shared_ptr<LevelSpecs> GetLevel(unsigned level_id) const;
    std::shared_ptr<BufferLevel::Specs> GetStorageLevel(unsigned storage_level_id) const;
    std::shared_ptr<ArithmeticUnits::Specs> GetArithmeticLevel() const;
    std::shared_ptr<LegacyNetwork::Specs> GetInferredNetwork(unsigned network_id) const;
    std::shared_ptr<NetworkSpecs> GetNetwork(unsigned network_id) const;
  };

  //
  // Stats.
  //
  struct Stats
  {
    double energy;
    double area;
    std::uint64_t cycles;
    double utilization;
    std::vector<problem::PerDataSpace<std::uint64_t>> tile_sizes;
    std::vector<problem::PerDataSpace<std::uint64_t>> utilized_capacities;
    std::vector<problem::PerDataSpace<std::uint64_t>> utilized_instances;
    std::uint64_t algorithmic_computes;
    std::uint64_t actual_computes;
    std::uint64_t last_level_accesses;
  };

 private:
  std::vector<std::shared_ptr<Level>> levels_;
  std::map<std::string, std::shared_ptr<Network>> networks_;

  // Maps to store the binding relationship between architectural tiling level
  // to actual micro-architecture. The key here is a temporal/spatial tiling
  // level id, and the value is the pointer to the actual micro-architecture
  // (buffer/network) for the tiling level. We might deprecate the above two
  // members in the future.

  // Level map
  std::map<unsigned, std::shared_ptr<Level>> level_map_;
  // Network map. The pair of network connecting two storage levels should
  // share the same spatial tiling id. Note that these read_fill network and
  // drain_update_network can be the same network.
  struct Connection
  {
    std::shared_ptr<Network> read_fill_network;
    std::shared_ptr<Network> drain_update_network;
  };
  std::map<unsigned, Connection> connection_map_;

  std::map<unsigned, double> tile_area_;

  Specs specs_;
  Stats stats_;

  // Serialization
  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive& ar, const unsigned int version = 0)
  {
    if (version == 0)
    {
      ar& BOOST_SERIALIZATION_NVP(levels_);
      ar& BOOST_SERIALIZATION_NVP(networks_);
    }
  }

 private:
  std::shared_ptr<Level> GetLevel(unsigned level_id) const;
  std::shared_ptr<BufferLevel> GetStorageLevel(unsigned storage_level_id) const;
  std::shared_ptr<ArithmeticUnits> GetArithmeticLevel() const;
  void FloorPlan();
  void ComputeStats(bool eval_success);

 public:

  // Constructors and assignment operators.
  Topology() = default;
  ~Topology() = default;

  // We need an explicit deep-copy constructor because of shared_ptrs.
  Topology(const Topology& other)
  {
    is_specced_ = other.is_specced_;
    is_evaluated_ = other.is_evaluated_;

    for (auto& level_p: other.levels_)
      levels_.push_back(level_p->Clone());

    for (auto& network_kv: other.networks_)
      networks_[network_kv.first] = network_kv.second->Clone();

    tile_area_ = other.tile_area_;
    specs_ = other.specs_;
    stats_ = other.stats_;
  }

  // Copy-and-swap idiom.
  friend void swap(Topology& first, Topology& second)
  {
    using std::swap;
    swap(first.is_specced_, second.is_specced_);
    swap(first.is_evaluated_, second.is_evaluated_);
    swap(first.levels_, second.levels_);
    swap(first.networks_, second.networks_);
    swap(first.tile_area_, second.tile_area_);
    swap(first.specs_, second.specs_);
    swap(first.stats_, second.stats_);
  }

  Topology& operator = (Topology other)
  {
    swap(*this, other);
    return *this;
  }

  // The hierarchical ParseSpecs functions are static and do not
  // affect the internal specs_ data structure, which is set by
  // the dynamic Spec() call later.
  static Specs ParseSpecs(config::CompoundConfigNode setting, config::CompoundConfigNode arithmetic_specs, bool is_sparse_topology);
  static Specs ParseTreeSpecs(config::CompoundConfigNode designRoot, bool is_sparse_topology);

  void Spec(const Specs& specs);
  void Reset();
  unsigned NumLevels() const;
  unsigned NumStorageLevels() const;
  unsigned NumNetworks() const;

  std::vector<EvalStatus> PreEvaluationCheck(const Mapping& mapping, analysis::NestAnalysis* analysis, sparse::SparseOptimizationInfo* sparse_optimizations, bool break_on_failure);
  std::vector<EvalStatus> Evaluate(Mapping& mapping, analysis::NestAnalysis* analysis, sparse::SparseOptimizationInfo* sparse_optimizations, bool break_on_failure);

  const Stats& GetStats() const { return stats_; }
  const Specs& GetSpecs() const {return specs_;}

  // FIXME: these stat-specific accessors are deprecated and only exist for
  // backwards-compatibility with some applications.
  double Energy() const { return stats_.energy; }
  double Area() const { return stats_.area; }
  std::uint64_t Cycles() const { return stats_.cycles; }
  double Utilization() const { return stats_.utilization; }
  std::vector<problem::PerDataSpace<std::uint64_t>> TileSizes() const { return stats_.tile_sizes; }
  std::vector<problem::PerDataSpace<std::uint64_t>> UtilizedCapacities() const { return stats_.utilized_capacities; }
  std::vector<problem::PerDataSpace<std::uint64_t>> UtilizedInstances() const { return stats_.utilized_instances; }
  std::uint64_t AlgorithmicComputes() const { return stats_.algorithmic_computes; }
  std::uint64_t ActualComputes() const { return stats_.actual_computes; }
  std::uint64_t LastLevelAccesses() const { return stats_.last_level_accesses; }

  friend std::ostream& operator<<(std::ostream& out, const Topology& sh);
};

}  // namespace model
<|endoftext|>


<commit_before>#pragma once
#include "ilayer.hpp"
#include <stdlib.h>

namespace Convolutional::Layer {

class FullyConnectedNeuralNetwork : public ILayer {
public:
	using ILayer::ILayer;

	class Neuron;

	class Connection {
	public:
		Neuron& from;
		Neuron& to;

		double weight = ((double) rand() / RAND_MAX * 2) - 1;

		Connection(Neuron& from, Neuron& to) : from(from), to(to) { };
	};

	class Neuron {
	public:
		Matrix::element_t lastActionPotential = 0;
		std::vector<Connection> connections;

		Neuron(std::size_t nConnections = 0) { connections.reserve(nConnections); };

		auto AddConnection(Connection& connection) -> void {
			connections.push_back(connection);
		}
	};

	class BiasNeuron: public Neuron {
	public:
		BiasNeuron() { lastActionPotential = 1.0; };
	};

	std::size_t nOutputs;
	std::vector<Neuron> inputNeurons;
	std::vector<Neuron> outputNeurons;

	FullyConnectedNeuralNetwork(std::size_t outputCount): nOutputs(outputCount), outputNeurons(outputCount, Neuron()) { };
	FullyConnectedNeuralNetwork(const FullyConnectedNeuralNetwork&) = default;
	FullyConnectedNeuralNetwork(FullyConnectedNeuralNetwork&&) = default;

	auto ProcessMultiMatrix(const MultiMatrix& multiMatrix) -> MultiMatrix override;
	auto GetReceptiveField(Matrix::Size size) const noexcept -> Matrix::Size override { return {1, 1}; }
	auto GetZeroPadding(Matrix::Size size) const noexcept -> Matrix::Size override { return {0, 0}; }
	auto GetStride(Matrix::Size size) const noexcept -> Matrix::Size override { return {1, 1}; }

	auto Clone() const noexcept -> std::unique_ptr<ILayer> override { return std::make_unique<FullyConnectedNeuralNetwork>(*this); }
};

}
<commit_msg>Cleanup ctors<commit_after>#pragma once
#include "ilayer.hpp"
#include <stdlib.h>

namespace Convolutional::Layer {

class FullyConnectedNeuralNetwork : public ILayer {
public:
	using ILayer::ILayer;

	class Neuron;

	class Connection {
	public:
		Neuron& from;
		Neuron& to;

		double weight = ((double) rand() / RAND_MAX * 2) - 1;

		Connection(Neuron& from, Neuron& to) : from(from), to(to) { };
	};

	class Neuron {
	public:
		Matrix::element_t lastActionPotential = 0;
		std::vector<Connection> connections;

		Neuron() = default;
		Neuron(std::size_t nConnections) { connections.reserve(nConnections); };

		auto AddConnection(Connection& connection) -> void {
			connections.push_back(connection);
		}
	};

	class BiasNeuron: public Neuron {
	public:
		BiasNeuron() { lastActionPotential = 1.0; };
	};

	std::size_t nOutputs;
	std::vector<Neuron> inputNeurons;
	std::vector<Neuron> outputNeurons;

	FullyConnectedNeuralNetwork(std::size_t outputCount): nOutputs(outputCount), outputNeurons(outputCount, Neuron()) { };
	FullyConnectedNeuralNetwork(const FullyConnectedNeuralNetwork&) = default;
	FullyConnectedNeuralNetwork(FullyConnectedNeuralNetwork&&) = default;

	auto ProcessMultiMatrix(const MultiMatrix& multiMatrix) -> MultiMatrix override;
	auto GetReceptiveField(Matrix::Size size) const noexcept -> Matrix::Size override { return {1, 1}; }
	auto GetZeroPadding(Matrix::Size size) const noexcept -> Matrix::Size override { return {0, 0}; }
	auto GetStride(Matrix::Size size) const noexcept -> Matrix::Size override { return {1, 1}; }

	auto Clone() const noexcept -> std::unique_ptr<ILayer> override { return std::make_unique<FullyConnectedNeuralNetwork>(*this); }
};

}
<|endoftext|>