5 #include <boost/range/algorithm/find.hpp> 6 #include <boost/range/algorithm/lower_bound.hpp> 8 #include <vcsn/algos/fwd.hh> 17 #include <vcsn/dyn/fwd.hh> 30 template <
typename Context>
37 "series (currently) requires a commutative weightset product");
41 template <typename Context> \ 43 expressionset_impl<Context> 53 DEFINE::make(std::istream& is)
57 eat(is,
"expressionset<");
58 auto ctx = Context::make(is);
91 o << "expressionset<"; 92 context().print_set(o, fmt); 94 if (identities() != vcsn::rat::identities{}) 95 o << '(
' << identities() << ')
'; 101 context().print_set(o, fmt); 103 if (identities() != vcsn::rat::identities{}) 104 o << '(
' << identities() << ')
'; 107 assert(!"expressionset::print_set: invalid format: rat"); 113 DEFINE::open(bool o) const 116 return this->labelset()->open(o); 119 DEFINE::context() const -> const context_t& 124 DEFINE::identities() const -> identities_t 129 DEFINE::labelset() const -> const labelset_ptr& 131 return ctx_.labelset(); 134 DEFINE::weightset() const -> const weightset_ptr& 136 return ctx_.weightset(); 139 DEFINE::atom(const label_t& v) 142 if (labelset_t::is_one(v)) 145 return std::make_shared<atom_t>(v); 148 DEFINE::name(const value_t& v, symbol name) const 151 return std::make_shared<name_t>(v, name); 157 return std::make_shared<zero_t>(); 163 return std::make_shared<one_t>(); 166 template <typename Context> 167 template <typename expressionset_impl<Context>::type_t Type> 169 expressionset_impl<Context>::gather_(values_t& res, const value_t& v) const 172 auto variadic = std::dynamic_pointer_cast<const variadic_t<Type>>(v); 173 if (variadic && ids_.is_associative()) 174 res.insert(std::end(res), std::begin(*variadic), std::end(*variadic)); 179 template <typename Context> 180 template <typename expressionset_impl<Context>::type_t Type> 182 expressionset_impl<Context>::gather_(const value_t& l, const value_t& r) const 185 auto res = values_t{}; 186 if (ids_.is_associative()) 188 gather_<Type>(res, l); 189 gather_<Type>(res, r); 199 DEFINE::add(const value_t& l, const value_t& r) const 202 auto res = value_t{}; 205 if (ids_.is_trivial() && is_zero(l)) 209 else if (ids_.is_trivial() && is_zero(r)) 213 else if (ids_.is_linear()) 214 res = add_linear_(l, r); 217 res = std::make_shared<add_t>(gather_<type_t::add>(l, r)); 221 DEFINE::add_linear_(const add_t& s, const value_t& r) const 224 auto res = values_t{}; 225 res.reserve(s.size() + 1); 227 // Copy the strictly smaller part. 228 auto i = boost::lower_bound(s, r, less_linear); 229 res.insert(end(res), begin(s), i); 235 if (less_linear(r, *i)) 239 auto w = weightset()->add(possibly_implicit_lweight_(*i), 240 possibly_implicit_lweight_(r)); 241 if (!weightset()->is_zero(w)) 243 auto l = unwrap_possible_lweight_(*i); 244 res.emplace_back(lweight(w, l)); 248 res.insert(end(res), i, end(s)); 251 return add_(std::move(res)); 254 DEFINE::add_(values_t&& vs) const 259 else if (vs.size() == 1) 262 return std::make_shared<add_t>(std::move(vs)); 265 DEFINE::add_linear_(const add_t& s1, const add_t& s2) const 268 auto res = values_t{}; 269 res.reserve(s1.size() + s2.size()); 270 // Merge two increasing lists. Add weights of equal labels. 273 auto i1 = begin(s1), end1 = end(s1); 274 auto i2 = begin(s2), end2 = end(s2); 279 res.insert(res.end(), i2, end2); 284 res.insert(res.end(), i1, end1); 287 else if (less_linear(*i1, *i2)) 288 res.emplace_back(*i1++); 289 else if (less_linear(*i2, *i1)) 290 res.emplace_back(*i2++); 293 auto w = weightset()->add(possibly_implicit_lweight_(*i1), 294 possibly_implicit_lweight_(*i2)); 295 if (!weightset()->is_zero(w)) 297 auto l = unwrap_possible_lweight_(*i1); 298 res.emplace_back(lweight(w, l)); 304 return add_(std::move(res)); 307 DEFINE::add_linear_(const value_t& l, const value_t& r) const 312 auto res = value_t{}; 313 if (auto ls = std::dynamic_pointer_cast<const add_t>(l)) 315 if (auto rs = std::dynamic_pointer_cast<const add_t>(r)) 316 res = add_linear_(*ls, *rs); 318 res = add_linear_(*ls, r); 320 else if (auto rs = std::dynamic_pointer_cast<const add_t>(r)) 321 res = add_linear_(*rs, l); 322 else if (less_linear(l, r)) 323 res = std::make_shared<add_t>(l, r); 324 else if (less_linear(r, l)) 325 res = std::make_shared<add_t>(r, l); 328 auto w = weightset()->add(possibly_implicit_lweight_(l), 329 possibly_implicit_lweight_(r)); 330 res = lweight(w, unwrap_possible_lweight_(l)); 335 DEFINE::type_ignoring_lweight_(const value_t& e) 338 return unwrap_possible_lweight_(e)->type(); 341 DEFINE::possibly_implicit_lweight_(const value_t& e) 344 if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e)) 347 return weightset_t::one(); 350 DEFINE::unwrap_possible_lweight_(const value_t& e) 353 if (auto lw = std::dynamic_pointer_cast<const lweight_t>(e)) 359 DEFINE::mul(const value_t& l, const value_t& r) const 362 auto res = value_t{}; 365 if (ids_.is_trivial() && is_zero(l)) 369 else if (ids_.is_trivial() && is_zero(r)) 372 // U_K: E.(<k>1) ⇒ E<k>, subsuming T: E.1 = E. 373 else if (ids_.is_trivial() && type_ignoring_lweight_(r) == type_t::one) 374 res = rweight(l, possibly_implicit_lweight_(r)); 376 // U_K: (<k>1).E ⇒ <k>E, subsuming T: 1.E = E. 377 else if (ids_.is_trivial() && type_ignoring_lweight_(l) == type_t::one) 378 res = lweight(possibly_implicit_lweight_(l), r); 380 // (<k>E)(<h>F) => <kh>(EF). 381 else if (ids_.is_linear() && weightset()->is_commutative() 382 && (l->type() == type_t::lweight 383 || r->type() == type_t::lweight)) 385 // FIXME: check that it can't shadow the following items.
401 for (
const auto& la: *down_pointer_cast<const add_t>(l))
410 for (
const auto& ra: *down_pointer_cast<const add_t>(
r))
415 res = std::make_shared<mul_t>(gather_<type_t::mul>(l,
r));
443 && context_t::has_one()
454 detail::static_if<are_composable<context_t>()
455 && context_t::has_one()
457 ([
this, &
res](
const auto& ls,
const auto& l,
const auto&
r)
465 constexpr
auto in = 0;
467 const auto& ls0 = ls.template set<out>();
469 auto get_label = [&](
const auto& e,
auto tape)
472 return std::get<decltype(tape){}>
479 auto lout = get_label(l, std::integral_constant<int, out>{});
480 auto lin = get_label(
r, std::integral_constant<int, in>{});
483 res = ls0.is_one(lin) ? rhs :
zero();
486 res = ls0.is_one(lout) ? lhs :
zero();
489 res = (ls0.equal(lout, lin)
492 down_pointer_cast<const atom_t>(lhs)->value(),
500 [](
const auto&,
const auto&,
const auto&)
508 res = std::make_shared<compose_t>(gather_<type_t::compose>(l,
r));
566 res = std::make_shared<conjunction_t>(gather_<type_t::conjunction>(l,
r));
588 res = std::make_shared<ldivide_t>(l,
r);
599 template <
typename Context>
600 template <
typename... Value>
605 auto t = ts.tuple(
v...);
625 {
return rs.is_zero(
r); }),
640 return std::make_shared<tuple_t>(std::forward<Value>(
v)...);
666 std::make_shared<infiltrate_t>(gather_<type_t::infiltrate>(l,
r));
692 res = std::make_shared<shuffle_t>(gather_<type_t::shuffle>(l,
r));
700 DEFINE::power(
const value_t& e,
unsigned n)
const 733 power(lw->sub(), n));
741 for (
unsigned i = 1; i < n; ++i)
748 res = std::make_shared<mul_t>(n, e);
755 for (
unsigned i = 1; i < n; ++i)
791 gather_<type_t::mul>(ls, l);
794 gather_<type_t::mul>(rs,
r);
813 product =
lweight(lw->weight(), product);
817 ls.insert(ls.end(), rs.begin() + 1, rs.end());
820 ls.insert(ls.end(), rs.begin(), rs.end());
824 return std::make_shared<mul_t>(std::move(ls));
843 && std::is_same<weightset_t, b>{})
848 res = std::make_shared<star_t>(e);
881 && std::is_same<weight_t, bool>{})
882 res = down_pointer_cast<const complement_t>(e)->sub();
885 res = std::make_shared<complement_t>(e);
917 res = down_pointer_cast<const transposition_t>(e)->sub();
920 res = std::make_shared<transposition_t>(e);
956 for (
const auto& a: *s)
957 addends.emplace_back(
lweight(w, a));
958 res = std::make_shared<add_t>(std::move(addends));
963 res = std::make_shared<lweight_t>(w, e);
1005 res = std::make_shared<rweight_t>(w, e);
1030 &&
is_zero(down_pointer_cast<const complement_t>(
v)->sub()));
1036 return rat::size<self_t>(
v);
1043 return cmp(lhs, rhs);
1062 return compare(lhs, rhs) == 0;
1081 template <
typename Context>
1082 template <
typename GenSet>
1121 template <
typename Context>
1122 template <
typename Ctx2>
1138 const auto&
res = dynres->template as<self_t>();
1157 template <
typename Context>
1158 template <
typename... Args>
1163 return letter_class_<labelset_t>(std::forward<Args>(args)...,
1164 std::is_same<labelset_t, vcsn::oneset>{});
1167 template <
typename Context>
1168 template <
typename LabelSet_>
1172 typename LabelSet_::letter_t>> ccs,
1174 std::false_type)
const 1179 const auto gens = ls.generators();
1186 for (
const auto& cc: ccs)
1188 auto i = std::find(std::begin(gens), std::end(gens), cc.first);
1189 auto end = std::find(i, std::end(gens), cc.second);
1191 self(),
": invalid letter interval: ",
1195 for (++end; i != end; ++i)
1198 ?
atom(ls.value(*i))
1202 else if (ccs.empty())
1209 std::set<typename LabelSet_::letter_t> accepted;
1210 for (
const auto& cc: ccs)
1212 auto i = std::find(std::begin(gens), std::end(gens), cc.first);
1213 auto end = std::find(i, std::end(gens), cc.second);
1215 "invalid letter interval: ",
1219 for (++end; i != end; ++i)
1220 accepted.emplace(*i);
1223 if (!
has(accepted, c))
1231 "invalid empty letter class");
1235 template <
typename Context>
1236 template <
typename LabelSet_,
typename... Args>
1239 std::true_type)
const Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
static auto less(const value_t &l, const value_t &r) -> bool
Whether l < r.
Print as a parsable type string.
static weight_t possibly_implicit_lweight_(const value_t &e)
The weight of e if it's an lweight, otherwise the weight one().
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
weightset_mixin< detail::r_impl > r
bool is_valid(const Aut &aut)
auto concat_(const value_t &l, const value_t &r, std::true_type) const -> value_t
If labelset is wordset.
std::ostream & print(const Aut &aut, std::ostream &out=std::cout, const std::string &fmt="default")
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
static auto compare(const value_t &l, const value_t &r) -> int
Three-way comparison.
Implementation of labels are letters.
typename weightset_t::value_t weight_t
identities_t identities() const
Accessor to the identities set.
auto add(const value_t &l, const value_t &r) const -> value_t
bool is_trivial() const
Whether trivial identities are on.
auto power(const value_t &e, unsigned n) const -> value_t
Add a power operator: e{n}.
An inner node with multiple children.
char eat(std::istream &is, char c)
Check lookahead character and advance.
const identities_t ids_
The set of rewriting rules to apply.
static auto equal(const value_t &l, const value_t &r) -> bool
Whether l == r.
static type_t type_ignoring_lweight_(const value_t &e)
The type of e, or the type of its child if e is a lweight.
bool is_agressive() const
Whether agressive optimizations are on.
expression read_expression(const context &ctx, identities ids, std::istream &is, const std::string &format="default", const location &loc=location{})
Read an expression from a stream.
Request the set implementation (bool weights).
const context_t & context() const
Accessor to the context.
static auto zero() -> value_t
auto transpose(const value_t &e) const -> value_t
The transposed of this rational expression.
typename node_t::values_t values_t
A list (vector) of expressions.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
auto ldivide(const value_t &l, const value_t &r) const -> value_t
r`.
bool is_distributive() const
Whether distributive identities are on.
const labelset_ptr & labelset() const
Accessor to the labelset.
auto rdivide(const Aut1 &a1, const Aut2 &a2)
Compute the right quotient.
bool is_zero(const value_t &v) const ATTRIBUTE_PURE
Whether v is the \\z.
auto conv(const ValueSet &vs, const std::string &str, Args &&... args) -> decltype(vs.conv(std::declval< std::istream &>(), std::forward< Args >(args)...))
Parse str via vs.conv.
auto lweight(const weight_t &w, const value_t &e) const -> value_t
Left-multiplication by a weight.
auto tuple(Value &&... v) const -> value_t
Build a tuple: e | f | ....
static auto unwrap_possible_lweight_(const value_t &e) -> value_t
If e is an lweight, then its child, otherwise e.
An expressionset can implement several different sets of identities on expressions.
An input/output format for valuesets.
Provide a variadic mul on top of a binary mul(), and one().
Whether two contexts are composable.
printer< ExpSet > make_printer(const ExpSet &rs, std::ostream &out)
bool is_associative() const
Whether associative identities are on.
A functor for three-way comparison between two expressions.
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
auto as_tupleset() const -> std::enable_if_t< Ctx::is_lat, as_tupleset_t< Ctx >>
If we are multitape, ourself as a tupleset.
auto mul(const value_t &l, const value_t &r) const -> value_t
auto letter_class_(const Args &&... chars, std::true_type) const -> value_t
If labelset is oneset.
Whether some of the values evaluate as true.
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
bool is_linear() const
Whether linear identities are on.
auto apply(Fun f, const std::tuple< Args... > &args) -> decltype(apply_impl_(f, args, make_index_sequence< sizeof...(Args)>()))
Unpack a tuple, and pass its content as argument to a funtion.
typename node_t::value_t value_t
An expression (a shared pointer to a tree).
std::string to_string(identities i)
Wrapper around operator<<.
bool is_universal(const value_t &v) const ATTRIBUTE_PURE
Whether v is the 0{c}.
An inner node implementing a weight.
auto conv(const letterset< GenSet > &ls, typename letterset< GenSet >::value_t v) const -> value_t
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
static bool is_one(const value_t &v) ATTRIBUTE_PURE
Whether v is the \\e.
static dyn::context ctx(const driver &d)
Get the context of the driver.
Turn a tuple of expressions that are labels into a multi-tape label.
const weightset_ptr & weightset() const
Accessor to the weightset.
static identities ids(const driver &d)
Get the identities of the driver.
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
auto complement(const value_t &e) const -> value_t
Add a complement operator: e{c}.
auto letter_class(Args &&... chars) const -> value_t
An expression matching one character amongst chars.
static auto atom(const label_t &v) -> value_t
Build a label.
static auto one() -> value_t
auto transposition(const value_t &e) const -> value_t
Add a transposition operator.
auto rweight(const value_t &e, const weight_t &w) const -> value_t
Right-multiplication by a weight.
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
std::enable_if_t< std::is_same< InExpSet, OutExpSet >{}, typename OutExpSet::value_t > copy(const InExpSet &in_rs, const OutExpSet &out_rs, const typename InExpSet::value_t &v)
Copy/convert a rational expression.
#define BUILTIN_UNREACHABLE()
expressionset_impl(const context_t &ctx, identities_t ids={})
Constructor.
int compare(const Lhs &lhs, const Rhs &rhs)
Comparison between lhs and rhs.
#define down_pointer_cast
auto print(const value_t &v, std::ostream &o=std::cout, format fmt={}) const -> std::ostream &
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.