mCRL2
Loading...
Searching...
No Matches
jitty.cpp
Go to the documentation of this file.
1// Author(s): Muck van Weerdenburg, Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9
10#define NAME std::string("rewr_jitty")
11
12#include "mcrl2/data/detail/rewrite/jitty.h"
13#include "mcrl2/data/detail/rewrite/jitty_jittyc.h"
14
15#include <boost/config.hpp>
16
17#include "mcrl2/data/substitutions/mutable_map_substitution.h"
18#include "mcrl2/data/replace.h"
19
20#ifdef MCRL2_DISPLAY_REWRITE_STATISTICS
21#include "mcrl2/data/detail/rewrite_statistics.h"
22#endif
23
24using namespace mcrl2::log;
25using namespace mcrl2::core;
26using namespace mcrl2::core::detail;
27
28
29
30namespace mcrl2::data::detail
31{
32
33// The function below is intended to remove the auxiliary function this_term_is_in_normal_form from a term
34// such that it can for instance be pretty printed.
35
37{
39 {
40 return t;
41 }
42
43 if (is_variable(t))
44 {
45 return t;
46 }
47
49 {
51 return t;
52 }
53
55 {
56 const application& ta=atermpp::down_cast<application>(t);
57 if (ta.head()==this_term_is_in_normal_form())
58 {
59 assert(ta.size()==1);
60 return ta[0];
61 }
62
63 return application(ta.head(), ta.begin(), ta.end(), [&](const data_expression& t){ return remove_normal_form_function(t); });
64 }
65
66
68 {
69 const where_clause& t1=atermpp::down_cast<where_clause>(t);
70 const assignment_expression_list& assignments=t1.declarations();
71 const data_expression& body=t1.body();
72
73 assignment_vector new_assignments;
74 for(const assignment_expression& ae: assignments)
75 {
76 const assignment& assignment_expr = atermpp::down_cast<assignment>(ae);
77 new_assignments.emplace_back(assignment_expr.lhs(), remove_normal_form_function(assignment_expr.rhs()));
78 }
79 return where_clause(remove_normal_form_function(body),assignment_list(new_assignments.begin(),new_assignments.end()));
80 }
81
82 assert(is_abstraction(t));
83
84 const abstraction& t1=atermpp::down_cast<abstraction>(t);
85 const binder_type& binder=t1.binding_operator();
86 const variable_list& bound_variables=t1.variables();
87 const data_expression& body=t1.body();
88
89 return abstraction(binder, bound_variables, remove_normal_form_function(body));
90}
91
93{
94 make_application(t,this_term_is_in_normal_form(),t);
95}
96
98{
99 protected:
102 public:
103 jitty_argument_rewriter(mutable_indexed_substitution<>& sigma, RewriterJitty& r)
104 : m_sigma(sigma), m_r(r)
105 {}
106
107 void operator()(data_expression& result, const data_expression& t)
108 {
109 m_r.rewrite_aux(result, t, m_sigma);
110 }
111};
112
114{
115 protected:
118
119 public:
120 dependencies_rewrite_rule_pair(std::set<std::size_t>& dependencies, const data_equation& eq)
122 {}
123
124 const std::set<std::size_t>& dependencies() const
125 {
126 return m_dependencies;
127 }
128
130 {
131 return m_equation;
132 }
133};
134
135
136
137
138
139void RewriterJitty::make_jitty_strat_sufficiently_larger(const std::size_t i)
140{
141 if (i>=jitty_strat.size())
142 {
143 jitty_strat.resize(i+1);
144 }
145}
146
147void RewriterJitty::rebuild_strategy(const data_specification& data_spec, const mcrl2::data::used_data_equation_selector& equation_selector)
148{
149 jitty_strat.clear();
150 function_symbol_vector function_symbols=data_spec.constructors();
151 function_symbols.insert(function_symbols.end(), data_spec.mappings().begin(), data_spec.mappings().end());
152 for(const function_symbol& f: function_symbols)
153 {
154 if (equation_selector(f))
155 {
156 const std::size_t i=atermpp::detail::index_traits<data::function_symbol, function_symbol_key_type, 2>::index(f);
157 make_jitty_strat_sufficiently_larger(i);
158 std::map< function_symbol, data_equation_list >::const_iterator j=jitty_eqns.find(f);
159 jitty_strat[i] =
160 (j==jitty_eqns.end()
161 ?create_strategy(f,data_equation_list(), data_spec)
162 :create_strategy(f,reverse(j->second), data_spec));
163 }
164 }
165
166}
167
168
170 const data_specification& data_spec,
171 const mcrl2::data::used_data_equation_selector& equation_selector):
172 Rewriter(data_spec,equation_selector),
174 std::string("Rewritten@@term"),
176{
178 for (const data_equation& eq: data_spec.equations())
179 {
180 if (equation_selector(eq))
181 {
182 try
183 {
184 CheckRewriteRule(eq);
185 }
186 catch (std::runtime_error& e)
187 {
188 mCRL2log(warning) << e.what() << std::endl;
189 continue;
190 }
191
192 const function_symbol& lhs_head_index=atermpp::down_cast<function_symbol>(get_nested_head(eq.lhs()));
193
194 data_equation_list n;
195 std::map< function_symbol, data_equation_list >::iterator it = jitty_eqns.find(lhs_head_index);
196 if (it != jitty_eqns.end())
197 {
198 n = it->second;
199 }
200 n.push_front(eq);
201 jitty_eqns[lhs_head_index] = n;
202 }
203 }
204
205 rebuild_strategy(data_spec, equation_selector);
206}
207
208RewriterJitty::~RewriterJitty() = default;
209
210// Find the variables that occur in the lhs and the rhs of the assignments;
211//
213{
214 std::set<variable> variables_in_substitution;
215 for(std::size_t i=0; i<assignments.size; ++i)
216 {
217 std::set<variable> s=find_free_variables(assignments.assignment[i].term);
218 variables_in_substitution.insert(s.begin(),s.end());
219 variables_in_substitution.insert(assignments.assignment[i].var);
220 }
221 return variables_in_substitution;
222}
223
225 data_expression& result,
226 const jitty_assignments_for_a_rewrite_rule& assignments,
227 const data_expression& t,
228 data::enumerator_identifier_generator& generator) // This generator is used for the generation of fresh variable names.
229{
231 {
232 result=t;
233 return;
234 }
236 {
237 // The following is more efficient than a plain assignment, as it avoids a call to thread local variables. Should be removed in due time.
238 result.assign(t, *m_thread_aterm_pool);
239 return;
240 }
241 else if (is_variable(t))
242 {
243 for (std::size_t i=0; i<assignments.size; i++)
244 {
245 if (t==assignments.assignment[i].var)
246 {
247 result.assign(assignments.assignment[i].term, *m_thread_aterm_pool);
248 if (assignments.assignment[i].variable_is_a_normal_form)
249 {
250 // Variables that are in normal form get a tag that they are in normal form.
251 add_normal_form_function(result);
252 return;
253 }
254 return;
255 }
256 }
257 result.assign(t, *m_thread_aterm_pool);
258 return;
259 }
260 else if (is_abstraction(t))
261 {
262 const abstraction& t1=atermpp::down_cast<abstraction>(t);
263 const binder_type& binder=t1.binding_operator();
264 const variable_list& bound_variables=t1.variables();
265 // Check that variables in the left and right hand sides of equations do not clash with bound variables.
266 std::set<variable> variables_in_substitution=bound_variables_in_substitution(assignments);
267
268 variable_vector new_variables;
269 mutable_map_substitution<> sigma;
270 bool sigma_trivial=true;
271 for(const variable& v: bound_variables)
272 {
273 if (variables_in_substitution.count(v)>0)
274 {
275 // Replace v in the list and in the body by a new variable name.
276 const variable fresh_variable(generator(),v.sort());
277 new_variables.push_back(fresh_variable);
278 sigma[v]=fresh_variable;
279 sigma_trivial=false;
280 }
281 else
282 {
283 new_variables.push_back(v);
284 }
285 }
286 subst_values(result,
287 assignments,
288 (sigma_trivial?t1.body():replace_variables(t1.body(),sigma)),
289 generator);
290 result=abstraction(binder,
291 variable_list(new_variables.begin(),new_variables.end()),
292 result);
293 return;
294 }
295 else if (is_where_clause(t))
296 {
297 const where_clause& t1=atermpp::down_cast<where_clause>(t);
298 const assignment_expression_list& local_assignments=t1.declarations();
299 const data_expression& body=t1.body();
300
301 std::set<variable> variables_in_substitution=bound_variables_in_substitution(assignments);
302
303 assignment_vector new_assignments;
304
305 mutable_map_substitution<> sigma;
306 bool sigma_trivial=true;
307
308 for(const assignment_expression& a: local_assignments)
309 {
310 const assignment& assignment_expr = atermpp::down_cast<assignment>(a);
311 const variable& v=assignment_expr.lhs();
312 subst_values(result,assignments,assignment_expr.rhs(),generator);
313 if (variables_in_substitution.count(v)>0)
314 {
315 // Replace variable in the assignment and in the body by a new variable name.
316 const variable fresh_variable(generator(),v.sort());
317 new_assignments.emplace_back(fresh_variable, result);
318 sigma[v]=fresh_variable;
319 sigma_trivial=false;
320 }
321 else
322 {
323 new_assignments.emplace_back(v, result);
324 }
325 }
326 subst_values(result,
327 assignments,
328 (sigma_trivial?body:replace_variables(body,sigma)),
329 generator),
330 result=where_clause(result, assignment_list(new_assignments.begin(),new_assignments.end()));
331 return;
332 }
333 else
334 {
335 const application& t1 = atermpp::down_cast<application>(t);
336 make_application(result,
337 t1.head(),
338 t1.begin(),
339 t1.end(),
340 [&](data_expression& result, const data_expression& t) -> void
341 { subst_values(result,assignments,t,generator); return;});
342 }
343}
344
345// Match term t with the lhs p of an equation.
346static bool match_jitty(
347 const data_expression& t,
348 const data_expression& p,
350 const bool term_context_guarantees_normal_form)
351{
353 {
354 return p==t;
355 }
356 else if (is_function_symbol(p))
357 {
358 return p==t;
359 }
360 else if (is_variable(p))
361 {
362
363 for (std::size_t i=0; i<assignments.size; i++)
364 {
365 if (p==assignments.assignment[i].var)
366 {
367 return t==assignments.assignment[i].term;
368 }
369 }
370
371 new (&assignments.assignment[assignments.size])
372 jitty_variable_assignment_for_a_rewrite_rule(
373 atermpp::down_cast<variable>(p),
374 t,
375 term_context_guarantees_normal_form);
376 assignments.size++;
377 return true;
378 }
379 else
380 {
382 {
383 return false;
384 }
385 // p and t must be applications.
386 assert(term_context_guarantees_normal_form); // If the argument must match an expression it must be a normal form.
387
388 const application& pa=atermpp::down_cast<application>(p);
389 const application& ta=atermpp::down_cast<application>(t);
390 if (pa.size()!=ta.size()) // are p and t applications of the same arity?
391 {
392 return false;
393 }
394
395 if (!match_jitty(ta.head(),
396 pa.head(),assignments,true))
397 {
398 return false;
399 }
400
401 for (std::size_t i=0; i<pa.size(); i++)
402 {
403 if (!match_jitty(ta[i], pa[i],assignments,true))
404 {
405 return false;
406 }
407 }
408
409 return true;
410 }
411}
412
413
414// This function applies the rewrite_cpp_code on a higher order term t with op as head symbol for
415// which the code in rewrite_cpp_code must be applied.
416template <class ITERATOR>
418 data_expression& result,
419 const application& t,
420 const std::function<void(data_expression&, const data_expression&)> rewrite_cpp_code,
421 ITERATOR begin,
422 ITERATOR end,
423 substitution_type& sigma)
424{
425 if (is_function_symbol(t.head()))
426 {
427 data_expression intermediate;
428 make_application(intermediate, t.head(), begin, end);
429 rewrite_cpp_code(result, intermediate);
430 return;
431 }
432
433 const application& ta=atermpp::down_cast<application>(t.head());
434 std::size_t n_args=recursive_number_of_args(ta);
435 apply_cpp_code_to_higher_order_term(result,ta,rewrite_cpp_code,begin,begin+n_args,sigma);
436 const data_expression rewrite_result=result; /* TODO Optimize */
437 rewrite_aux(result,application(rewrite_result,
438 begin+n_args,
439 end,
440 [&](const data_expression& t){ return application(this_term_is_in_normal_form(),t); } ),
441 sigma);
442}
443
444
445/// \brief Rewrite a term with a given substitution and put the rewritten term in result.
447 data_expression& result,
448 const data_expression& term,
449 substitution_type& sigma)
450{
451 if (is_function_symbol(term))
452 {
453 assert(term!=this_term_is_in_normal_form());
454 rewrite_aux_const_function_symbol(result,atermpp::down_cast<const function_symbol>(term),sigma);
455 return;
456 }
457 if (is_variable(term))
458 {
459 sigma.apply(atermpp::down_cast<variable>(term),result, *m_thread_aterm_pool);
460 return;
461 }
462 if (is_machine_number(term))
463 {
464 result=term;
465 return;
466 }
467
468 if (is_where_clause(term))
469 {
470 const where_clause& w = atermpp::down_cast<where_clause>(term);
471 rewrite_where(result,w,sigma);
472 return;
473 }
474
475 if (is_abstraction(term))
476 {
477 const abstraction& ta=atermpp::down_cast<abstraction>(term);
478 if (is_exists(ta))
479 {
480 existential_quantifier_enumeration(result,ta,sigma);
481 return;
482 }
483 if (is_forall(ta))
484 {
485 universal_quantifier_enumeration(result,ta,sigma);
486 return;
487 }
488 assert(is_lambda(ta));
489 rewrite_single_lambda(result,ta.variables(),ta.body(), sigma, false);
490 return;
491 }
492
493 // Here term must have the shape appl(t1,...,tn)
494 assert(is_application(term));
495 {
496 const application& terma=atermpp::down_cast<application>(term);
497 if (terma.head()==this_term_is_in_normal_form())
498 {
499 assert(terma.size()==1);
500 assert(remove_normal_form_function(terma[0])==terma[0]);
501 result.assign(terma[0], *m_thread_aterm_pool);
502 return;
503 }
504
505 // The variable term has the shape appl(t,t1,...,tn);
506
507 // First check whether t has the shape appl(appl...appl(f,u1,...,un)(...)(...) where f is a function symbol.
508 // In this case rewrite that function symbol. This is an optimisation. If this does not apply t is rewritten,
509 // including all its subterms. But this is costly, as not all subterms will be rewritten again
510 // in rewrite_aux_function_symbol.
511
512 const data_expression& head=get_nested_head(term);
513
515 {
516 rewrite_aux_function_symbol(result, atermpp::down_cast<function_symbol>(head),terma,sigma);
517 return;
518 }
519
520 const application& tapp=atermpp::down_cast<application>(term);
521
522 m_rewrite_stack.increase(2);
523
524 const std::size_t t = 0; // Index of variable t in the stack.
525 rewrite_aux(m_rewrite_stack.element(t,2),tapp.head(),sigma);
526
527 // Here t has the shape f(u1,....,un)(u1',...,um')....: f applied several times to arguments,
528 // x(u1,....,un)(u1',...,um')....: x applied several times to arguments, or
529 // binder x1,...,xn.t' where the binder is a lambda, exists or forall.
530
531 const std::size_t head1 = 1; // Index of variable head1 in the stack.
532 m_rewrite_stack.set_element(head1,2,get_nested_head(m_rewrite_stack.get_element(t,2)));
533 if (is_function_symbol(m_rewrite_stack.get_element(head1,2)))
534 {
535 // In this case t (i.e. the top of the rewrite stack) has the shape f(u1...un)(u1'...um').... where all u1,...,un,u1',...,um' are normal formas.
536 // In the invocation of rewrite_aux_function_symbol these terms must not be rewritten to normalform again.
537 make_application(result, m_rewrite_stack.get_element(t,2), tapp.begin(), tapp.end());
538 const std::size_t do_not_rewrite_first_arguments=recursive_number_of_args( m_rewrite_stack.get_element(t,2));
539 assert(remove_normal_form_function(m_rewrite_stack.get_element(t,2))==m_rewrite_stack.get_element(t,2));
540 rewrite_aux_function_symbol(m_rewrite_stack.element(t,2),
541 atermpp::down_cast<function_symbol>(m_rewrite_stack.get_element(head1,2)),
542 atermpp::down_cast<application>(result),
543 sigma,
544 do_not_rewrite_first_arguments);
545 result=m_rewrite_stack.element(t,2);
546 m_rewrite_stack.decrease(2);
547 return;
548 }
549 else if (is_variable(m_rewrite_stack.element(head1,2)))
550 {
551 // return appl(t,t1,...,tn) where t1,...,tn still need to be rewritten.
552 jitty_argument_rewriter r(sigma,*this);
553 const bool do_not_rewrite_head=false;
554 make_application(result, m_rewrite_stack.element(t,2) , tapp.begin(), tapp.end(), r, do_not_rewrite_head); // Replacing r by a lambda term requires 16 more bytes on the stack.
555 m_rewrite_stack.decrease(2);
556 return;
557 }
558 assert(is_abstraction(m_rewrite_stack.top()));
559 const abstraction& ta=atermpp::down_cast<abstraction>(m_rewrite_stack.element(t,2) );
560 const binder_type& binder(ta.binding_operator());
561 if (is_lambda_binder(binder))
562 {
563 rewrite_lambda_application(result,ta,tapp,sigma);
564 m_rewrite_stack.decrease(2);
565 return;
566 }
567 if (is_exists_binder(binder))
568 {
569 assert(term.size()==1);
570 existential_quantifier_enumeration(result,ta,sigma);
571 m_rewrite_stack.decrease(2);
572 return;
573 }
574 assert(is_forall_binder(binder));
575 assert(term.size()==1);
576 universal_quantifier_enumeration(result,ta,sigma);
577 m_rewrite_stack.decrease(2);
578 return;
579 }
580}
581
582// The last argument prevents the recursively first indicated number of arguments not to be rewritten. If 0 they are all rewritten.
583void RewriterJitty::rewrite_aux_function_symbol(
584 data_expression& result,
585 const function_symbol& op,
586 const application& term,
587 substitution_type& sigma,
588 const std::size_t do_not_rewrite_first_arguments /*=0*/)
589{
591
592 const std::size_t arity=detail::recursive_number_of_args(term);
593 assert(arity>0);
594 m_rewrite_stack.increase(arity+1);
595 bool* rewritten_defined = MCRL2_SPECIFIC_STACK_ALLOCATOR(bool, arity);
596
597 for(std::size_t i=0; i<arity; ++i)
598 {
599 rewritten_defined[i]=false;
600 }
601
602 const std::size_t op_value=atermpp::detail::index_traits<data::function_symbol,function_symbol_key_type, 2>::index(op);
603 make_jitty_strat_sufficiently_larger(op_value);
604 const strategy& strat=jitty_strat[op_value];
605
606 if (!strat.rules().empty())
607 {
609 MCRL2_SPECIFIC_STACK_ALLOCATOR(jitty_variable_assignment_for_a_rewrite_rule, strat.number_of_variables()));
610
611 for (const strategy_rule& rule : strat.rules())
612 {
613 if (rule.is_rewrite_index())
614 {
615 const std::size_t i = rule.rewrite_index();
616 if (i < arity)
617 {
618 assert(!rewritten_defined[i]||i==0);
619 if (!rewritten_defined[i])
620 {
621 if (i<do_not_rewrite_first_arguments)
622 {
623 m_rewrite_stack.set_element(i,arity+1,detail::get_argument_of_higher_order_term(term,i));
624 }
625 else
626 {
627 rewrite_aux(m_rewrite_stack.element(i,arity+1),detail::get_argument_of_higher_order_term(term,i),sigma);
628 }
629 rewritten_defined[i]=true;
630 }
631 assert(m_rewrite_stack.element(i,arity+1).defined());
632 }
633 else
634 {
635 break;
636 }
637 }
638 else if (rule.is_cpp_code())
639 {
640 // Here it is assumed that precompiled code only works on the exact right number of arguments and
641 // precompiled functions are not used in a higher order fashion. Maybe this requires an explicit check.
642 assert(arity>0);
643 if (term.head()==op)
644 {
645 assert(m_rewrite_stack.stack_size()>=arity+1);
646 application rewriteable_term(op, m_rewrite_stack.stack_iterator(0,arity+1),
647 m_rewrite_stack.stack_iterator(arity,arity+1)); /* TODO Optimize */
648 rule.rewrite_cpp_code()(result, rewriteable_term);
649 m_rewrite_stack.decrease(arity+1);
650 return;
651 }
652 else
653 {
654 // Guarantee that all higher order arguments are in normal form. Maybe this had to be done in the strategy for higher
655 // order terms.
656 for(std::size_t i=0; i<recursive_number_of_args(term); i++)
657 {
658 if (!rewritten_defined[i])
659 {
660 rewrite_aux(m_rewrite_stack.element(i,arity+1),detail::get_argument_of_higher_order_term(term,i),sigma);
661 rewritten_defined[i]=true;
662 }
663 }
664 apply_cpp_code_to_higher_order_term(
665 result,
666 term,
667 rule.rewrite_cpp_code(),
668 m_rewrite_stack.stack_iterator(0,arity+1),
669 m_rewrite_stack.stack_iterator(arity,arity+1), sigma);
670 m_rewrite_stack.decrease(arity+1);
671 return;
672 }
673 }
674 else
675 {
676 const data_equation& rule1=rule.equation();
677 const data_expression& lhs=rule1.lhs();
678 std::size_t rule_arity = (is_function_symbol(lhs)?0:detail::recursive_number_of_args(lhs));
679
680 if (rule_arity > arity)
681 {
682 break;
683 }
684
685 assert(assignments.size==0);
686
687 bool matches = true;
688 for (std::size_t i=0; i<rule_arity; i++)
689 {
690 assert(i<arity);
691 if (!match_jitty(rewritten_defined[i]?
692 m_rewrite_stack.get_element(i,arity+1):
693 detail::get_argument_of_higher_order_term(term,i),
694 detail::get_argument_of_higher_order_term(atermpp::down_cast<application>(lhs),i),
695 assignments,rewritten_defined[i]))
696 {
697 matches = false;
698 break;
699 }
700 }
701 if (matches)
702 {
703 bool condition_of_this_rule=false;
704 if (rule1.condition()==sort_bool::true_())
705 {
706 condition_of_this_rule=true;
707 }
708 else
709 {
710 subst_values(m_rewrite_stack.top(),assignments,rule1.condition(),m_generator);
711 rewrite_aux(result, m_rewrite_stack.top(), sigma);
712 condition_of_this_rule = (result==sort_bool::true_());
713 }
714 if (condition_of_this_rule)
715 {
716 const data_expression& rhs=rule1.rhs();
717
718 if (arity == rule_arity)
719 {
720 subst_values(m_rewrite_stack.top(),assignments,rhs,m_generator);
721 rewrite_aux(result, m_rewrite_stack.top(),sigma);
722 m_rewrite_stack.decrease(arity+1);
723 return;
724 }
725 else
726 {
727 assert(arity>rule_arity);
728 // There are more arguments than those that have been rewritten.
729 // Get those, put them in rewritten.
730
731 for(std::size_t i=rule_arity; i<arity; ++i)
732 {
733 m_rewrite_stack.set_element(i,arity+1,detail::get_argument_of_higher_order_term(term,i));
734 rewritten_defined[i]=true;
735 }
736
737 subst_values(m_rewrite_stack.top(),assignments,rhs,m_generator);
738 std::size_t i = rule_arity;
739 sort_expression sort = detail::residual_sort(op.sort(),i);
740 while (is_function_sort(sort) && (i < arity))
741 {
742 const function_sort& fsort = atermpp::down_cast<function_sort>(sort);
743 const std::size_t end=i+fsort.domain().size();
744 assert(end-1<arity);
745 assert(m_rewrite_stack.stack_size()+i>=arity+1);
746 assert(end<arity+1);
747 assert(end>=i);
748
749 make_application(m_rewrite_stack.top(),m_rewrite_stack.top(),
750 m_rewrite_stack.stack_iterator(i,arity+1),
751 m_rewrite_stack.stack_iterator(end,arity+1));
752 i=end;
753 sort = fsort.codomain();
754 }
755
756 rewrite_aux(result,m_rewrite_stack.top(),sigma);
757 m_rewrite_stack.decrease(arity+1);
758 return;
759 }
760 }
761
762 }
763 assignments.size=0;
764 }
765 }
766 }
767
768 // No rewrite rule is applicable. Rewrite the not yet rewritten arguments.
769 // As we rewrite all, we do not record anymore whether terms are rewritten.
770
771 for (std::size_t i=0; i<arity; i++)
772 {
773 if (!rewritten_defined[i])
774 {
775 rewrite_aux(m_rewrite_stack.element(i,arity+1),detail::get_argument_of_higher_order_term(term,i),sigma);
776 }
777 }
778
779 // The while loop must always be iterated once. Therefore, the initial traversal is put before the
780 // main loop.
781 const function_sort& fsort=atermpp::down_cast<function_sort>(op.sort());
782 const std::size_t end=fsort.domain().size();
783
784 make_application(result,op,m_rewrite_stack.stack_iterator(0,arity+1), m_rewrite_stack.stack_iterator(end,arity+1));
785 std::size_t i=end;
786 const sort_expression* sort = &fsort.codomain();
787 while (i<arity && is_function_sort(*sort))
788 {
789 const function_sort& fsort=atermpp::down_cast<function_sort>(*sort);
790 const std::size_t end=i+fsort.domain().size();
791 assert(m_rewrite_stack.stack_size()+i>=arity+1);
792 assert(end<arity+1);
793 assert(end>=i);
794 make_application(result,result,m_rewrite_stack.stack_iterator(i,arity+1), m_rewrite_stack.stack_iterator(end,arity+1));
795 i=end;
796 sort = &fsort.codomain();
797 }
798
799 m_rewrite_stack.decrease(arity+1);
800 return;
801}
802
804 data_expression& result,
805 const function_symbol& op,
806 substitution_type& sigma)
807{
808 // This is special code to rewrite a function symbol. Note that the function symbol can be higher order,
809 // e.g., it can be a function symbol f for which a rewrite rule f(n)=... exists.
810
811 const std::size_t op_value=atermpp::detail::index_traits<data::function_symbol,function_symbol_key_type, 2>::index(op);
812 make_jitty_strat_sufficiently_larger(op_value);
813
814 // Cache the rhs's as they are rewritten very often.
815 if (rhs_for_constants_cache.size()<=op_value)
816 {
817 rhs_for_constants_cache.resize(op_value+1);
818 }
819 const data_expression& cached_rhs = rhs_for_constants_cache[op_value];
820 if (!cached_rhs.is_default_data_expression())
821 {
822 /* result.assign(cached_rhs,
823 this->m_busy_flag,
824 this->m_forbidden_flag,
825 *this->m_creation_depth); */
826 result.assign(cached_rhs, *m_thread_aterm_pool);
827 return;
828 }
829
830 const strategy& strat=jitty_strat[op_value];
831
832 for (const strategy_rule& rule : strat.rules())
833 {
834 if (rule.is_rewrite_index())
835 {
836 // In this case a standalone function symbol is rewritten, which could have arguments.
837 // It is not needed to rewrite the arguments.
838 break;
839 }
840 else if (rule.is_cpp_code())
841 {
842 rule.rewrite_cpp_code()(result, op);
843 rhs_for_constants_cache[op_value]=result;
844 return;
845 }
846 else
847 {
848 const data_equation& rule1=rule.equation();
849 const data_expression& lhs=rule1.lhs();
850 std::size_t rule_arity = (is_function_symbol(lhs)?0:detail::recursive_number_of_args(lhs));
851
852 if (rule_arity > 0)
853 {
854 break;
855 }
856
857 if (rule1.condition()==sort_bool::true_())
858 {
859 rewrite_aux(result,rule1.rhs(),sigma);
860 rhs_for_constants_cache[op_value]=result;
861 return;
862 }
863 rewrite_aux(result,rule1.condition(),sigma);
864 if (result==sort_bool::true_())
865 {
866 rewrite_aux(result,rule1.rhs(),sigma);
867 rhs_for_constants_cache[op_value]=result;
868 return;
869 }
870 }
871 }
872
873 rhs_for_constants_cache[op_value]=op;
874 result=op;
875 return;
876}
877
879 data_expression& result,
880 const data_expression& term,
881 substitution_type& sigma)
882{
883#ifdef MCRL2_DISPLAY_REWRITE_STATISTICS
884 data::detail::increment_rewrite_count();
885#endif
887 {
888 rewrite_aux(result, term, sigma);
889 }
890 else
891 {
892 assert(m_rewrite_stack.stack_size()==0);
894 try
895 {
896 rewrite_aux(result, term, sigma);
897 }
899 {
900 rewriting_in_progress=false; // Restart rewriting, due to a stack overflow.
901 // The stack is a vector, and it may be relocated in memory when
902 // resized. References to the stack loose their validity.
903 m_rewrite_stack.reserve_more_space();
904 rewrite(result,term,sigma);
905 return;
906 }
908 assert(m_rewrite_stack.stack_size()==0);
909 }
910
911 assert(remove_normal_form_function(result)==result);
912 return;
913}
914
916 const data_expression& term,
917 substitution_type& sigma)
918{
919 data_expression result;
920 rewrite(result, term, sigma);
921 return result;
922}
923
924
925rewrite_strategy RewriterJitty::getStrategy()
926{
927 return jitty;
928}
929}
An abstraction expression.
Definition abstraction.h:23
const variable_list & variables() const
Definition abstraction.h:60
abstraction(const binder_type &binding_operator, const variable_list &variables, const data_expression &body)
Constructor.
Definition abstraction.h:39
const data_expression & body() const
Definition abstraction.h:65
const binder_type & binding_operator() const
Definition abstraction.h:55
\brief A data equation
data_expression & operator=(const data_expression &) noexcept=default
bool is_default_data_expression() const
A function to efficiently determine whether a data expression is made by the default constructor.
void rewrite_aux_const_function_symbol(data_expression &result, const function_symbol &op, substitution_type &sigma)
Definition jitty.cpp:803
void thread_initialise() override
Definition jitty.h:131
rewrite_strategy getStrategy() override
Get rewriter strategy that is used.
Definition jitty.cpp:925
RewriterJitty(const data_specification &data_spec, const used_data_equation_selector &)
Definition jitty.cpp:169
void rewrite_aux(data_expression &result, const data_expression &term, substitution_type &sigma)
Rewrite a term with a given substitution and put the rewritten term in result.
Definition jitty.cpp:446
void add_normal_form_function(data_expression &t)
Definition jitty.cpp:92
data_expression rewrite(const data_expression &term, substitution_type &sigma) override
Rewrite an mCRL2 data term.
Definition jitty.cpp:915
void apply_cpp_code_to_higher_order_term(data_expression &result, const application &t, const std::function< void(data_expression &, const data_expression &)> rewrite_cpp_code, ITERATOR begin, ITERATOR end, substitution_type &sigma)
Definition jitty.cpp:417
const function_symbol & this_term_is_in_normal_form()
Definition jitty.h:71
void subst_values(data_expression &result, const jitty_assignments_for_a_rewrite_rule &assignments, const data_expression &t, data::enumerator_identifier_generator &generator)
Definition jitty.cpp:224
data_expression remove_normal_form_function(const data_expression &t)
Definition jitty.cpp:36
atermpp::detail::thread_aterm_pool * m_thread_aterm_pool
Definition jitty.h:91
void rebuild_strategy(const data_specification &data_spec, const mcrl2::data::used_data_equation_selector &equation_selector)
Definition jitty.cpp:147
void rewrite(data_expression &result, const data_expression &term, substitution_type &sigma) override
Rewrite an mCRL2 data term.
Definition jitty.cpp:878
Rewriter interface class.
Definition rewrite.h:39
Rewriter(const data_specification &data_spec, const used_data_equation_selector &eq_selector)
Constructor. Do not use directly; use createRewriter() function instead.
Definition rewrite.h:60
const std::set< std::size_t > & dependencies() const
Definition jitty.cpp:124
dependencies_rewrite_rule_pair(std::set< std::size_t > &dependencies, const data_equation &eq)
Definition jitty.cpp:120
mutable_indexed_substitution & m_sigma
Definition jitty.cpp:100
jitty_argument_rewriter(mutable_indexed_substitution<> &sigma, RewriterJitty &r)
Definition jitty.cpp:103
void operator()(data_expression &result, const data_expression &t)
Definition jitty.cpp:107
A strategy is a list of rules and the number of variables that occur in it.
\brief A function sort
const sort_expression & codomain() const
\brief A function symbol
const sort_expression & sort() const
\brief A sort expression
Component for selecting a subset of equations that are actually used in an encompassing specification...
Definition selection.h:36
\brief A where expression
const data_expression & body() const
const assignment_expression_list & declarations() const
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:393
static bool match_jitty(const data_expression &t, const data_expression &p, jitty_assignments_for_a_rewrite_rule &assignments, const bool term_context_guarantees_normal_form)
Definition jitty.cpp:346
std::set< variable > bound_variables_in_substitution(const jitty_assignments_for_a_rewrite_rule &assignments)
Definition jitty.cpp:212
const data_expression & get_nested_head(const data_expression &t)
bool is_application(const data_expression &t)
Returns true if the term t is an application.
bool is_where_clause(const atermpp::aterm &x)
Returns true if the term t is a where clause.
bool is_abstraction(const atermpp::aterm &x)
Returns true if the term t is an abstraction.
bool is_exists_binder(const atermpp::aterm &x)
bool is_lambda_binder(const atermpp::aterm &x)
bool is_forall(const atermpp::aterm &x)
Returns true if the term t is a universal quantification.
bool is_function_symbol(const atermpp::aterm &x)
Returns true if the term t is a function symbol.
bool is_exists(const atermpp::aterm &x)
Returns true if the term t is an existential quantification.
bool is_function_sort(const atermpp::aterm &x)
Returns true if the term t is a function sort.
bool is_machine_number(const atermpp::aterm &x)
Returns true if the term t is a machine_number.
bool is_lambda(const atermpp::aterm &x)
Returns true if the term t is a lambda abstraction.
bool is_forall_binder(const atermpp::aterm &x)
bool is_variable(const atermpp::aterm &x)
Returns true if the term t is a variable.
jitty_assignments_for_a_rewrite_rule(jitty_variable_assignment_for_a_rewrite_rule *a)
Definition jitty.h:40