<commit_before>#include <cassert>
#include <chrono>
#include <iostream>
#include <memory>
#include <set>
#include <thread>

#include <boost/dynamic_bitset.hpp>

#include <sdd/sdd.hh>
#include <sdd/tools/size.hh>

#include "mc/classic/bounded_post.hh"
#include "mc/classic/count_tokens.hh"
#include "mc/classic/dead.hh"
#include "mc/classic/dump.hh"
#include "mc/classic/exceptions.hh"
#include "mc/classic/inhibitor.hh"
#include "mc/classic/interruptible.hh"
#include "mc/classic/live.hh"
#include "mc/classic/make_order.hh"
#include "mc/classic/post.hh"
#include "mc/classic/pre.hh"
#include "mc/classic/results.hh"
#include "mc/classic/statistics.hh"
#include "mc/classic/worker.hh"
#include "util/timer.hh"

namespace pnmc { namespace mc { namespace classic {

namespace chrono = std::chrono;

using sdd_conf = sdd::conf1 ;
using SDD = sdd::SDD<sdd_conf>;
using homomorphism = sdd::homomorphism<sdd_conf>;

using sdd::composition;
using sdd::fixpoint;
using sdd::intersection;
using sdd::sum;
using sdd::function;

/*------------------------------------------------------------------------------------------------*/

SDD
initial_state(const sdd::order<sdd_conf>& order, const pn::net& net)
{
  return SDD(order, [&](const std::string& id)
                        -> sdd::values::flat_set<unsigned int>
                       {
                         assert(net.places_by_id().find(id) != net.places_by_id().end());
                         return {net.places_by_id().find(id)->marking};
                       });
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Create a timed function if required by the configuration, a normal function otherwise.
template <typename Fun, typename... Args>
homomorphism
mk_fun( const conf::configuration& conf, const bool& stop, const sdd::order<sdd_conf>& o
      , const sdd_conf::Identifier& id, Args&&... args)
{
  if (conf.max_time > chrono::duration<double>(0))
  {
    return function(o, id, interruptible<sdd_conf, Fun>(stop, std::forward<Args>(args)...));
  }
  else
  {
    return function(o, id, Fun(std::forward<Args>(args)...));;
  }
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Compute the transition relation corresponding to a petri net.
homomorphism
transition_relation( const conf::configuration& conf, const sdd::order<sdd_conf>& o
                   , const pn::net& net, boost::dynamic_bitset<>& transitions_bitset
                   , statistics& stats, const bool& stop)
{
  util::timer timer;

  std::set<homomorphism> operands;
  operands.insert(sdd::id<sdd_conf>());

  for (const auto& transition : net.transitions())
  {
    if (transition.pre.empty() and transition.post.empty())
    {
      continue; // A transition with no pre or post places, no need to keep it.
    }

    homomorphism h_t = sdd::id<sdd_conf>();

    // Post actions.
    for (const auto& arc : transition.post)
    {
      // Is the maximal marking limited?
      homomorphism f = conf.marking_bound == 0
                     ? mk_fun<post>(conf, stop, o, arc.first, arc.second.weight)
                     : mk_fun<bounded_post<sdd_conf>>( conf, stop, o, arc.first, arc.second.weight
                                                     , conf.marking_bound, arc.first);
      h_t = composition(h_t, sdd::carrier(o, arc.first, f));
    }

    // Add a "canary" to detect live transitions. It will be triggered if all pre are fired.
    if (conf.compute_dead_transitions)
    {
      // Target the same variable as the last pre or post to be fired to avoid evaluations.
      const auto var = transition.pre.empty()
                     ? std::prev(transition.post.cend())->first
                     : transition.pre.cbegin()->first;

      const auto f = mk_fun<live>(conf, stop, o, var, transition.index, transitions_bitset);
      h_t = composition(h_t, sdd::carrier(o, var, f));
    }

    // Pre actions.
    for (const auto& arc : transition.pre)
    {
      const homomorphism f = [&]{
        switch (arc.second.kind)
        {
          case pn::arc::type::normal:
            return mk_fun<pre>(conf, stop, o, arc.first, arc.second.weight);

          case pn::arc::type::inhibitor:
            return mk_fun<inhibitor>(conf, stop, o, arc.first, arc.second.weight);

          default:
            throw std::runtime_error("Unsupported arc type.");
        }
      }();
      h_t = composition(h_t, sdd::carrier(o, arc.first, f));
    }

    operands.insert(h_t);
  }
  stats.relation_duration = timer.duration();
  return fixpoint(sum(o, operands.cbegin(), operands.cend()));
}

/*------------------------------------------------------------------------------------------------*/

homomorphism
rewrite( const conf::configuration&, const sdd::order<sdd_conf>& o
       , const homomorphism& h, statistics& stats)
{
  util::timer timer;
  const auto res = sdd::rewrite(o, h);
  stats.rewrite_duration = timer.duration();
  return res;
}<commit_msg>Reorder pre and post arcs using the order of variables.<commit_after>#include <algorithm> // sort, transform
#include <cassert>
#include <chrono>
#include <iostream>
#include <memory>
#include <set>
#include <thread>

#include <boost/dynamic_bitset.hpp>

#include <sdd/sdd.hh>
#include <sdd/tools/size.hh>

#include "mc/classic/bounded_post.hh"
#include "mc/classic/count_tokens.hh"
#include "mc/classic/dead.hh"
#include "mc/classic/dump.hh"
#include "mc/classic/exceptions.hh"
#include "mc/classic/inhibitor.hh"
#include "mc/classic/interruptible.hh"
#include "mc/classic/live.hh"
#include "mc/classic/make_order.hh"
#include "mc/classic/post.hh"
#include "mc/classic/pre.hh"
#include "mc/classic/results.hh"
#include "mc/classic/statistics.hh"
#include "mc/classic/worker.hh"
#include "util/timer.hh"

namespace pnmc { namespace mc { namespace classic {

namespace chrono = std::chrono;

using sdd_conf = sdd::conf1 ;
using SDD = sdd::SDD<sdd_conf>;
using homomorphism = sdd::homomorphism<sdd_conf>;

using sdd::composition;
using sdd::fixpoint;
using sdd::intersection;
using sdd::sum;
using sdd::function;

/*------------------------------------------------------------------------------------------------*/

SDD
initial_state(const sdd::order<sdd_conf>& order, const pn::net& net)
{
  return SDD(order, [&](const std::string& id)
                        -> sdd::values::flat_set<unsigned int>
                       {
                         assert(net.places_by_id().find(id) != net.places_by_id().end());
                         return {net.places_by_id().find(id)->marking};
                       });
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Create a timed function if required by the configuration, a normal function otherwise.
template <typename Fun, typename... Args>
homomorphism
mk_fun( const conf::configuration& conf, const bool& stop, const sdd::order<sdd_conf>& o
      , const sdd_conf::Identifier& id, Args&&... args)
{
  if (conf.max_time > chrono::duration<double>(0))
  {
    return function(o, id, interruptible<sdd_conf, Fun>(stop, std::forward<Args>(args)...));
  }
  else
  {
    return function(o, id, Fun(std::forward<Args>(args)...));;
  }
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Compute the transition relation corresponding to a petri net.
homomorphism
transition_relation( const conf::configuration& conf, const sdd::order<sdd_conf>& o
                   , const pn::net& net, boost::dynamic_bitset<>& transitions_bitset
                   , statistics& stats, const bool& stop)
{
  util::timer timer;

  std::set<homomorphism> operands;
  operands.insert(sdd::id<sdd_conf>());

  // Temporary storage to sort post and pre arcs.
  std::vector<const std::pair<const std::string, pn::arc>*> arcs_tmp;
  arcs_tmp.reserve(128);

  for (const auto& transition : net.transitions())
  {
    if (transition.pre.empty() and transition.post.empty())
    {
      continue; // A transition with no pre or post places, no need to keep it.
    }

    homomorphism h_t = sdd::id<sdd_conf>();

    // Sort post arcs using the variable order.
    arcs_tmp.clear();
    std::transform( transition.post.cbegin(), transition.post.cend()
                  , std::back_inserter(arcs_tmp)
                  , [](const std::pair<const std::string, pn::arc>& p){return &p;});
    std::sort( arcs_tmp.begin(), arcs_tmp.end()
             , [&]( const std::pair<const std::string, pn::arc>* lhs
                  , const std::pair<const std::string, pn::arc>* rhs)
                  {
//                    return o.node(lhs->first) < o.node(rhs->first);
                    return o.node(rhs->first) < o.node(lhs->first);
                  }
             );

    // Post actions.
    for (const auto& arc : arcs_tmp)
    {
      // Is the maximal marking limited?
      homomorphism f = conf.marking_bound == 0
                     ? mk_fun<post>(conf, stop, o, arc->first, arc->second.weight)
                     : mk_fun<bounded_post<sdd_conf>>( conf, stop, o, arc->first, arc->second.weight
                                                     , conf.marking_bound, arc->first);
      h_t = composition(h_t, sdd::carrier(o, arc->first, f));
    }

    // Add a "canary" to detect live transitions. It will be triggered if all pre are fired.
    if (conf.compute_dead_transitions)
    {
      // Target the same variable as the last pre or post to be fired to avoid evaluations.
      // @todo Target the same variable as the sorted pre or post.
      const auto var = transition.pre.empty()
                     ? std::prev(transition.post.cend())->first
                     : transition.pre.cbegin()->first;

      const auto f = mk_fun<live>(conf, stop, o, var, transition.index, transitions_bitset);
      h_t = composition(h_t, sdd::carrier(o, var, f));
    }

    // Sort pre arcs using the variable order.
    arcs_tmp.clear();
    std::transform( transition.pre.cbegin(), transition.pre.cend()
                  , std::back_inserter(arcs_tmp)
                  , [](const std::pair<const std::string, pn::arc>& p){return &p;});
    std::sort( arcs_tmp.begin(), arcs_tmp.end()
             , [&]( const std::pair<const std::string, pn::arc>* lhs
                  , const std::pair<const std::string, pn::arc>* rhs)
                  {
//                    return o.node(lhs->first) < o.node(rhs->first);
                    return o.node(rhs->first) < o.node(lhs->first);
                  }
             );

    // Pre actions.
    for (const auto& arc : arcs_tmp)
    {
      const homomorphism f = [&]{
        switch (arc->second.kind)
        {
          case pn::arc::type::normal:
            return mk_fun<pre>(conf, stop, o, arc->first, arc->second.weight);

          case pn::arc::type::inhibitor:
            return mk_fun<inhibitor>(conf, stop, o, arc->first, arc->second.weight);

          default:
            throw std::runtime_error("Unsupported arc type.");
        }
      }();
      h_t = composition(h_t, sdd::carrier(o, arc->first, f));
    }

    operands.insert(h_t);
  }
  stats.relation_duration = timer.duration();
  return fixpoint(sum(o, operands.cbegin(), operands.cend()));
}

/*------------------------------------------------------------------------------------------------*/

homomorphism
rewrite( const conf::configuration&, const sdd::order<sdd_conf>& o
       , const homomorphism& h, statistics& stats)
{
  util::timer timer;
  const auto res = sdd::rewrite(o, h);
  stats.rewrite_duration = timer.duration();
  return res;
}
{'fraction_non_alphanumeric': 0.2046252676659529, 'fraction_numerical': 0.0007708779443254819, 'mean_word_length': 2.1685210312075984, 'pattern_counts': {'":': 0, '<': 78, '<?xml version=': 0, '>': 104, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '206154', 'n_tokens_mistral': 3611, 'n_tokens_neox': 3501, 'n_words': 828}