Cadabra
Computer algebra system for field theory problems
Props.hh
Go to the documentation of this file.
1 /*
2 
3 Cadabra: a field-theory motivated computer algebra system.
4 Copyright (C) 2001-2014 Kasper Peeters <kasper.peeters@phi-sci.com>
5 
6 This program is free software: you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation, either version 3 of the
9 License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 
19 */
20 
21 // Classes handling storage of property information. Actual property
22 // implementations are in the properties directory in separate files.
23 
24 #pragma once
25 
26 #include <map>
27 #include <list>
28 #include <type_traits>
29 #include "Storage.hh"
30 
31 namespace cadabra {
32 
33  class Properties;
34  class Kernel;
35  class Accent;
36  class LaTeXForm;
37  class Ex_comparator;
38 
39  class pattern {
40  public:
41  pattern();
42  pattern(const Ex&);
43 
54 
55  bool match(const Properties&, const Ex::iterator&, bool ignore_parent_rel=false, bool ignore_properties=false) const;
56  bool children_wildcard() const;
57 
61  bool match_ext(const Properties&, const Ex::iterator&, Ex_comparator& comp, bool ignore_parent_rel=false, bool ignore_properties=false) const;
62 
64  };
65 
67 
68  class keyval_t {
69  public:
70  typedef std::pair<std::string, Ex::iterator> kvpair_t;
71  typedef std::list<kvpair_t> kvlist_t;
72 
73  typedef kvlist_t::const_iterator const_iterator;
74  typedef kvlist_t::iterator iterator;
76 
77  const_iterator find(const std::string&) const;
78  iterator find(const std::string&);
79  const_iterator begin() const;
80  const_iterator end() const;
81  void push_back(const kvpair_t&);
82  void erase(iterator);
83 
84  private:
86  };
87 
103  // default implementation returns true for any pattern.
125 
126 
127  class property {
128  public:
129  property(bool hidden=false);
130  virtual ~property() {};
131 
132  // Parse the argument tree into key-value pairs. Returns false on error.
133  bool parse_to_keyvals(const Ex&, keyval_t&);
134 
135  // Use the pre-parsed arguments in key/value form to set parameters.
136  // Parses universal arguments by default. Will be called once for
137  // every property; assigning a non-list property to multiple patterns
138  // still calls this only once.
139  // FIXME: failure to call
140  // into superclass may lead to problems for labelled properties.
141  virtual bool parse(Kernel&, keyval_t& keyvals);
142 
143  // New entry point, which also passes the Ex of the pattern, so that
144  // the property itself can inject other properties automatically (e.g.
145  // declare an InverseMetric if a Metric is declared).
146  virtual bool parse(Kernel&, std::shared_ptr<Ex>, keyval_t& keyvals);
147 
148  // Check whether the property can be associated with the pattern.
149  // Throw an error if validation fails. Needs access to all other
150  // declared properties so that it can understand what the pattern
151  // means (which objects are indices etc.).
152  virtual void validate(const Kernel&, const Ex&) const;
153 
155  // virtual void display(std::ostream&) const;
156 
159  virtual void latex(std::ostream&) const;
160 
161  virtual std::string name() const=0;
162  virtual std::string unnamed_argument() const;
163 
164  // To compare properties we sometimes need to compare their variables, not only
165  // their type. The following function needs to be overridden in all properties
166  // for which comparison by type is not sufficient to establish equality.
167  //
168  // id_match: only one of these properties can be registered, but their data is not the same
169  // exact_match: these properties are exactly identical
171  virtual match_t equals(const property *) const;
172 
176  void hidden(bool h);
177  bool hidden(void) const;
178 
179  private:
180  bool parse_one_argument(Ex::iterator arg, keyval_t& keyvals);
181  bool hidden_;
182  };
183 
184  class labelled_property : virtual public property {
185  public:
186  virtual bool parse(Kernel&, std::shared_ptr<Ex>, keyval_t&) override;
187  std::string label;
188  };
189 
192 
193  class list_property : public property {
194  public:
195  };
196 
202 
203  template<class T>
204  class Inherit : virtual public property {
205  public:
206  virtual ~Inherit() {};
207  virtual std::string name() const
208  {
209 // T tmp;
210  // T can be abstract, so we cannot instantiate. Maybe use typeid,
211  // but then we need to be careful about name mangling.
212  return std::string("Inherit");
213  };
214  };
215 
218 
219  class PropertyInherit : virtual public property {
220  public:
221  virtual std::string name() const
222  {
223  return std::string("PropertyInherit");
224  };
225  };
226 
236 
237  class Properties {
238  public:
239  // Registering property types.
241  public:
243 
244  typedef std::map<std::string, property* (*)()> internal_property_map_t;
245  typedef internal_property_map_t::iterator iterator;
246 
248  };
249 
253 
254  void register_property(property* (*)(), const std::string& name);
256  typedef std::pair<pattern *, const property *> pat_prop_pair_t;
257 
265  typedef std::multimap<nset_t::iterator, pat_prop_pair_t, nset_it_less> property_map_t;
266  typedef std::multimap<const property *, pattern *> pattern_map_t;
267 
271  std::string master_insert(Ex proptree, const property *thepropbase);
272 
273  void clear();
274 
279  property_map_t props; // pattern -> property
280  pattern_map_t pats; // property -> pattern; for list properties, patterns are stored here in order
281 
283  template<class T> const T* get(Ex::iterator, bool ignore_parent_rel=false) const;
284  template<class T> const T* get(Ex::iterator, int& serialnum, bool doserial=true, bool ignore_parent_rel=false) const;
286  template<class T> const T* get(Ex::iterator, const std::string& label) const;
287  template<class T> const T* get(Ex::iterator, int& serialnum, const std::string& label, bool doserial=true) const;
289  template<class T> const T* get(Ex::iterator, Ex::iterator, bool ignore_parent_rel=false) const;
290  template<class T> const T* get(Ex::iterator, Ex::iterator, int&, int&, bool ignore_parent_rel=false) const;
291 
295  template<class T>
296  std::pair<const T*, const pattern *> get_with_pattern(Ex::iterator, int& serialnum,
297  const std::string& label,
298  bool doserial=true, bool ignore_parent_rel=false) const;
299 
300  template<class T>
301  std::pair<const T*, const pattern *> get_with_pattern_ext(Ex::iterator, Ex_comparator&, int& serialnum,
302  const std::string& label,
303  bool doserial=true, bool ignore_parent_rel=false) const;
304 
305  // Get the outermost node which has the given property attached, i.e. go down through
306  // all (if any) nodes which have just inherited the property.
307  template<class T> Ex::iterator head(Ex::iterator, bool ignore_parent_rel=false) const;
308 
309  // Inverse search: given a property type, get a pattern which has this property.
310  // When given an iterator, it starts to search in the property
311  // map from this particular point. Note: this searches on property type, not exact property.
312  // template<class T>
313  // property_map_t::iterator get_pattern(property_map_t::iterator=props.begin());
314 
315  // Equivalent search: given a node, get a pattern of equivalents.
316  // property_map_t::iterator get_equivalent(Ex::iterator,
317  // property_map_t::iterator=props.begin());
318 
319  private:
320  // Insert a property. Do not use this directly, use the public
321  // interface `master_insert` instead.
322  void insert_prop(const Ex&, const property *);
323  void insert_list_prop(const std::vector<Ex>&, const list_property *);
324  bool check_label(const property *, const std::string&) const;
325  bool check_label(const labelled_property *, const std::string&) const;
326  // Search through pointers
327  bool has(const property *, Ex::iterator);
328  // Find serial number of a pattern in a given list property
329  int serial_number(const property *, const pattern *) const;
331  void destroy_comparator(Ex_comparator *) const;
332  };
333 
334  template<class T>
335  const T* Properties::get(Ex::iterator it, bool ignore_parent_rel) const
336  {
337  int tmp;
338  return get<T>(it, tmp, false, ignore_parent_rel);
339  }
340 
341  template<class T>
342  const T* Properties::get(Ex::iterator it, int& serialnum, bool doserial, bool ignore_parent_rel) const
343  {
344  auto ret = get_with_pattern<T>(it, serialnum, "", doserial, ignore_parent_rel);
345  return ret.first;
346  }
347 
348  template<class T>
349  std::pair<const T*, const pattern *> Properties::get_with_pattern(Ex::iterator it, int& serialnum, const std::string& label,
350  bool doserial, bool ignore_parent_rel) const
351  {
352  Ex_comparator *compptr = create_comparator();
353  // FIXME: catch and rethrow all exceptions so we do not leak memory
354  auto ret = get_with_pattern_ext<T>(it, *compptr, serialnum, label, doserial, ignore_parent_rel);
355  destroy_comparator(compptr);
356  return ret;
357  }
358 
359  template<class T>
360  std::pair<const T*, const pattern *> Properties::get_with_pattern_ext(Ex::iterator it, Ex_comparator& comp,
361  int& serialnum, const std::string& label,
362  bool doserial, bool ignore_parent_rel) const
363  {
364  std::pair<const T*, const pattern *> ret;
365  ret.first=0;
366  ret.second=0;
367  bool inherits=false;
368 
369  //std::cerr << *it->name_only() << std::endl;
370  // std::cerr << props.size() << std::endl;
371  std::pair<property_map_t::const_iterator, property_map_t::const_iterator> pit=props.equal_range(it->name_only());
372 
373  // First look for properties of the node itself. Go through the loop twice:
374  // once looking for patterns which do not have wildcards, and then looking
375  // for wildcard patterns.
376  bool wildcards=false;
377 
378  // For some properties, we cannot lookup properties lower down the
379  // tree, because it would lead to an endless recursion (and it would
380  // not make sense anyway). At the moment, this is only for Accent.
381  bool ignore_properties=false;
382  if(std::is_same<T, Accent>::value)
383  ignore_properties=true;
384 
385  for(;;) {
386  property_map_t::const_iterator walk=pit.first;
387  while(walk!=pit.second) {
388  if(wildcards==(*walk).second.first->children_wildcard()) {
389  // First check property type; a dynamic cast is much faster than a pattern match.
390  ret.first=dynamic_cast<const T *>((*walk).second.second);
391  if(ret.first) {
392  if((*walk).second.first->match_ext(*this, it, comp, ignore_parent_rel, ignore_properties)) {
393  ret.second=(*walk).second.first;
394  if(!check_label(ret.first, label))
395  ret.first=0;
396  else {
397  if(doserial)
398  serialnum=serial_number( (*walk).second.second, (*walk).second.first );
399  break;
400  }
401  }
402  }
403  ret.first=0;
404  if(dynamic_cast<const PropertyInherit *>((*walk).second.second))
405  inherits=true;
406  else if(dynamic_cast<const Inherit<T> *>((*walk).second.second))
407  inherits=true;
408  }
409  ++walk;
410  }
411  if(!wildcards && !ret.first) {
412  // std::cerr << "not yet found, switching to wildcards" << std::endl;
413  wildcards=true;
414  }
415  else break;
416  }
417 
418  // Do not walk down the tree if the property cannot be passed up the tree.
419  // FIXME: see issue/259.
420  if(std::is_same<T, LaTeXForm>::value)
421  inherits=false;
422 
423  // If no property was found, figure out whether a property is inherited from a child node.
424  if(!ret.first && inherits) {
425  // std::cout << "no match but perhaps inheritance?" << std::endl;
426  Ex::sibling_iterator sib=it.begin();
427  while(sib!=it.end()) {
428  std::pair<const T*, const pattern *> tmp=get_with_pattern<T>((Ex::iterator)(sib), serialnum, label, doserial);
429  if(tmp.first) {
430  ret=tmp;
431  break;
432  }
433  ++sib;
434  }
435  }
436 
437  // std::cout << ret << std::endl;
438  return ret;
439  }
440 
441  template<class T>
442  const T* Properties::get(Ex::iterator it, const std::string& label) const
443  {
444  int tmp;
445  return get<T>(it, tmp, label, false);
446  }
447 
448  template<class T>
449  const T* Properties::get(Ex::iterator it, int& serialnum, const std::string& label, bool doserial) const
450  {
451  auto ret=get_with_pattern<T>(it, serialnum, label, doserial, false);
452  return ret.first;
453  }
454 
455  template<class T>
456  const T* Properties::get(Ex::iterator it1, Ex::iterator it2, bool ignore_parent_rel) const
457  {
458  int tmp1, tmp2;
459  return get<T>(it1,it2,tmp1,tmp2, ignore_parent_rel);
460  }
461 
462  template<class T>
463  const T* Properties::get(Ex::iterator it1, Ex::iterator it2, int& serialnum1, int& serialnum2, bool ignore_parent_rel) const
464  {
465  const T* ret1=0;
466  const T* ret2=0;
467  bool found=false;
468 
469  bool inherits1=false, inherits2=false;
470  std::pair<property_map_t::const_iterator, property_map_t::const_iterator> pit1=props.equal_range(it1->name_only());
471  std::pair<property_map_t::const_iterator, property_map_t::const_iterator> pit2=props.equal_range(it2->name_only());
472 
473  property_map_t::const_iterator walk1=pit1.first;
474  while(walk1!=pit1.second) {
475  if((*walk1).second.first->match(*this, it1, ignore_parent_rel)) { // match for object 1 found
476  ret1=dynamic_cast<const T *>((*walk1).second.second);
477  if(ret1) { // property of the right type found for object 1
478  property_map_t::const_iterator walk2=pit2.first;
479  while(walk2!=pit2.second) {
480  if((*walk2).second.first->match(*this, it2, ignore_parent_rel)) { // match for object 2 found
481  ret2=dynamic_cast<const T *>((*walk2).second.second);
482  if(ret2) { // property of the right type found for object 2
483  if(ret1==ret2 && walk1!=walk2) { // accept if properties are the same and patterns are not
484  serialnum1=serial_number( (*walk1).second.second, (*walk1).second.first );
485  serialnum2=serial_number( (*walk2).second.second, (*walk2).second.first );
486  found=true;
487  goto done;
488  }
489  }
490  }
491  if(dynamic_cast<const PropertyInherit *>((*walk2).second.second))
492  inherits2=true;
493  ++walk2;
494  }
495  }
496  if(dynamic_cast<const PropertyInherit *>((*walk1).second.second))
497  inherits1=true;
498  }
499  ++walk1;
500  }
501 
502  // If no property was found, figure out whether a property is inherited from a child node.
503  if(!found && (inherits1 || inherits2)) {
504  Ex::sibling_iterator sib1, sib2;
505  if(inherits1) sib1=it1.begin();
506  else sib1=it1;
507  bool keepgoing1=true;
508  do { // 1
509  bool keepgoing2=true;
510  if(inherits2) sib2=it2.begin();
511  else sib2=it2;
512  do { // 2
513  const T* tmp=get<T>((Ex::iterator)(sib1), (Ex::iterator)(sib2), serialnum1, serialnum2, ignore_parent_rel);
514  if(tmp) {
515  ret1=tmp;
516  found=true;
517  goto done;
518  }
519  if(!inherits2 || ++sib2==it2.end())
520  keepgoing2=false;
521  }
522  while(keepgoing2);
523  if(!inherits1 || ++sib1==it1.end())
524  keepgoing1=false;
525  }
526  while(keepgoing1);
527  }
528 
529 done:
530  if(!found) ret1=0;
531  return ret1;
532  }
533 
534  template<class T>
535  Ex::iterator Properties::head(Ex::iterator it, bool ignore_parent_rel) const
536  {
537  Ex::iterator dn=it;
538  for(;;) {
539  if(get<PropertyInherit>(dn, ignore_parent_rel)) {
540  dn=dn.begin();
541  }
542  else {
543  assert(get<T>(dn));
544  break;
545  }
546  }
547  return dn;
548  }
549 
550  }
A generic tree comparison class which will take into account index contractions and will also keep tr...
Definition: Compare.hh:192
Basic storage class for symbolic mathemematical expressions.
Definition: Storage.hh:142
If a property X derives from Inherit<Y>, and get<Y> is called on an object which has an X property (b...
Definition: Props.hh:204
virtual ~Inherit()
Definition: Props.hh:206
virtual std::string name() const
Definition: Props.hh:207
Definition: Kernel.hh:15
internal_property_map_t store
Definition: Props.hh:247
std::map< std::string, property *(*)()> internal_property_map_t
Definition: Props.hh:244
internal_property_map_t::iterator iterator
Definition: Props.hh:245
~registered_property_map_t()
Definition: Props.cc:175
Class holding a collection of properties attached to expressions.
Definition: Props.hh:237
void insert_list_prop(const std::vector< Ex > &, const list_property *)
Definition: Props.cc:435
Ex::iterator head(Ex::iterator, bool ignore_parent_rel=false) const
Definition: Props.hh:535
std::pair< pattern *, const property * > pat_prop_pair_t
Definition: Props.hh:256
std::string master_insert(Ex proptree, const property *thepropbase)
Register a property for the indicated Ex.
Definition: Props.cc:580
std::pair< const T *, const pattern * > get_with_pattern_ext(Ex::iterator, Ex_comparator &, int &serialnum, const std::string &label, bool doserial=true, bool ignore_parent_rel=false) const
Definition: Props.hh:360
pattern_map_t pats
Definition: Props.hh:280
registered_property_map_t registered_properties
Definition: Props.hh:255
bool check_label(const property *, const std::string &) const
Definition: Props.cc:643
std::multimap< const property *, pattern * > pattern_map_t
Definition: Props.hh:266
void register_property(property *(*)(), const std::string &name)
Registering properties.
Definition: Props.cc:180
std::multimap< nset_t::iterator, pat_prop_pair_t, nset_it_less > property_map_t
We keep two multi-maps: one from the pattern to the property (roughly) and one from the property to t...
Definition: Props.hh:265
bool has(const property *, Ex::iterator)
Definition: Props.cc:140
Ex_comparator * create_comparator() const
Definition: Props.cc:653
std::pair< const T *, const pattern * > get_with_pattern(Ex::iterator, int &serialnum, const std::string &label, bool doserial=true, bool ignore_parent_rel=false) const
General property finder, which will return not only the property but also the pattern which matched t...
Definition: Props.hh:349
void destroy_comparator(Ex_comparator *) const
Definition: Props.cc:658
const T * get(Ex::iterator, bool ignore_parent_rel=false) const
Normal search: given a pattern, get its property if any.
Definition: Props.hh:335
void insert_prop(const Ex &, const property *)
Definition: Props.cc:349
property_map_t props
The following two maps own the pointers to the properties and patterns stored in them; use clear() to...
Definition: Props.hh:279
int serial_number(const property *, const pattern *) const
Definition: Props.cc:530
void clear()
Definition: Props.cc:156
PropertyInherit is like Inherit<T> for all properties.
Definition: Props.hh:219
virtual std::string name() const
Definition: Props.hh:221
Arguments to properties get parsed into a keyval_t structure.
Definition: Props.hh:68
kvlist_t::const_iterator const_iterator
Definition: Props.hh:73
std::list< kvpair_t > kvlist_t
Definition: Props.hh:71
void push_back(const kvpair_t &)
Definition: Props.cc:217
const_iterator end() const
Definition: Props.cc:212
kvlist_t keyvals
Definition: Props.hh:85
kvlist_t::iterator iterator
Definition: Props.hh:74
const_iterator begin() const
Definition: Props.cc:207
std::pair< std::string, Ex::iterator > kvpair_t
Definition: Props.hh:70
kvpair_t value_type
Definition: Props.hh:75
void erase(iterator)
Definition: Props.cc:222
const_iterator find(const std::string &) const
Definition: Props.cc:185
Definition: Props.hh:184
std::string label
Definition: Props.hh:187
virtual bool parse(Kernel &, std::shared_ptr< Ex >, keyval_t &) override
Definition: Props.cc:320
Something cannot be both a list property and a normal property at the same time, so we can safely inh...
Definition: Props.hh:193
Definition: Props.hh:39
bool match(const Properties &, const Ex::iterator &, bool ignore_parent_rel=false, bool ignore_properties=false) const
Match a pattern to an expression.
Definition: Props.cc:43
bool match_ext(const Properties &, const Ex::iterator &, Ex_comparator &comp, bool ignore_parent_rel=false, bool ignore_properties=false) const
As match, but using a comparator object which is externally provided, so that the caller can use the ...
Definition: Props.cc:49
Ex obj
Definition: Props.hh:63
bool children_wildcard() const
Definition: Props.cc:132
pattern()
Definition: Props.cc:34
Base class for all properties, handling argument parsing and defining the interface.
Definition: Props.hh:127
virtual match_t equals(const property *) const
Definition: Props.cc:315
property(bool hidden=false)
Definition: Props.cc:228
virtual bool parse(Kernel &, keyval_t &keyvals)
Definition: Props.cc:243
virtual void latex(std::ostream &) const
Display the property on the stream.
Definition: Props.cc:305
bool parse_to_keyvals(const Ex &, keyval_t &)
Definition: Props.cc:279
virtual std::string unnamed_argument() const
Definition: Props.cc:310
bool parse_one_argument(Ex::iterator arg, keyval_t &keyvals)
Definition: Props.cc:259
bool hidden(void) const
Definition: Props.cc:238
bool hidden_
Definition: Props.hh:181
virtual ~property()
Definition: Props.hh:130
virtual std::string name() const =0
match_t
Definition: Props.hh:170
@ exact_match
Definition: Props.hh:170
@ no_match
Definition: Props.hh:170
@ id_match
Definition: Props.hh:170
virtual void validate(const Kernel &, const Ex &) const
Definition: Props.cc:255
Functions to handle the exchange properties of two or more symbols in a product.
Definition: Adjform.cc:83