Representation of Sets of Trees for Abstract Interpretation

Laurent Mauborgne

Thesis defended November 25, 1999 at École Polytechnique

Jury : Ahmed Bouajjani  Patrick Cousot (director)
Jean Goubault-Larrecq  Nicolas Halbwachs
Neil Jones (rapporteur, president) Andreas Podelski

David Schmidt (rapporteur)

Remerciements

Les remerciements constituent une étape obligée dans une thèse. Ils peuvent être plus ou moins sincères, plus ou moins conventionnels. Pour ma part, je suis très heureux d’utiliser cette opportunité, car il y a vraiment des personnes qui ont beaucoup compté durant cette thèse, et qui ont grandement contribué à son élaboration dans les meilleures conditions.

Valérie a toujours cru en moi et son soutien m’a beaucoup apporté. Je ne sais pas si sans elle cette thèse serait terminée. Je lui dédie cet ouvrage.

Patrick Cousot a été mon directeur de thèse. Il a accepté d’encadrer mon travail en me laissant une très grande liberté d’organisation et de recherche. J’ai beaucoup apprécié les discussions que nous avons eues sur mon travail. Mon seul regret sera de ne pas avoir assez suivi ses conseils au début de ma thèse.

Neil Jones et David Schmidt ont accepté de lire ma thèse et d’en être les rapporteurs. J’ai récemment relu ma thèse, et je sais que leur travail n’a pas été des plus faciles. Je les remercie pour leur gentillesse. David Schmidt, en particulier, m’a beaucoup encouragé. Neil Jones a accepté d’être président du jury, malgré la charge supplémentaire que cela représente. Je suis honoré qu’ils aient accepté de faire un si long voyage pour assister à ma soutenance.

Jean Goubault-Larrecq, Nicolas Halbwachs, Andreas Podelski et Ahmed Bouajjani ont accepté d’être membres de mon jury. J’ai la chance qu’ils aient tous bien voulu venir pour ma soutenance, malgré tous les obstacles d’agenda. Je remercie particulièrement Jean qui, croyant avoir été désigné rapporteur, m’a fait part de commentaires précieux qui ont beaucoup contribué à améliorer cette thèse. Dommage que le quiproquo n’ait pas duré plus longtemps...

Merci aux personnes du laboratoire qui m’ont accueilli et soutenu. Louis Granboulan a relu une des premières versions de ma thèse. Joëlle Isnard m’a bien aidé dans l’organisation de mes déplacements et la réception du jury.

Enfin, je tiens à remercier tous ceux qui m’ont soutenu durant ces années, qui m’ont encouragé sans jamais me critiquer, ou qui m’ont aidé à préparer ma soutenance. J’espère qu’ils se reconnaîtront. iv

Résumé

L’interprétation abstraite est un cadre très général permettant l’utilisation sûre d’approximations d’un point de vue sémantique. Cette théorie est utilisée principalement dans l’analyse de programmes et permet la conception de programmes calculant automatiquement les propriétés de programmes. Ces analyseurs s’appuient sur des structures de données permettant de représenter ces propriétés. Ces structures de données sont des objets fondamentaux de l’analyse, car elles déterminent la précision et la complexité de celle-ci. Les structures de données classiques peuvent être peu adaptées à cet usage, car elles ne sont pas conçues pour tirer avantage des possibilités d’approximation. C’est pourquoi différentes représentations ont été développées spécifiquement pour l’interprétation abstraite. Par exemple, dans le cas des ensembles d’entiers, on peut utiliser une représentation basée sur l’utilisation des polyhèdres convexes, ou encore sur l’utilisation de congruences.

Les arbres sont des objets fondamentaux en informatique : ils sont présents dès que l’on considère des structures non linéaires. Les structures classiques pour représenter les ensembles d’arbres sont les automates d’arbres. On en utilise parfois des variantes, comme les grammaires d’arbres, mais ces variantes sont souvent moins efficaces à cause de l’introduction de noms de variables. Les automates d’arbres ont une complexité élevée, surtout les automates d’arbres infinis, et les ensembles d’arbres qu’ils permettent de représenter sont limités : ils n’autorisent pas la représentation d’ensembles de la forme f(a^{n}, b^{n}, c^{n}), n ∈ ℕ qui présentent des relations entre les sous-arbres.

Le résultat principal de cette thèse est une nouvelle représentation des ensembles d’arbres plus expressives que les automates d’arbres, adaptée aux techniques d’approximation et mettant en œuvre un principe de partage permettant une meilleure compacité et une meilleure efficacité des algorithmes associés. Cette représentation, les schémas d’arbres, permet de décrire des ensembles contenant des arbres infinis et avec une notion de relation entre les sous-arbres. Ce résultat est obtenu par extraction d’une structure, le squelette du schémas, qui exprime le partage préfixe maximum de l’ensemble. Cette structure est ensuite enrichie de liens représentés par des relations. Cela permet donc d’extraire l’aspect relationnel des ensembles d’arbres.

Puisque les ensembles représentés peuvent être infinis, et les arbres eux-mêmes infinis, il a fallu représenter aussi des relations infinies. Ces relations sont très importantes dans les schémas d’arbres : ce sont elles qui déterminent leur pouvoir expressif, et ce sont aussi les facteurs prédominants de leur complexité. La façon la plus efficace connue de représenter des relations finies est l’utilisation de BDDs. Les représentations de relations infinies développées dans cette thèse sont des extensions des BDDs avec un pouvoir expressif comparable aux ensembles de mots infinis de Büchi. Une nouvelle classe de relations infinies permettant une représentation efficace a été définie. Elle permet l’approximation précise d’un grand nombre de relations infinies. Elle permet entre autres l’expression d’ensembles équitables.

La séparation entre l’aspect structurel et l’aspect relationnel des ensembles d’arbres a permis d’envisager l’introduction de nouvelles contraintes dans les schémas d’arbres. Ces contraintes sont basées sur l’utilisation de compteurs. Les compteurs peuvent être utilisés pour déterminer automatiquement quelles boucles grossissent et de quelle façon elles grossissent à l’intérieur d’une séquence de schémas d’arbres. Cette information est utile pour concevoir des outils d’approximation supplémentaires.

Les schémas d’arbres sont donc de nouvelles structures de données disponibles en interprétation abstraite qui devraient permettre des analyses plus fines et plus rapides.

Contents

1 Introduction 1

1.1 Motivations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.1.1 Abstract Interpretation . . . . . . . . . . . . . . . . . . . . 1 1.1.2 Representation of Sets of Trees . . . . . . . . . . . . . . . 1

1.2 Goal of the Thesis . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Guiding Ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.3.1 High Expressive Power for the Representation . . . . . . . 2 1.3.2 Uniqueness . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3.3 Formal Definitions . . . . . . . . . . . . . . . . . . . . . . 3

1.4 Overview of the Thesis . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Preliminary Definitions 5

2.1 Basic Notations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1.1 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1.2 Orderings . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.1.3 Equivalences . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.2 Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 2.2.1 Orderings on Words . . . . . . . . . . . . . . . . . . . . . 7 2.2.2 Infinite Words . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2.3 Automata on Words . . . . . . . . . . . . . . . . . . . . . 7

2.3 Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3.1 Arity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3.2 Subtrees . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3.3 Infinite Trees . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3.4 Substitutions in Trees . . . . . . . . . . . . . . . . . . . . 9 2.3.5 Recursive Functions on Trees . . . . . . . . . . . . . . . . 10 2.3.6 Representation of a Tree . . . . . . . . . . . . . . . . . . . 10

2.4 Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4.1 Multi-edge Graphs . . . . . . . . . . . . . . . . . . . . . . 12 2.4.2 Walking Through a Graph . . . . . . . . . . . . . . . . . . 12

2.5 Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.5.1 Projection . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.5.2 Support Set of a Relation . . . . . . . . . . . . . . . . . . 13 2.5.3 Boolean Operations on Relations . . . . . . . . . . . . . . 13 2.5.4 Projection According to a Value . . . . . . . . . . . . . . . 14 2.5.5 Independent Decomposition . . . . . . . . . . . . . . . . . 14

2.6 Abstract Interpretation . . . . . . . . . . . . . . . . . . . . . . . . 14 2.6.1 Soundness and Galois Connections . . . . . . . . . . . . . 14 2.6.2 Fixpoints and Iteration Sequences . . . . . . . . . . . . . . 15 2.6.3 Dynamic Approximation of Fixpoints . . . . . . . . . . . . 16

3 Sharing Regular Trees 17

3.1 Classic Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.1 General Framework . . . . . . . . . . . . . . . . . . . . . . 17 3.1.2 Structures for the Trees . . . . . . . . . . . . . . . . . . . 18 3.1.3 Finite Trees . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.2 Sharing Strongly Connected Graphs . . . . . . . . . . . . . . . . . 19 3.2.1 Maximal Sharing Strongly Connected Graphs . . . . . . . 19 3.2.2 Keys of Strongly Connected Graphs . . . . . . . . . . . . . 22

3.3 Regular Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.3.1 Informal Presentation . . . . . . . . . . . . . . . . . . . . . 24 3.3.2 Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.3.3 More Remarks to Understand the Algorithm . . . . . . . . 27 3.3.4 Proof of the Algorithm . . . . . . . . . . . . . . . . . . . . 30 3.3.5 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.4 Algorithms on Shared Regular Trees . . . . . . . . . . . . . . . . 35 3.4.1 Easy Algorithms . . . . . . . . . . . . . . . . . . . . . . . 35 3.4.2 Generic Memoizing Algorithms . . . . . . . . . . . . . . . 36 3.4.3 Recursive Construction . . . . . . . . . . . . . . . . . . . . 39 3.4.4 Complexity Issues . . . . . . . . . . . . . . . . . . . . . . . 40

4 Representation of Relations 43

4.1 Definitions and Common Structures . . . . . . . . . . . . . . . . . 44 4.1.1 Equivalent Entries . . . . . . . . . . . . . . . . . . . . . . 44 4.1.2 Isomorphic Relations . . . . . . . . . . . . . . . . . . . . . 46 4.1.3 Regular Relations . . . . . . . . . . . . . . . . . . . . . . . 47

4.2 Decision Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.2.1 MDD for Finite Relations . . . . . . . . . . . . . . . . . . 51 4.2.2 Regular Infinite Relations . . . . . . . . . . . . . . . . . . 54 4.2.3 ω-deterministic Relations . . . . . . . . . . . . . . . . . . . 60 4.2.4 MDD with Large Sets of Choice . . . . . . . . . . . . . . . 63

4.3 Algorithms on ω-deterministic Relations . . . . . . . . . . . . . . 64 4.3.1 Canonicity of the representation . . . . . . . . . . . . . . . 64 4.3.2 Entry Names . . . . . . . . . . . . . . . . . . . . . . . . . 73 4.3.3 Basic Algorithms . . . . . . . . . . . . . . . . . . . . . . . 75 4.3.4 Intersection . . . . . . . . . . . . . . . . . . . . . . . . . . 77

4.3.5 Approximation . . . . . . . . . . . . . . . . . . . . . . . . 79 4.4 Other Representations . . . . . . . . . . . . . . . . . . . . . . . . 83

4.4.1 A Set of Vectors is a Set of Trees . . . . . . . . . . . . . . 83 4.4.2 Exact Relations . . . . . . . . . . . . . . . . . . . . . . . . 83

4.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

5 Tree Schemata 85

5.1 Different Approaches . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.1.1 Representations Based on Automata . . . . . . . . . . . . 85 5.1.2 Representations Based on Expressions . . . . . . . . . . . 87 5.1.3 Tree Schemata . . . . . . . . . . . . . . . . . . . . . . . . 88

5.2 The Skeleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 5.2.1 A Set of Trees is a Tree . . . . . . . . . . . . . . . . . . . . 88 5.2.2 Definition of the Set of Tree Schema Skeletons . . . . . . . 91 5.2.3 The Choice Nodes . . . . . . . . . . . . . . . . . . . . . . 92

5.3 The links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 5.3.1 The Choice Space . . . . . . . . . . . . . . . . . . . . . . . 93 5.3.2 Links as Relations . . . . . . . . . . . . . . . . . . . . . . 94 5.3.3 Links are Local . . . . . . . . . . . . . . . . . . . . . . . . 94 5.3.4 The Names of the Links . . . . . . . . . . . . . . . . . . . 96 5.3.5 Sharing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 5.3.6 Set Represented by a Tree Schema . . . . . . . . . . . . . 98 5.3.7 Restrictions on the Links . . . . . . . . . . . . . . . . . . . 101

5.4 The Set of Tree Schemata, T S(F) . . . . . . . . . . . . . . . . . . 106 5.4.1 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 5.4.2 Description of the Sets of Trees Representable by Tree

Schemata . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

5.5 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 5.5.1 Expressive Power . . . . . . . . . . . . . . . . . . . . . . . 109 5.5.2 Strong Determinism . . . . . . . . . . . . . . . . . . . . . 110 5.5.3 Sources of Non-Uniqueness . . . . . . . . . . . . . . . . . . 110

6 Algorithms on Tree Schemata 113 6.1 Auxiliary Informations on the Links . . . . . . . . . . . . . . . . . 113 6.2 Inclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

6.2.1 Inclusion of Skeletons . . . . . . . . . . . . . . . . . . . . . 114 6.2.2 Inclusion of Tree Schemata . . . . . . . . . . . . . . . . . . 116

6.3 Intersection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 6.3.1 Intersection of Skeletons . . . . . . . . . . . . . . . . . . . 119 6.3.2 Intersection of Tree Schemata . . . . . . . . . . . . . . . . 121

6.4 Union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 6.4.1 Union of Skeletons . . . . . . . . . . . . . . . . . . . . . . 125 6.4.2 Union of Tree Schemata . . . . . . . . . . . . . . . . . . . 130 6.5 Projection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

6.5.1 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 6.5.2 Projection of Skeletons . . . . . . . . . . . . . . . . . . . . 131 6.5.3 Projection of Tree Schemata . . . . . . . . . . . . . . . . . 131

6.6 Meta Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 6.7 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

7 Tree Schemata with Counters 135

7.1 New Entries for the Links . . . . . . . . . . . . . . . . . . . . . . 135 7.1.1 Tree Schemata on Labels and Variables . . . . . . . . . . . 136 7.1.2 Many Variables in a Link . . . . . . . . . . . . . . . . . . . 136 7.1.3 Variables on Infinite Domains . . . . . . . . . . . . . . . . 137

7.2 Interaction between Counters and Skeletons . . . . . . . . . . . . 137 7.2.1 Choice Node Counters . . . . . . . . . . . . . . . . . . . . 137 7.2.2 Labels as Abstract Operators . . . . . . . . . . . . . . . . 140 7.2.3 Counters as Labels . . . . . . . . . . . . . . . . . . . . . . 140

7.3 Finding Cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 7.3.1 Deciding When to Look for a Cycle . . . . . . . . . . . . . 141 7.3.2 Finding or Building a New Cycle . . . . . . . . . . . . . . 142 7.3.3 Maximal Folding . . . . . . . . . . . . . . . . . . . . . . . 143

7.4 Modified Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . 143 7.4.1 Global Information and Forgetting . . . . . . . . . . . . . 144 7.4.2 Inclusion and Loops . . . . . . . . . . . . . . . . . . . . . 144 7.4.3 Intersection and Counter Functions Merging . . . . . . . . 145

7.5 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147

8 Tree Based Abstract Interpretations 149

8.1 Model of Logic Programs . . . . . . . . . . . . . . . . . . . . . . . 149 8.1.1 Syntax and Collecting Semantics . . . . . . . . . . . . . . 149 8.1.2 Approximation of the Model . . . . . . . . . . . . . . . . . 150 8.1.3 Comparison with Other Approaches . . . . . . . . . . . . . 153

8.2 Sets of Traces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 8.2.1 Flowchart Semantics . . . . . . . . . . . . . . . . . . . . . 154 8.2.2 Big-Step Semantics . . . . . . . . . . . . . . . . . . . . . . 155 8.2.3 Parallel Programs: Fairness . . . . . . . . . . . . . . . . . 157

8.3 Other Applications . . . . . . . . . . . . . . . . . . . . . . . . . . 159 8.3.1 Model Checking . . . . . . . . . . . . . . . . . . . . . . . . 159 8.3.2 Closure Analysis . . . . . . . . . . . . . . . . . . . . . . . 160

9 Conclusion 161 9.1 Main Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 9.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

9.2.1 Practical Usefulness . . . . . . . . . . . . . . . . . . . . . . 162 9.2.2 Negation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 9.2.3 Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

A List of Symbols and Conventions 163 A.1 Widely Used Mathematical Symbols . . . . . . . . . . . . . . . . 163 A.2 Conventions for Other Mathematical Symbols . . . . . . . . . . . 163 A.3 Sets and Operators Defined in the Thesis . . . . . . . . . . . . . . 164

A.3.1 Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 A.3.2 Tree Schemata . . . . . . . . . . . . . . . . . . . . . . . . 165

B Algorithms 167 B.1 Notations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 B.2 List of Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

Bibliography 173

Chapter 1

Introduction

1.1 Motivations

1.1.1 Abstract Interpretation

Abstract interpretation [CC77, Cou78, CC92b] is a formalized framework designed to deal with approximations, specially useful for the static analysis of programs. This framework is very general and can be applied to a great variety of problems. In fact, a lot of works have been achieved, either based on abstract interpretation or trying to improve different parts of the framework. Because abstract interpretation is so general, there have been theoretical advances and researches to improve the possible applications of abstract interpretation.

When we try to apply abstract interpretation techniques, we must consider the objects manipulated during the process. This question is crucial to the implementation because it determines the accuracy and the complexity of the computation. But in many cases, the objects that are available from classical computer science may be inadequate, because they don’t take advantage of the possibility of approximation. Thus some specific objects and their manipulation have been defined to be used in abstract interpretation. Usually, they cannot represent any possible object but they come with approximation mechanisms. If we consider for example sets of numbers or tuples of numbers, Patrick Cousot and Nicolas Halbwachs presented in [CH78] a representation based on convex polyhedra. Philippe Granger proposed the use of congruences in [Gra89].

1.1.2 Representation of Sets of Trees

Finite and infinite trees are present in a way or another in most parts of computer science. In [Knu97], Donald E. Knuth describes the trees as “the most important nonlinear structures that arise in computer algorithms”. They can be seen as the underlying structure of many different kind of objects such as words, graphs —provided we can distinguish a node [Eng94, EV94]—, and of course non linear data structures. In program semantics, they appear as control flow graphs or traces of execution. Even a set of trees can be seen as a tree.

Alas, representing sets of trees is difficult. In the case of finite trees, automata techniques can be implemented but they lack some natural approximation method. When it comes to infinite trees —a necessary step to represent graphs, for example— we can only find theoretical description of automata, but no realistic implementation is available. When someone needs sets of trees in an abstract interpretation, he will have to restrain his analysis to linear structures, such as in [Deu92], or to very crude approximations losing any relation between different parts of the trees as in [HJ90, Hei92].

1.2 Goal of the Thesis

The goal of this thesis is to provide a set of tools to manipulate sets of possibly infinite trees in abstract interpretation. The user of this set of tools should only care about basic operations over sets of trees, such as intersection, projection, etc. The set of tools would then take care of computing those operations using an efficient internal representation of sets of trees.

As representing sets of possibly infinite trees is a difficult task, some operations on sets of trees will require the use of automatic approximation. In order to make things easier for the user, operations of explicit approximation will be provided, as well as algorithms to decide whether there is an approximation that seems to suit the current iteration on the set of trees. In order to give the possibility to trade between accuracy and complexity options to force more automatic approximations should be available.

1.3 Guiding Ideas

In order to fulfill our objectives, the representation of sets of trees is to combine two main qualities: efficiency and expressive power.

1.3.1 High Expressive Power for the Representation

All experiments in abstract interpretation indicate that the later we approximate the more accurate the final result. In order to approximate as late as possible, automatic approximation should be reduced to a minimum. It means that for every representation used in an abstract interpretation, we must try be able to represent the largest set of object possible. In this thesis, we try in every area of the representation to go as far as possible in the expressive power without, hopefully, jeopardizing the efficiency of the representation.

1.3.2 Uniqueness

The efficiency of a representation lies in its compactness and in the complexity of the algorithms using the objects. This is a matter of balance, so we cannot use algorithms from data compression for example, because, although the compactness of compressed objects is very good, their manipulation would be very difficult. The notion of uniqueness, on the other hand, seems to deal with every aspect of the efficiency of the representation.

The representation of an object is said to be unique if no other representation represents this object in the same frame. A typical example of non-uniqueness is the use of variable names: they produce at least as many possible representation for a given object as the number of possible variable names. Striving after the uniqueness of a representation is moving towards a better compactness of this representation. Actually, if it is not unique, then the representation contains some redundancy.

The problem with uniqueness is that it may require a lot of computation to find a kind of normal form (the minimal state representation when possible). Our argument is that, in most case, the gain in most algorithms makes up for this overhead. It is particularly true if we need equality testing or emptiness testing.

1.3.3 Formal Definitions

Because it deals with the essence of approximation from a very theoretical point of vue, abstract interpretation is a mathematical model. It is very well formalized, and this formal presentation of the model allows a very high confidence in its correctness and a genericity of the results. The drawback —or the advantage— is that any extension or application of abstract interpretation should be very formal too.

In our case, a formal definition is an advantage, because we have to deal with infinite structures and infinite behavior. Experience shows that in this case, informal presentation and intuitive proofs can lead to wrong results.

1.4 Overview of the Thesis

After this presentation, the thesis starts with a recall of basic mathematical background and the associated notations. The following fields are presented: words, trees, graphs, relations and abstract interpretation. If the reader is already familiar with one of these fields, he can skip it and use the summary of the notations in appendix A when necessary.

Chapter 3 gives the basic algorithms on regular trees that are extended later to insure good sharing properties.

Chapter 4 studies the efficient representation of relations. It gives new classes of infinite relations that can be represented by decision diagrams. The expressive power of these relations is essential in the representation of sets of trees.

Chapter 5 describes the representation at the heart of the thesis, tree schemata. Tree schemata and their use of relations are formally described. In the next chapter, some algorithms on tree schemata are presented as a guideline to use them.

Chapter 7 presents some extensions to basic tree schemata. This extensions take advantage of the way relations are used in tree schemata. The most useful extension is the incorporation of loop counters which allow more precise approximation by numerical analysis.

Finally, chapter 8 presents briefly some possible applications of tree schemata and the last chapter concludes.

Preliminary Definitions

In this chapter, we introduce some basic definitions over mathematical objects that will be used in the thesis. These presentations are quite succinct because most of them are very well-known in computer science. They are mainly given to set the notations over these objects. Most of these notations are summarized in appendix A.

2.1 Basic Notations

The set of natural numbers will be denoted ℕ. If n ∈ ℕ, then

[n] =^{def} {i ∈ ℕ | 0 ≤ i < n}

If, moreover, m ∈ ℕ,

[n, m[ =^{def} {i ∈ ℕ | n ≤ i < m}

The cartesian product of two sets E and F is denoted E × F. The cartesian product of a set family (E_{i})_{i∈I} is denoted ⨂_{i∈I} E_{i}.

2.1.1 Functions

Let E and F be two sets, and f ⊂ E × F. The set f is said to be a function, and we write f : E →F, if and only if ∀a ∈ E, there is at most one b in F such that <a, b> ∈ f. We write f(a) = b. We say that f is a function from E to F. The domain of f is denoted dom(f) =^{def} {a ∈ E | ∃b ∈ F, f(a) = b}. The image of f is denoted im(f) =^{def} {b ∈ F | ∃a ∈ E, f(a) = b}.

If f : E →E, the element x ∈ E is called a fixpoint of f if f(x) = x.

2.1.2 Orderings

Let E be a set. A partial ordering ≤ on E is a subset of E × E such that ∀a, b, c ∈ E, <a, a> ∈ ≤ (reflexivity), (<a, b> ∈ ≤ and <b, a> ∈ ≤)⇒ a = b (antisymmetry), and (<a, b> ∈ ≤ and <b, c> ∈ ≤) ⇒ <a, c> ∈ ≤ (transitivity). When using partial orderings, we use the infix notation: a ≤ b for <a, b> ∈ ≤.

Every partial ordering ≤ corresponds to a strict partial ordering denoted < defined as < =^{def} { <a, b> ∈ ≤ | a ≠ b}. A total ordering ≤ on E is a partial ordering on E such that ∀a, b ∈ E, a ≤ b or b ≤ a.

Let E be a set partially ordered by ≤. Let F ⊂ E. The element a ∈ E is an upper bound of F if ∀b ∈ F, b ≤ a. It is said to be the least upper bound of F, denoted lub_{≤}(F), if it is an upper bound of F, and for all b that is also an upper bound of F, a ≤ b. Note that lub_{≤}(F) is not always defined, but when it exists, it is unique. We define dually the greatest lower bound of F (glb_{≤}(F)).

A complete lattice is a set E and a partial ordering ≤ on E such that for all F ⊂ E, lub_{≤}(F) and glb_{≤}(F) exist.

2.1.3 Equivalences

Let E be a set. An equivalence ≡ on E is a subset of E × E such that ∀a, b, c ∈ E, <a, a> ∈ ≡ (reflexivity), <a, b> ∈ ≡ ⇔ <b, a> ∈ ≡ (symmetry), and (<a, b> ∈ ≡ and <b, c> ∈ ≡)⇒ <a, c> ∈ ≡ (transitivity). As for partial orderings, we use the infix notation: <a, b> ∈ ≡ is denoted a ≡ b.

Equivalences define equivalence classes. Let ≡ be an equivalence on E. The equivalence classes of ≡ are the sets in {{b | a ≡ b} | a ∈ E}. Note that equivalence classes cannot be empty because of the reflexivity property.

2.2 Words

Let A be a set of letters. Then A^{∗} is the set of finite words made of letters from A, and A^{+} the set of non-empty words over A. The empty word will be written ε. The word consisting of a single letter a of A is written a. If u and v are words over A, then their concatenation will be denoted u.v or uv. |u| is the length of u. |ε| = 0.

If (u_{i})_{i∈I} is a family of words with total ordering <_{I} on I, their concatenation following the order of their indexes is written ⨀_{i∈I}^{<_{I}} u_{i}. If I = ∅, then this is ε. This operation can be extended to families of sets of words in the following way:

L_{1}L_{2} =^{def} {u_{1}u_{2} | u_{1} ∈ L_{1}, u_{2} ∈ L_{2}}

If L ⊂ A^{∗}, we can define the set of all finite concatenations of elements of L, in any orders. This set is written L^{∗}. Formally,

L^{∗} =^{def} ⋃_{i∈ℕ}{⨀_{j<i}^{<} u_{j} | ∀j < i, u_{j} ∈ L}

2.2.1 Orderings on Words

There is a canonical ordering on A^{∗}, the prefix relation ≺ defined as:

∀u, v ∈ A^{∗}, u ≺ v ⇔^{def} ∃u_{1} ∈ A^{+}, v = uu_{1}

A subset M of A^{∗} is said to be prefix closed if and only if ∀u ∈ M, ∀v ∈ A^{∗}, v ≺ u ⇒ v ∈ M.

An ordering <_{A} on A can be extended to A^{∗} by means of the alphabetic ordering, ≺_{A}^{∗} defined as:

∀u, v ∈ A^{∗}, u ≺_{A}^{∗} v ⇔ u ≺ v ∨ ∃w ∈ A^{∗}, a, b ∈ A, wa ⪯ u ∧ wb ⪯ v ∧ a <_{A} b

If <_{A} is total, then ≺_{A}^{∗} is total.

2.2.2 Infinite Words

The set of infinite words made of letters from A is written A^{ω}. An infinite word can be seen as a function from ℕ to A, so we write u(i) for the i^{th} letter of u. A^{∞} =^{def} A^{∗} ∪A^{ω}. A subset of A^{∞} is also called a language. The prefix ordering can be extended to A^{∞} by ∀u ∈ A^{∗}, ∀v ∈ A^{∞}, u ≺ v ⇔ ∃u_{1} ∈ A^{∞}, v = uu_{1}. Using this ordering, we can define the infinite closure of sets of finite words (the same as the adherence of [BN80]). The infinite closure of the set of words L ⊂ A^{∗}, written \overrightarrow{L} is defined by:

\overrightarrow{L} =^{def} \{x ∈ A^{ω} | \{u ∈ L | u ≺ x\} is infinite\}

If L ⊂ A^{∗}, we define L^{ω} as \overrightarrow{L^{∗}}. An infinite word w is said to be ultimately periodic if there is a finite word u and a finite word v such that w = u.v^{ω}.

2.2.3 Automata on Words

Let A be a set of letters. We can define many different automata to recognize sets of finite or infinite words of A. All these automata have a common structure, which we call an automaton in general, that is a set of states, Q and a transition set E ⊂ Q × A × Q. An automaton is said to be finite if E is finite. Two transitions (p, a, q) and (p′, a′, q′) are said to be consecutive if q = p′. A path is a sequence of consecutive transitions. The label of a path is the sequence of the letters of its transitions. The first state of the first transition of a path is called its origin. If the path is finite, the last state of its last transition is called its end. If the path p is infinite, we write In(p) the set of states that appear in an infinite number of transitions of p. This set is called the set of infinitely repeated states of p.

A Büchi automaton [Büc60] is a finite automaton plus a set of initial states I and a set of final states F. We write A = (Q, E, I, F). A recognizes any infinite word that is the label of a path of A with origin in I and such that there is a state of F in the set of infinitely repeated states of the path. We write L^{ω}(A) this set of infinite words. A Büchi automaton can be used to recognize a set of finite words: L^{∗}(A) is the set of words labeling path of A with origin in I and end in F.

2.3 Trees

Let F be a set of labels. A tree t labeled by F is a function of pos(t) → F such that pos(t) is a prefix closed non-empty subset of ℕ^{∗}. The domain of t, pos(t), defines the shape of the tree. The elements of pos(t) can also be called the paths of the tree. t(ε) is called the root of t.

2.3.1 Arity

The set of labels F is said ranked if it is associated with an arity function Ar_{F} : F → ℕ. A tree t labeled by F is said to respect the arity of F whenever the following property holds:

∀p ∈ pos(t), ∀n ∈ ℕ, p.n ∈ pos(t) ⇔ n < Ar_{F} (t(p))

In this thesis, every tree labeled by a ranked set will be assumed to respect its arity. The set of trees labeled by the ranked set F (and respecting its arity) will be denoted H(F).

2.3.2 Subtrees

Let p ∈ pos(t). The subtree of t rooted at p, denoted t_{[p]}, is defined by:

pos(t_{[p]}) =^{def} {q ∈ ℕ^{∗} | pq ∈ pos(t)}

∀q ∈ pos(t_{[p]}), t_{[p]}(q) =^{def} t(pq)

A subtree is a child of t if there is an i ∈ ℕ and this subtree is t_{[i]}.The tree t is a father of this tree.

The notion of subtrees defines an ordering on H(F), denoted ⋖. The formal definition of this ordering is:

∀u, t ∈ H(F), u ⋖ t ⇔^{def} ∃p ∈ pos(t), u = t_{[p]}

If a u ⋖ t or t ⋖ u we say that u and t are parent .

The set of subtrees of a tree t is denoted Subtrees(t).

2.3.3 Infinite Trees

A tree t is said to be infinite as soon as pos(t) is infinite.

A tree t is regular [Tho90] if and only if the number of its distinct subtrees is finite (or Subtrees(t) is finite). If t respects an arity function, then it is the case if and only if:

∃N ∈ ℕ, ∀p ∈ pos(t), |p| > N ⇒ ∃q, q_{1} ∈ pos(t), q ≺ q_{1} ⪯ p and t_{[q]} = t_{[q_{1}]}

Proof: Suppose t is regular. We just have to take N the number of distinct subtrees of t. Conversely, if t satisfies the formula, we show that whatever t_{[p]}, ∃q ∈ pos(t) such that |q| ≤ N and t_{[q]} = t_{[p]}. Thus, the number of distinct subtrees of t is bounded by n^{N}, where n is the maximum arity of the labels. □

2.3.4 Substitutions in Trees

We present different notions of substitution in trees. Let t and u be trees and p a path of pos(t). The substitution of t by u at position p, denoted t_{{p}\u} is the tree v defined by:

pos(v) =^{def} {q ∈ pos(t) | p ⊀ q} ∪ {pq | q ∈ pos(u)}

v(q) =^{def} if ∃r ∈ pos(u), q = pr then v(r)
else t(q)

If now P is a set of paths, the substitution of t by u at positions P, denoted t_{P \u} is the tree v defined by:

pos(v) =^{def} {q ∈ pos(t) | ∀p ∈ P, p ⊀ q} ∪ ⋃_{p∈P} {pq | q ∈ pos(u)}

v(q) =^{def} if ∃r ∈ pos(u), ∃p ∈ P, q = pr then v(r)
else t(q)

If s is another tree, the substitution of s by u in t, denoted t[s\u] is defined by:

t[s\u] =^{def} t_{{p∈pos(t) | t_{[p]}=s}\u}

We can also define substitutions with respect to a label f, which replaces every node labeled by f by u.

2.3.5 Recursive Functions on Trees

Basically, trees are recursive, so most functions defined on trees will be recursive. The recursive definition can be written as a fixpoint equation of the form:

f(t) = F (t(ε), ⨂_{i<Ar_{F} (t(ε))} f (t_{[i]}))

Depending on F and its domain, this equation can have many solutions or even no solution at all. We know from [Tar55] that if F is monotone on a complete lattice then the set of fixpoints of F is non-empty and is a complete lattice. In that case, the usual convention is to consider the least fixpoint of F as the semantics of the equation.

In the case of an infinite tree though, this convention will often lead to uninteresting results, that is the image of any infinite trees by the least fixpoint of F is the bottom of the lattice. Thus the convention we follow in this thesis is to consider the greatest fixpoint as the semantics of the equation, including for finite trees.

2.3.6 Representation of a Tree

Finite trees have been very commonly used in computer science for years. It is not surprising that a very efficient way of representing trees is known and widely used (see for example [Knu97], Sect. 2.3). This method merely consists in representing a tree as a set of paths associated with their labels and then share the prefix parts of the paths. Thus, a tree is represented by its root and by arrows associated with each possible suffix of ε, starting from the root and pointing towards representations of the subtrees corresponding to the suffix. When it comes to representing objects, an illustrated example is often easier to understand than an exhaustive explanation:

t_{1} = \{ \begin{matrix}ε & → & f \\ 0 & → & g \\ 00 & → & a \\ 1 & → & f \\ 10 & → & a \\ 11 & → & g \\ 110 & → & a \end{matrix} will be represented by [figure: f; 0; 1; g; 0; f; 0; 1; a; a; g; 0; a]

Usually, the values associated with the arrows are omitted. The convention is that the arrows are ordered from left to right according to their values. Even the arrows can be replaced by mere lines, with the convention that the tree is read top-down .

The qualities of this representation lie in its simplicity and in its ease of use. Most algorithms just go through the representation using local informations only.

This representation is often easily improved by sharing the end of the paths (see [AHU83] for example). In fact, a part of the path can be shared if its labels can be shared too. This amounts to share the common subtrees. At the expense of the maintenance of a global information (the set of already encountered subtrees), this technique allows an appreciable gain of space and time. In our example,

t_{1} = [figure: f; 0; 1; g; 0; f; 0; 1; a; a; g; 0; a] would be represented by [figure: f; 0; 1; g; 0; f; 0; 1; a]

Moreover, this optimization allows for a very natural representation of infinite regular trees [Col82]. Thus:

t_{2} = \{ \begin{matrix}(10)^{∗} & → & f \\ (10)^{∗}0 & → & a \\ 1(01)^{∗} & → & g \end{matrix} will be represented by [figure: f; 0; 1; a; g; 0]

The problem with this representation is that classical techniques for sharing in finite trees do not apply to infinite trees. In this thesis, a new technique has been devised that allows this representation to be canonical. It is described in length in chapter 3.

Other optimizations are possible, but the added complexity seems too heavy for a generic use of the trees.

In the sequel, a generic tree from H(F) will be denoted [figure: f; t_{0}; t_{n−1}] , where f ∈ F

is the root of the tree, n is the arity of f and (t_{i})_{i<n} are the children of the root.

2.4 Graphs

A directed graph G is a set of nodes G^{N} and a set of edges G^{E} ⊂ G^{N} × G^{N}. The empty graph (i.e. G^{N} = ∅) is denoted ∅^{G}. A finite Graph is a graph with a finite set of nodes. A path from the node N to the node M of G^{N} is a word over G^{E} such that the first letter of the word is of the form (N, N′), the last letter of the word, (M′, M), and each consecutive letter of the word, (N_{1}, N_{2})(N_{2}, N_{3}). A directed graph is said to be strongly connected if and only if, for all nodes N and M of the graph, there is a path of the graph from N to M. If p is a path from N to M, we write N.p =^{def} M.

A symmetric graph^{1} is a graph whose set of edges is symmetric. That is G is symmetric if and only if ∀(N, M) ∈ G^{E}, (M, N) ∈ G^{E}. The underlying symmetric graph of a directed graph is the graph with the same set of nodes and with a set of edges defined by: if (N, M) is an edge of G^{E}, then (N, M) and (M, N) are edges of the underlying symmetric graph of G. A graph is said to be connected if and only if its underlying symmetric graph is strongly connected.

A graph is said to be labeled if there is a function from its set of nodes to a set of labels.

A subgraph H of a graph G is a graph such that H^{N} ⊂ G^{N} and H^{E} = {(N, M) ∈ G^{E} | N and M ∈ H^{N}}.

2.4.1 Multi-edge Graphs

A multi-edge graph G is a set of nodes G^{N}, a set of edges names G^{ν} and a set of edges G^{E} ⊂ G^{N} ×G^{N} ×G^{ν}. The underlying directed graph of a multi-edge graph is the directed graph defined by G^{N} and G^{E} where we forget the third component of the edges. A multi-edge graph is strongly connected (respectively connected) if and only if its underlying directed graph is strongly connected (respectively connected). A path of a multi-edge graph is a word over its set of edges such that when forgetting the third component of its letters, we obtain a path of the underlying directed graph. The word over the set of edges names obtained from a path of the graph is called the label of the path. If N is a node of a multi-edge graph, w a word over the set of edges names, we write N.w for the set of nodes M such that w is the label of a path from N to M.

2.4.2 Walking Through a Graph

Many algorithms on graphs proceed by “walking through” the graph, that is they go from nodes to nodes of the graphs, following the edges. The most popular way of going through a graph is the depth first search [Tar72]. Whatever the way of going through a graph, some common notions arise from the notion of visiting nodes sequentially. The root of a subgraph of the graph analyzed by the algorithm is the first node of the subgraph visited by the algorithm. The return edges of the graph are those edges that go from a node N visited by the algorithm to a node that is already visited when it reaches N.

2.5 Relations

Let I be a set of indexes, and (E_{i})_{i∈I} a set family. A relation R on this family is a subset of ⨂_{i∈I} E_{i}, the cartesian product of the family. The elements of I are also called the entries of the relation.

1Sometimes, a symmetric graph is said to by simply a graph, as opposed to directed graphs.

2.5.1 Projection

Let e ∈ ⨂_{i∈I} E_{i}. If I = ∅, e is denoted <>. If I ≠ ∅, then let j ∈ I. The projection of e according to its j^{th} component is denoted e_{(j)}. In the same way, if R is a subset of ⨂_{i∈I} E_{i}, its projection according to its j^{th} component is denoted R_{(j)}:

R_{(j)} =^{def} {x ∈ E_{j} | ∃e ∈ R, x = e_{(j)} }

Let J ⊂ I. The projection of e according to J is denoted likewise by e_{(J)}. In the same way,

R_{(J)} =^{def} {x ∈ ⨂_{j∈J} E_{j} | ∃e ∈ R, x = e_{(J)}}

Dually, we will write e_{(∁J)} for e_{(I\J)}, as I is known from e.

2.5.2 Support Set of a Relation

Let R be a relation on (E_{i})_{i∈I}. The set family (F_{i})_{i∈I} is called the support set of R if and only if R ⊂ ⨂_{i∈I} F_{i} and ∀i ∈ I, ∀x ∈ F_{i}, ∃e ∈ R, e_{(i)} = x. The support set of a relation R is denoted Support(R). It is unique, as

Support(R) = ⨂_{i∈I} {e_{(i)} | e ∈ R}

A relation is said to be square if it is equal to its support set.

2.5.3 Boolean Operations on Relations

Let R be a relation and D ⊃ Support(R). The negation of R with respect to D is defined by:

¬_{D}R =^{def} {e ∈ D | e ∉ R}

When D is clear from the context, it can be omitted.

Let R and S be two relations. Let R be a relation on ⨂_{i∈I} E_{i} and S on

⨂_{i∈J} F_{j}. We define extend(R, S) =^{def} ⨂_{i∈I∪J} E_{i} ∪ F_{i} with E_{i} = ∅ if i ∉ I and

F_{i} = ∅ if i ∉ J. Then:

R_{1} ∧ R_{2} =^{def} {e ∈ extend(R, S) | e_{(I)} ∈ R and e_{(J)} ∈ S}

R_{1} ∨ R_{2} =^{def} {e ∈ extend(R, S) | e_{(I)} ∈ R or e_{(J)} ∈ S}

2.5.4 Projection According to a Value

Let J ⊂ I. Let e ∈ ⨂_{i∈J} E_{i}. Let R be a relation on (E_{i})_{i∈I}. The projection ^{2} of R according to e is the relation R_{:J=e} defined by:

R_{:J=e} =^{def} {x ∈ ⨂_{i∈I\J} E_{i} | ∃y ∈ R, y_{(∁J)} = x ∧ y_{(J)} = e}

In the case where J = {j}, we can write R_{:j=e} =^{def} R_{:{j}=e}. If J is clear from the context, we write R(e) for R_{:J=e}.

If there is a family (F_{j})_{j∈K} isomorphic to (E_{i})_{i∈J}, and the isomorphism σ is clear from the context, we will write R_{:J=e} for R_{:J=σ(e)}.

The set of all possible projections according to a value of R is defined by

AllProj(R) =^{def} {R_{:J=e} | J ⊂ I and e ∈ ⨂_{i∈J} E_{i}}.

2.5.5 Independent Decomposition

Let I = I_{1} ∪ I_{2} and I_{1} ∩ I_{2} = ∅. A relation R can be independently decomposed in R_{(I_{1})} and R_{(I_{2})}, written R = R_{(I_{1})} ⊼ R_{(I_{2})}, if and only if:

∀e ∈ ⨂_{i∈I} E_{i}, e ∈ R ⇔ (e_{(I_{1})} ∈ R_{(I_{1})} ∧ e_{(I_{2})} ∈ R_{(I_{2})})

2.6 Abstract Interpretation

The way abstract interpretation deals with semantic approximations ([Cou78, CC92b, Cou96]) is through the use of semantic domains and the relationship between them. Given two semantics, one is called the concrete semantics and the other one the abstract semantics which is an approximation of the concrete one. In the case of program analysis, the most concrete semantics is the standard semantics which describes all the possible behaviors of programs. A first approximation is the collecting semantics which contains the behaviors of interest. Thus, when comparing those two semantics, the standard semantics is the concrete one, and the collecting semantics the abstract one. Other more abstract semantics may be introduced, compared to which the collecting semantics will be the concrete semantics.

2.6.1 Soundness and Galois Connections

The properties of the different semantics are taken from sets called semantic domains. So we have a concrete semantic domain P^{♭} and an abstract semantic domain P^{♯}. The most basic way of describing the relationship between the concrete and the abstract semantics is the soundness relation, S, a relation on P^{♭} × P^{♯}. <c, a> ∈ S means that a is a sound approximation of c.

2This is also called cofactor in [BHMSV84].

Because we can have many sound approximation for a given property, we need to know more about these approximations, about their accuracy. This information is given by a partial ordering on the properties, the approximation ordering, denoted ≤^{♭} for the concrete domain, and ≤^{♯} for the abstract one. The approximation ordering must be compatible with the soundness relation: if <c, a> ∈ S, then, a≤^{♯}a′ ⇒ <c, a′ > ∈ S and c′≤^{♭}c ⇒ <c′, a> ∈ S. If there is a best abstraction for all concrete properties, then we can define an abstraction function, α which maps every concrete property to its best abstraction. Dually, if there is a greatest concrete property that is soundly approximated by a given a for any a, then there is a concretisation function γ.

If we have an abstraction function and a concretisation function, the relationship between the semantics can be described by a Galois connection:

\xymatrix{(P^{♭}, ≤^{♭}) \ar[r]_{α} & (P^{♯}, ≤^{♯}) \ar[l]_{γ}}

It means that (P^{♭}, ≤^{♭}) and (P^{♯}, ≤^{♯}) are partially ordered sets and that α : P^{♭} →P^{♯} and γ : P^{♯} → P^{♭} are such that: ∀a ∈ P^{♯}, ∀c ∈ P^{♭}, α(c)≤^{♯}a ⇔ c≤^{♭}γ(a). When α is surjective, we say that we have a Galois insertion.

2.6.2 Fixpoints and Iteration Sequences

The semantics of a program will often be described in terms of fixpoint of a semantic function, F. In order to insure the existence of such a fixpoint and to characterize it constructively ([CC79]), we suppose that the semantic domains are complete lattices for some partial orderings, the computation orderings, denoted ⊑^{♭} and ⊑^{♯}, which can be different from the approximation orderings. In this case, the least fixpoint of F^{♭} : P^{♭} →P^{♭}, a monotonic function for ⊑^{♭}, is the limit of the concrete iteration sequence:

F^{♭}^{β+1} =^{def} F^{♭} (F^{♭}^{β}) for all β ordinal
F^{♭}^{λ} =^{def} ⨆_{β<λ} F^{♭}^{β} where λ is a limit ordinal^{3}

What we try to compute, now, is a sound approximation of the least fixpoint of F^{♭}. It can be performed by the abstract iteration sequence over the abstract semantic function F^{♯} defined as: F^{♯}(a) =^{def} α(F^{♭}(γ(a)). Note that the least fixpoint of this function may be less precise than the abstraction of the least fixpoint of the concrete semantic function.

3Note that 0 is a limit ordinal. The least upper bound of the empty set is called the infinum of the lattice.

2.6.3 Dynamic Approximation of Fixpoints

The approximation of the concrete fixpoint by the abstract iteration sequence is a static approximation: we choose the abstract domain for a whole class of programs and it determines a priori the approximation. But the more precise these approximations, the more precise the result. In fact, experiments show that we get better results by choosing a more precise abstraction, which can lead to unpractical abstract iteration sequences, and then dynamically approximate the abstract iteration sequence. In abstract interpretation, this is performed by means of a widening operator.

A widening operator ▽ is a partial function: ℘(P^{♯})→P^{♯} such that ∀E^{♯} ⊂ P^{♯}, if ▽(E^{♯}) exists, ∀c ∈ P^{♭}, if ∃a ∈ E^{♯} such that <c, a> ∈ S, then <c, ▽E^{♯} > ∈ S.

The abstract iteration sequence with widening is:

F^{♯}^{↑β+1} =^{def} ▽ {F^{♯}^{↑β}, F^{♯} (F^{♯}^{↑β})} for all β ordinal
F^{♯}^{↑λ} =^{def} ▽ {F^{♯}^{↑β} | β < λ} where λ is a limit ordinal

The limit of the abstract iteration sequence with widening is a post fixpoint of F^{♯}. Thus it is a sound approximation of the least fixpoint of F^{♭}.

Sharing Regular Trees

Sharing common substructures is one of the leading ideas of efficient representations. It allows more compact representations and reuse of intermediate results. It is always involved in a way or another when representing infinite structures.

In general, sharing mechanisms use a dictionary mechanism to know whether a given substructure has already been encountered. These mechanisms only work for acyclic structures, as they need to start on a basic substructure that does not depend on some other substructure. So, these classical mechanisms would not apply to infinite regular trees. In this chapter, we present a new sharing mechanism that can be applied to any structure, even cyclic or connected structures.

We present first the classical sharing mechanism, that is used for finite trees. Then we present the new mechanism on strongly connected graphs, which are the essence of the difficulty in the sharing of infinite regular trees. This mechanism is then used together with the classical one to build the shared representation of any infinite regular tree. We end this chapter with the description of some algorithms on this representation.

3.1 Classic Sharing

3.1.1 General Framework

The main problem of sharing is to store intermediate substructures when building a structure in such a way that it is easy to know whether this substructure has been encountered already, and where it is stored. In order to do this, we use keys extracted from the structures, which are linked —through a dictionary mechanism— to the places where these structures are stored. For this process to be valid, the keys must properly discriminate between the structures. We suppose we have a structure (and substructure) universe, U. We describe the possible semantic equality between structures by an equivalence class ≡ on U. A key k is a valid key with respect to ≡ if:

∀u, v ∈ U, u ≡ v ⇔ k(u) = k(v)

In this way, if two structures are equivalent, they are stored in the same place: we keep just one representative of the equivalence class.

3.1.2 Structures for the Trees

In our paradigm, each regular tree t labeled on F is represented by a node of a labeled multi-edge graph G_{t}, with set of labels F and set of edges names ℕ. In the computer representation, the idea is that each node of those graphs corresponds to a memory location. Thus, the structure universe for the trees will be the nodes of such graphs. We define ≡_{t} the semantic equivalence on the nodes: N ≡_{t} M if and only if N and M represent the same tree.

Let N be a node of G_{t} with label f of arity Ar_{F} (f) = n. As defined in chapter 2, there are n edges from N to nodes N_{i} whose name is i in G_{t}^{E}. As

a shortcut, we will write N is labeled by [figure: f; N_{0}; N_{n−1}]. As the outgoing edges of a

particular node are uniquely determined by their names, there is at most one path labeled by a given word of ℕ^{∗} starting from a given node. Thus, if p is a word of ℕ^{∗} and N a node, N.p is either empty or a singleton. When it is a singleton, we will identify the singleton and its element.

Each node of the graph G_{t} represents a subtree of t. The graph is said to be of maximal sharing if the number of its nodes is the number of different subtrees of t. In fact, the graph G_{t} is part of a wider graph defined by a dictionary D, which links any subtree of t, and possibly of some other trees, to their nodes.

3.1.3 Finite Trees

In the case of finite trees, sharing is easy and widely used. The dictionary mechanism used to link the keys to the nodes is usually a hash table^{1} ([Knu73], Sect. 6.4). The keys are built as follows: first, sharing the leaves is easy, as the label of the node can be its key. Then, if the keys of (t_{i})_{i<n} are known, they

are linked to the nodes (N_{i})_{i<n}. The key for [figure: f; t_{0}; t_{n−1}] is (f, (N_{i})_{i<n}). Each time

a key is not present in the dictionary, it is associated with a new unique node, which is linked to the nodes (N_{i})_{i<n} by edges labeled by the corresponding i. The key defined by this mechanism is valid for ≡_{t} by induction on the height of the trees represented by the nodes. The graphs resulting of this building mechanism are of maximal sharing due to the validity of the keys.

1An interesting alternative to hashing is proposed in [CP95]. It is used in [KR96].

3.2 Sharing Strongly Connected Graphs

The main difference between the representations of finite and infinite (regular) trees, is that the graphs representing infinite trees contain strongly connected subgraphs. Finding the best representative and a key for such subgraphs is difficult, as we can’t use any recursion mechanism. We are thus forced to use non-local informations.

3.2.1 Maximal Sharing Strongly Connected Graphs

Equivalence of Graph Nodes

In order to achieve maximal sharing, we need to know constructively when two nodes represent the same tree. The following simple algorithm decides the equivalence of two nodes, which can be in the same graph or not. Let N and M be two graph nodes. The two nodes represent the same tree if and only if eqTree(N, M) holds true. A similar algorithm was already sketched in [Knu97] for “List structures” representing infinite trees (exercise 2.3.5-12).

eqTree(N, M):

S ← ← ← ∅

  return return return(eqTreeRec(N, M))
  eqTreeRec(N, M):
   if if if {N, M} ∈ S or or or N = M then then then return return return(true true true)

N is labeled by [figure: f; N_{0}; N_{n−1}] and M is labeled by [figure: g; M_{0}; M_{m−1}]

   if if if f = g then then then

S ← ← ← S ∪ {{N, M}}

     return return return(⋀_{i<n} eqTreeRec(N_{i}, M_{i}))

   else else else return return return(false false false)

Proof: N represents the tree u and M the tree v. If eqTree(N, M) is false, then there is a path p such that u(p) ≠ v(p) and so u ≠ v.

If u ≠ v, then there is a path p such that u(p) ≠ v(p). We try to prove that there is such a path that is reached by eqTree(N, M). If it is the case, then

eqTree(N, M) = false.

First we restrict the set of eligible paths to Acyclic(M, N) =^{def} {p | ∀q ≺ q′ ⪯ p, {M.q, N.q} ≠ {M.q′, N.q′}}. Any path that is reached by eqTree(N, M) is in Acyclic(M, N). Note that Acyclic(M, N) is a finite set, and so orders on this set are well founded. Let p be a path such that u(p) ≠ v(p) of minimal length. If p is not in Acyclic(M, N) then there is q ≺ q′ ⪯ p such that {M.q, N.q} = {M.q′, N.q′}. Let p = q′p_{1}. {u_{[q]}, v_{[q]}} = {u_{[q′]}, v_{[q′]}}, and u_{[q′]}(p_{1}) ≠ v_{[q′]}(p_{1}), so u_{[q]}(p_{1}) ≠ v_{[q]}(p_{1}) which means that u(qp_{1}) ≠ q(qp_{1}). But |qp_{1}| < |p|. Thus p is in Acyclic(M, N), and so Acyclic(M, N) contains at least one path such that u and v differ on that path.

Let p_{f} be the least path of Acyclic(M, N) for ≺_{ℕ}^{∗} such that u(p_{f}) ≠ v(p_{f}). If p_{f} is not reached by eqTree(N, M), then there is a q ≺ p_{f}, q ∈ Acyclic(M, N) such that, either N.q = M.q, or there is a q_{f} ≺_{ℕ}^{∗} q, q_{f} ∈ Acyclic(M, N) such that {N.q, M.q} = {N.q_{f}, M.q_{f}}. Let p_{1} be such that p_{f} = qp_{1}. In the first case, u_{[q]} = v_{[q]}, and so u_{[q]}(p_{1}) = v_{[q]}(p_{1}), which means that u(p) = v(p). In the second case, {u_{[q]}, v_{[q]}} = {u_{[q_{f}]}, v_{[q_{f}]}}. But q_{f} ≺_{ℕ}^{∗} q, and q_{f} ⊀ q because q ∈ Acyclic(M, N), so q_{f}p_{1} ≺_{ℕ}^{∗} q, and so q_{f}p_{1} ≺_{ℕ}^{∗} qp_{1}. By minimality of p_{f}, this means that q_{f}p_{1} ∉ Acyclic(M, N). So, there are r ≺ r′ ⪯ q_{f}p_{1} such that {M.r, N.r} = {M.r′, N.r′}. We take for r the least such path for ≺. Because q_{f} ∈ Acyclic(M, N), we cannot have both r and r′ prefix of q_{f}. Because p_{f} ∈ Acyclic(M, N), we cannot have both r and r′ suffix of q_{f}. Thus, r ⪯ q_{f} ≺ r′. Because p_{f} ∈ Acyclic(M, N), r ⊀ p_{f}, so r ⊀ q. Let q_{f}p_{1} = r′p_{2}. We have {u_{[rp_{2}]}, v_{[rp_{2}]}} = {u_{[p_{f}]}, v_{[p_{f}]}}, but this time rp_{2} ∈ Acyclic(M, N). As r ≺ q_{f}, r ⊀ q and q_{f} ≺_{ℕ}^{∗} q, r ≺_{ℕ}^{∗} q, and so rp_{2} ≺_{ℕ}^{∗} p_{f}. This contradicts the minimality of p_{f}. It proves that p_{f} is reached by eqTree(N, M) and so that eqTree(N, M) holds false. □

Finding the Graph of Maximal Sharing

A graph is of maximal sharing if and only if there is no couple of nodes, N_{1} and N_{2}, such that N_{1} ≠ N_{2} and N_{1} and N_{2} represent the same subtree. One way of finding the graph with maximal sharing equivalent to a given graph is to test every pair of nodes with eqTree, and each time the result of the algorithm is true, merge the two nodes. The eqTree algorithm is quite efficient in practice, despite its quadratic worst case complexity. But testing every pair of nodes leads to a quadratic complexity in any case. It is possible to be more efficient by using a partitioning algorithm based on the same principle as Hopcroft’s automata minimization algorithm [Hop71]. As the graph we partition represents a tree, it is not the most general problem, and so we present a simpler algorithm than [CC82].

The following algorithm modifies a graph into an equivalent graph (i.e. representing the same tree) with maximal sharing. The node G is a node of the graph to be modified. It is also a node of the resulting graph.

share(G):

Blocks is a function which associates with every integer the empty set

  BCount ← ← ← 0

D ← ← ← ∅

  initiateBlocks(G)

MaxArity is the maximal arity of the labels in the graph

  for for for i ← ← ← 0 to to to MaxArity − 1 do do do

a ← ← ← the block with the greatest number of incoming edges labeled by i

   ToTest(i) ← ← ← [BCount]\{a}
  while while while ∃ i such that ToTest(i) ≠ ∅ do do do

take a a out of ToTest(i)

   k ← ← ← BCount − 1
   for for for b ← ← ← 0 to to to k do do do
     Blocks(BCount) ← ← ← {N ∈ Blocks(b) | ∃M ∈ Blocks(a), N →^{i} M}
     if if if Blocks(BCount) ≠ ∅ and and and Blocks(BCount) ≠ Blocks(b) then then then
       for for for j ← ← ← 0 to to to MaxArity − 1 do do do

if if if the number of nodes leading (labeled by j) to the block b is greater than the number of nodes leading to the block BCount

            and and and b ∉ ToTest(j) then then then add b to ToTest(j)
        else else else add BCount to ToTest(j)
       BCount ← ← ← BCount + 1
  for for for a ← ← ← 0 to to to BCount − 1 do do do
   if if if |Blocks(a)| > 1 then then then
     if if if G ∈ Blocks(a) then then then N ← ← ← G
     else else else N is any node in Blocks(a)
     ∀M ∈ Blocks(a), M ≠ N do do do

every edge O →^{i} M is replaced by O →^{i} N remove M from G^{N}

initiateBlocks(N):
  if if if N ∉ D then then then

add N to D

N is labeled by [figure: f; N_{0}; N_{n−1}]

if if if ∃ i < BCount such that Blocks(i) contains a node labeled by f then then then

add N to Blocks(i)

   else else else

     Blocks(BCount) ← ← ← {N}
     BCount ← ← ← BCount + 1
   for for for i ← ← ← 0 to to to n − 1 do do do initiateBlocks(N_{i})

The algorithm first creates a partition (represented by Blocks) according to the labels of the nodes, and then progressively refines it until we get the coarsest congruence which refines the initial partition. With an adequate representation of the different sets involved, this algorithm yields an n log n worst case complexity. To compute efficiently the best partitions, we can compute the inverse of the graph (the sets of nodes which are linked to a given node) during the initial traversal of the graph. In practice, we also mark the blocks containing only one element, which cannot be refined further, and when a block contains two elements, we use the eqTree algorithm to refine it or merge the two elements (and possibly many other during the process). It seems to give faster results in practice.

Example:

share( [figure: k_{1}; 1; 0; k_{2}; 0; 1; k_{1}; 0; 1; k_{2}; 0; 1] ) = [figure: k_{1}; 0; 1; k_{2}; 0; 1]

♢

3.2.2 Keys of Strongly Connected Graphs

When using the graphs, it is efficient to use as a key of a node its label and the nodes of its neighbors, as for finite trees. The problem with strongly connected graphs is that some nodes must be chosen arbitrarily, because the nodes of a strongly connected graph all depend on each other. So the simple key that is the label of the node and the neighbor nodes is not enough to know if a given strongly connected graph have already been encountered elsewhere. So we give another key which is valid for strongly connected graphs with maximal sharing.

As we use the graphs to represent trees, we always distinguish one node of the graph, which is the root of the tree. This node may be any node of the graph, so we must compute a key for each node of a given graph, each of them linked to that node. The pointed graph is first transformed into a finite tree which then gives a unique key as defined above. The tree associated with a given node is labeled by the labels of G^{N} and elements of ℕ^{∗}. The arity of the elements of ℕ^{∗} is 0. The elements of ℕ^{∗} are the smallest (for ≺) paths without cycle that lead from the root to a given node. In a sense, they represent these nodes when we loop in the graph. The tree is computed through the following algorithm:

treeKey(N):

S is a partial function from G^{N} to ℕ^{∗} and dom(S) = ∅

  return return return(treeKeyRec(ε, N))
treeKeyRec(p, N):
  if if if N ∈ dom(S) then then then return return return(S(N))

add N → p to S

  for for for i ← ← ← 0 to to to n − 1 do do do t_{i} ← ← ← treeKeyRec(p.i, N_{i})

  return return return( [figure: f; t_{0}; t_{n−1}] )

Example: The keys of the two nodes of [figure: k_{1}; 0; 1; k_{2}; 0; 1] are respectively

[figure: k_{1}; ε; k_{2}; ε; 1; and; k_{2}; k_{1}; ε; 0; ε]

♢

As with any key, treeKey defines an equivalence. This equivalence relates isomorphic graphs, that is, graphs with a one to one node equivalence. This equivalence is included in ≡_{t} but is not equal to ≡_{t}. Thus, treeKey is not a valid key for ≡_{t} on any graph. But the point is that the two equivalences are indeed equal when restricted on graphs with maximal sharing:

Property 3.1 Whatever M and N, nodes of graphs with maximal sharing,

treeKey(M) = treeKey(N) ⇔ M ≡_{t} N .

Proof: The difficult point is M ≡_{t} N ⇒ treeKey(M) = treeKey(N). Suppose there are M and N nodes of graphs with maximal sharing such that M ≡_{t} N and treeKey(M) ≠ treeKey(N). Let t_{M} = treeKey(M) and t_{N} = treeKey(N). Because t_{M} ≠ t_{N}, there is a path p such that t_{M}(p) ≠ t_{N}(p). But if t_{M}(p) is a label of the graph, t_{M}(p) is the label of M.p, and the same holds for N. Because M ≡_{t} N, M.p and N.p have the same label, so at least one of t_{M}(p) or t_{N}(p) is not a label of the graphs (and so is in ℕ^{∗}), say t_{M}(p). It means there is a q ≺ p such that M.q ≡_{t} M.p. So N.q ≡_{t} N.p, but by maximal sharing of N, N.q and N.p must be the same node, and so t_{N}(p) = q = t_{M}(p). □

Because we can find an equivalent graph with maximal sharing for strongly connected graphs, we have a valid key mechanism for any strongly connected graph: we first apply share, then treeKey.

3.3 Regular Trees

3.3.1 Informal Presentation

We present the sharing of regular trees in algorithmic form. The idea of this algorithm is to use the classical sharing algorithm combined with the algorithm for strongly connected graphs. As any regular tree is not either finite or represented by a strongly connected graph, we must follow a kind of decomposition algorithm. This decomposition algorithm allows the procedure to be incremental.

First, we apply the classical algorithm as much as we can on finite subtrees of the tree we want to represent. Each finite subtree being associated with a node by the classical algorithm, they can be considered as a leaf of a new tree.

In this new tree, we eliminate the leaves by incorporating them into the labels of their fathers. This is coded by what we call partial keys, which are labels associated with the nodes of their children that are leaves of this tree. A partial key is considered as a new label of lesser arity than the label it is based on. This encoding in partial key gives another new tree with no finite subtree.

A tree with no finite subtree contains a subtree represented by a strongly connected graph. We associate a node with this subtree through a specific algorithm based on the algorithm devised in the preceding section. This algorithm is quite involved to efficiently reduce cycles. Then we can iterate on a new tree where this subtree is considered as a leaf labeled by its node. This new tree contains at least one finite subtree, so we can iterate our algorithm.

This process is iterated until we can build the key of the root. It is a finite process because at each iteration, we associate a node with a new subtree, and the number of distinct subtrees of a regular tree is finite by definition.

3.3.2 Algorithm

D is the dictionary linking keys to nodes of a graph representing a tree. A partial key k is a name name(k) ∈ F and a partial function from [Ar_{F} (name(k))] to nodes. D_{G} is the dictionary linking keys obtained by treeKey to nodes of the graph representing the strongly connected graph.

We suppose that we can sometimes know if two subtrees are equals, but we may allow that sometimes two isomorphic subtrees won’t be recognized as equals. In order for the algorithm to terminate, this should only happen a finite number of times. For example, the tree is represented with no maximal sharing, and there is a finite number of representatives for a given subtree. Because we allow a previous representation of trees that does not share, we must use the share algorithm to reduce the strongly connected graphs. This tolerance is useful in some algorithms manipulating shared regular trees.

The algorithm is illustrated on a full example section 3.3.5, page 32.

representation(t):

(N, S, G) ← ← ← represent(t, {t})

return return return(N)

represent( [figure: f; t_{0}; t_{n−1}] , T ):

t ← ← ← [figure: f; t_{0}; t_{n−1}]

k is the partial key such that name(k) = f and dom(k) = ∅ S is a partial function from trees to sets of nodes and numbers and dom(S) = ∅ N is a new node

for for for i ← ← ← 0 to to to n − 1 do do do
  if if if t_{i} ∈ T then then then add t_{i} →(N, i) to S

else else else (N_{i}, S_{i}, G_{i}) ← ← ← represent(t_{i}, T ∪ {t_{i}})

if if if dom(S_{i}) = ∅ then add i→N_{i} to k

   else else else add S_{i} to S
10 if if if dom(S) = ∅ then then then
  if if if k ∈ dom(D) then then then return return return(D(k), S, ∅^{G})

  else else else

Let N be labeled by f and N.i ← ← ← N_{i} add k →N to D

   return return return(N, S, ∅^{G})

else else else

G^{N} ← ← ← ⋃_{i<n} G_{i}^{N}

G^{E} ← ← ← ⋃_{i<n} G_{i}^{E}

add N labeled by k to G^{N} 20 add {(N, N_{i}, i) | dom(S_{i}) ≠ ∅} to G^{E}

  if if if t ∈ dom(S) then then then
   while while while S(t) ≠ ∅ do do do

take (M, i) out of S(t) add (M, N, i) to G^{E} delete t from dom(S)

  if if if dom(S) = ∅ then then then return return return(representCycle(N), S, ∅^{G})
  else else else return return return(N, S, G)
representCycle(N):

l_{1} is the key obtained from treeKey(N)

if if if l_{1} ∈ dom(D_{G}) then then then return return return(D_{G}(l_{1}))

D_{S} and D_{D} are two empty node dictionary

b ← ← ← shareWithDone(N)
if if if b then then then

add l_{1} →D_{S}(N) to D_{G}

  return return return(D_{S}(N))

else else else

  share(N)

10 l_{2} is the key obtained from treeKey(N)

  if if if l_{2} ∈ dom(D_{G}) then then then

add l_{1} →D_{G}(l_{2}) to D_{G}

   return return return(D_{G}(l_{2}))

  else else else

add l_{1} →N to D_{G}

   ∀M ∈ G^{N} do do do

M is labeled by m

m′ is m completed by the children of M in G.

add m′ →M to D 20 l′ is the key obtained from treeKey(M)

add l′ →M to D_{G}

   return return return(N)

shareWithDone(N)
if if if N ∈ dom(D_{S}) then then then return return return(false false false)

add N to D_{S}

N is labeled by [figure: k; N_{0}; N_{n−1}]

∀i ∈ dom(k) do do do if if if tryShare(N, k(i), i, k(i)) then then then return return return(true true true)
for for for i ← ← ← 0 to to to n − 1 do do do if if if shareWithDone(N_{i}) then then then return return return(true true true)
return return return(false false false)

tryShare(N, M, i, O)

if if if M ∈ dom(D_{D}) then then then return return return(false false false)

add M to D_{D} if if if N and M have the same label and M.i = O then then then

D_{C} is an empty node dictionary

  if if if compareWithDone(N, M) then then then

replace D_{S} by D_{C}

   return return return(true true true)

M is labeled by [figure: f; M_{0}; M_{n−1}]

return return return(⋁_{j<n} tryShare(N, M_{j}, i, O))

compareWithDone(N, M)
if if if N ∈ dom(D_{C}) then then then
  if if if D_{C}(N) = M then then then return return return(true true true) else else else return return return(false false false)

N is labeled by [figure: f; N_{0}; N_{n−1}] by extending the partial key k labeling N

M is labeled by [figure: g; M_{0}; M_{m−1}]

  if if if f = g then then then

add N →M to D_{C}

   for for for i ← ← ← 0 to to to n − 1 do do do
     if if if i ∈ dom(k) then then then if if if N_{i} ≠ M_{i} then then then return return return(false false false)
     else else else if if if compareWithDone(N_{i}, M_{i}) = false false falsethen then then return return return(false false false)
   return return return(true true true)
  else else else return return return(false false false)

3.3.3 More Remarks to Understand the Algorithm

Global Algorithm

The represent function is evaluated on a tree t and a set of trees T. Its result is a node N, a partial function S and a graph G. t is the subtree that we examine. In particular we have to decide whether or not to associate it with a new node. T is the set of trees that contains t and the subtrees that have been encountered so far. It is used to detect cycles in the tree. Each cycle that we detect and that is not resolved by the use of the algorithm on strongly connected graphs is stored in S. If there are unresolved cycles, that means that we are in a strongly connected part of the tree, and we must build the graph representing this part. It is the role of the graph G. N is the node that is associated with the subtree t. If there is no unresolved cycle, this node is the final one.

When we identify an independent subgraph in the representation of the tree, we call representCycle. The first task of this algorithm is to verify that the graph has not been encountered yet. This is performed using the treeKey, shareWithDone and share procedures. Finding out whether a given graph has already been encountered is quite a difficult task. It is performed in four steps. First, we verify, using the treeKey algorithm, whether the graph in its form has already been encountered. If it is the case, it is stored in D_{G}, and we can retrieve it from this dictionary. If not, we must then fold the cycles in the graph in order to have a normal form. There are two sources of cycle unfolding: a cycle can be unfolded by cycle growth, or by root unfolding. For example, consider the cycle

\xymatrix{a \ar[r] & b \ar[l]}. \xymatrix{ & b \ar[dl] \\ a \ar[dr] & & a \ar[ul] \\ & b \ar[ur]}is an example of cycle growth, and \xymatrix{a \ar[r] & b \ar[r] & a \ar[l]} is an example of

root unfolding. The second step determines whether there is root unfolding. It is performed using the shareWithDone algorithm. If this step was not successful, we must go to the third step. This third step uses the share procedure to reduce cycle growth, and then, the graph being in normal form, we use the treeKey algorithm again.

representation(t) is the node representing t in the graph defined by D. It is easy to see that this graph is of maximal sharing, assuming there is no duplication of strongly connected graph representation. If there are p_{1} and p_{2} such that t_{[p_{1}]} = t_{[p_{2}]}, if p_{1} ≺ p_{2} then when t_{[p_{2}]} is reached, it is already present in T, and so no new node is created. If the paths don’t compare for ≺, then for example p_{1} ≺_{ℕ}^{∗} p_{2} and the nodes for t_{[p_{1}]} and all its subtrees are already indexed in D, thus no new node is added in D when the key for t_{[p_{2}]} is computed.

Algorithm to Avoid Duplication of Strongly Connected Subgraphs

As we described in the global algorithm remarks, avoiding duplication of strongly connected subgraph is performed in four steps. The first step^{2} using treeKey is performed to avoid unnecessary work before any transformation of the strongly connected subgraph. The unnecessary work is avoided only if the same node of the same strongly connected subgraph have already been encountered. The second use of this algorithm^{3}, performed on a normal form of the graph, decides whether the graph has already been encountered. This is because the first time a graph is constructed, every key of every node of the graph in normal form is computed and associated via D_{G} with its unique representation. We could not store every key for any node in any form of the graph (and so the first use of treeKey could not decide whether the graph had already been encountered in an other form) because the number of such forms is infinite. It is obvious when considering cycle growth. But even when considering root unfolding, the number of tree keys can be infinite too, because the root itself can be a cycle.

Example: Root unfolding with a strongly connected root that can be as big as we want, even after cycle growth reduction.

[figure: a; 1; 0; b; 1; 0; b; 1; 0; …; 1; b; 1; 0; b; 1; 0; a; 0; 1; b; 0; 1] = [figure: a; 0; 1; b; 0; 1]

♢

The order in which we fold the subgraph is important. It is a consequence of the represent algorithm. In the case of root unfolding, the cycle of this unfolding has already been treated by the algorithm, and so it is uniquely represented. All we have to do, then, is to return the node in this cycle that is equivalent to the node we are considering. There is no need to check for cycle growth. If there is no root unfolding, then we can reduce cycle growth with the share algorithm, and have a graph in normal form. If later on we come to a node of an equivalent graph with no root unfolding, we will find the same tree key, because the partial values associated with the nodes will be the same due to the uniqueness of the representation.

2first lines of representCycle.

3lines 10 to 13 of representCycle.

The algorithm determining whether there is root unfolding is based on some properties of the graph to reduce the complexity of the computation. The basic idea is to compare every node of the graph we consider with every node that is reachable, and already computed, from this graph. These nodes are accessed through the partial keys labeling the graph. As in the algorithm, we call G the graph we are considering. H is the graph already computed and stored in D that is reachable from the partial keys of G. shareWithDone(N) determines whether a node N of G is equivalent to a node of H. If it is the case, then there is root unfolding. If not, there is no root unfolding. It is enough to verify this property for one node to treat the entire graph G because G is strongly connected. Suppose N is equivalent to M in H. Then, whatever the legible path p, N.p is equivalent to M.p. Because H has been treated already, any M.p is in H, and because G is strongly connected, any node of G is a N.p.

There is a kind of reciprocal property that is exploited too: for some subsets of H^{N}, if no node of the subset is equivalent to a particular node of G, then they are not equivalent to any node of G. A subset of H^{N} is said to be closed if and only if, for every legible path p, for every node N in the subset, N.p is in the subset.

Property 3.2 ∀F ⊂ H^{N} such that F is closed, if ∃N ∈ G^{N} such that ∀M ∈ F, N and M represent different trees, then it is the case whatever N ∈ G^{N}.

Proof: Let F be such a subset and N a node of G. If N is not equivalent to any node in F, then, suppose there is a M ∈ G^{N} and a O ∈ F such that M is equivalent to O. As G is strongly connected, there is a p such that M.p = N. So, N would be equivalent to O.p, which is in F. This proves that no element of G^{N} is equivalent to any element of F. □

Because of these properties, we can compare only the nodes of G with the nodes that are reachable from their partial keys and not already encountered. That is what shareWithDone does, calling tryShare for every node in G. The nodes in G that have already been visited are stored in D_{S}. tryShare takes the node N of G to be compared with the node M of H, and the label i and N.i. These last two arguments serve to avoid too much calls to compareWithDone. We exploit the property that, as N.i is in H^{N} and the representations in H are unique, if N is equivalent to M, then N.i = M.i. The nodes of H that have already been visited are stored in D_{D}. We know by the property proved above that no element of D_{D} is equivalent to a node of G.

When the equality is possible, tryShare uses compareWithDone to compare the two nodes. The first node is in G and the second one in H. Because the representation in H is unique, a given node of G can be equivalent to at most one element of H^{N}. Thus we can use a dictionary (D_{C}) to store the pairs of already compared nodes: {N, M} with N ∈ G^{N} and M ∈ H^{N} has already been compared if and only if D_{C}(N) = M. To perform the comparison, we have to extend the partial key labeling N, but the nodes which come from the partial key are in H^{N}, and so they can be directly compared to M, because of the uniqueness of the representation in H. If compareWithDone is true, then every node of G is mapped in D_{C} to a node of H to which it is equivalent. D_{S} takes the value of D_{C}, so that the node which is equivalent to the initial node with which shareWithDone was called can be easily found.

This algorithm leads to a quadratic worst case complexity. An alternative would be to use the classical partitioning Hopcroft algorithm on the whole graph, including the already shared part. This algorithms gives an n log(n) worst case complexity. But as for eqTree, the worst case is rare, and in practice, the algorithm presented here seems to work faster. A possible explanation lies in the fact that the partitioning algorithm is badly suited to take advantage of the parts of the graph that are already shared. The algorithm presented here is more incremental.

3.3.4 Proof of the Algorithm

The algorithm returns the node of a graph. We must prove that this graph represents the good tree, and that it is a graph of maximal sharing.

Equivalence and Partial Keys

During its execution, the algorithm manipulates graphs labeled by partial keys. In order to show the correctness of the result, we must give the exact meaning of these graphs, and in particular define the corresponding equivalence. This equivalence, denoted ≡_{pk} shows when two graphs represent the same tree.

The idea of partial keys is that their name corresponds to the label of the tree, and the partial function to subtrees which have already been treated by the algorithm. So we have a kind of a progression ordering on keys: k_{1} ≤_{pk} k_{2} ⇔ name(k_{1}) = name(k_{2}) and ∀i ∈ dom(k_{1}), k_{2}(i) = k_{1}(i).

The partial keys can be forgotten so that we give an equivalent graph labeled on F, and with no notion of progression. Considering a graph G labeled by a set of partial keys K_{G}, the new graph G′ is defined as: G^{′N} = G^{N}∪the nodes of the graphs in K_{G}, and G^{′E} = G^{′E} ∪ {(N, i, M) | N ∈ G^{N} labeled by k and k(i) = M}∪the edges of the graphs in K_{G}. The equivalence with partial keys is defined as the transitive and symmetric closure of ≡_{t} augmented by the G ≡_{pk} G′.

Correctness

The property proving the correctness is the following: if represent(t, T ∪ {t}) returns (N, ∅, ∅^{G}), then N represents t. Considering that we already showed earlier that the algorithm terminates, we will prove it by induction on the recursive calls to represent. The three first return points in represent (lines 11, 15 and 26) fall into the property, whereas for the fourth one (line 27), the function S is not empty. So we need only prove the property on the three first return points.

Lines 11 and 15, the partial function S is empty, so the test line 6 have always been false, and each call to represent returned a value of the form (N_{i}, ∅, ∅^{G}), so by induction, each N_{i} represent correctly t_{i}. The line 11 corresponds to a case which have already been encountered. Line 15, the node N is linked to the different N_{i}, so it is a correct representation of t.

Line 26 depends on representCycle, which has four return point. The property of representCycle(N) is that it returns a node M of a graph with no partial keys and such that N ≡_{pk} M. The first return point, line 2, supposes that there is a M such that M ≡_{pk} N which has already been treated. M ≡_{pk} N implies M ≡_{t} N, so it is correct to return the same result as for M. The second return point, line 7, supposes that shareWithDone has detected a node M = D_{S}(N) which represents the same tree as N and which is already a unique representation of the tree. So returning M is correct. The third return point, line 13, comes after a call to share, so N is now the node of another graph which is equivalent (for ≡_{t}) to the initial one. The third return point supposes that there have already been a node M such that M ≡_{pk} N which has already been encountered, so it is correct to return the same result as for M. The last return point returns N, which is of course correct.

The last point to make the link between representCycle and represent is to prove that line 26 of represent, the node N represents t. When we call representCycle, the partial function S is empty. It means that every bit of information stored line 6 have been used and translated in the graph G (lines 22–25). The nodes in the partial keys come from calls to represent with return value (M, ∅, ∅^{G}) and so are correct by hypothesis. The rest of the graph is directly derived from the tree.

Dictionaries and Maximal Sharing

In order to ensure the uniqueness of the representation, we use two dictionaries: D and D_{G}. For every new node created which definitely represents a tree, an entry in D is created with for a key the label of the node and the nodes of its children (line 14 of represent, and line 19 of representCycle). The problem is that this kind of key is not valid for ≡_{t} with infinite trees. So the dictionary D_{G} stores the key obtained by treeKey for every node which definitely represents a tree, and which is in a loop of the graph (line 21 of representCycle).

When we use the results stored in the dictionaries, we don’t create any new node, so we cannot duplicate anything. We just have to see that the new nodes effectively created do not duplicate any other one stored in D. We go through the different opportunities for duplication, and suppose it is the first time a duplication occurs. If no such first time is possible, then no duplication ever occurs.

Line 14 of represent, we know that the key k is not in D. Moreover, each

one of the N_{i} composing the key is unique by hypothesis. So if a tree [figure: f; t_{0}; t_{n−1}] had

already been encountered, the key (f, (N_{i})_{i<n}) would already have been encountered.

Line 22 of representCycle, we know that the key treeKey(share(N)) has never been encountered before. Because such a key is valid for strongly connected graphs, it means that no other node M such that M ≡_{t} N have been encountered before. But the problem is that we have a partial key semantics on these graphs, and ≡_{t}⊂≡_{pk}, so we could have M ≢_{t} N but M ≡_{pk} N in effect representing the same tree. Because M ≢_{t} N, there is a path p such that M.p and N.p don’t have the same label, k_{M} and k_{N}. But as N and M represent the same tree, k_{M} and k_{N} must have the same name, so their only possible difference is in the partial function. It mean there is an i such that one of the keys is defined on i and not the other key (if both of them were defined on i, their value would be the same on i, as the nodes in partial keys are unique representations). By construction, the nodes M and N are in strongly connected graphs. So if one of the keys is not defined on i, there is a q such that M.piq = M or N.piq = N. If t is the tree represented by both nodes, it means that t_{[piq]} = t. Suppose k_{M} is defined on i, then there is a node reachable from k_{M}(i) which represents the same tree as M, and as such it would have been found by shareWithDone. So the graph defined by M would never have gone beyond the line 7 of representCycle. It means that another representative is stored for the cycle (we go on like this until we find one which is equivalent to N, which means that the test line 11 could not have been false). If k_{N} is defined on i, by the same argument, we could not have been beyond the line 7, and so no new node is created.

3.3.5 Example

We present the algorithm to represent regular trees on an example. Let us consider the graph of figure 3.1, where each node is assigned a number. We will write t_{i} for the tree represented by the node □_{i}. We will describe each call to represent on each t_{i}. The return result of this algorithm, (N, S, G) are described

[figure: f _{1}; 0; 1; 2; _{f _{2}}; 0; 1; 2; _{g _{5}}; 0; 1; _{a _{6}}; _{g _{3}}; 0; 1; _{a _{4}}]

Figure 3.1: Example

by a framed node N in a graph and possibly a finite function. If there is no such function, it means that the domain of S is empty and the graph G is empty. If there is such a function, then G is the graph containing N and S is the function.

In some graphs, we will draw partial keys. In these cases, the actual edges of the graph are represented by plain lines, and the nodes which are linked by the partial keys are associated with those keys by dotted lines.

represent(t_{1}, {t_{1}}):

line 21 G = [figure: f; 0; 1; 2; f; 0; 1; 2; g; 1; g; 0; 1; a] and S = {t_{1} →(□_{5}, 0)}

line 26 calls representCycle( [figure: _{f _{1}}; 0; 1; 2; f; 0; 1; 2; g; 0; 1; g; 0; 1; a] ) and returns[figure: _{f _{2}}; 0; 1; 2; g; 0; 1; a]

represent(t_{2}, {t_{1}, t_{2}}):

line 21 G = [figure: f; 1; 2; g; 1; a] and S = {t_{2} →(□_{2}, 0)(□_{3}, 0)} line 26 calls representCycle( [figure: _{f _{2}}; 0; 1; 2; g; 0; 1; a]) and returns [figure: _{f _{2}}; 0; 1; 2; g; 0; 1; a]

represent(t_{3}, {t_{1}, t_{2}, t_{3}}): line 21 G = g and S = {t_{2} →(□_{3}, 0), t_{3} →(□_{3}, 1)} line 27 returns [figure: g _{3}; 1] and {t_{2} → (□_{3}, 0)}

represent(t_{4}, {t_{1}, t_{2}, t_{4}}): line 14 D becomes {a→□_{4}} line 15 returns a _{4}

represent(t_{5}, {t_{1}, t_{5}}): line 21 G = g and S = {t_{1} →(□_{5}, 0), t_{5} →(□_{5}, 1)} line 27 returns [figure: g _{5}; 1] and {t_{1} → (□_{5}, 0)}

represent(t_{6}, {t_{1}, t_{6}}): line 11 returns a _{4}

representCycle( [figure: _{f _{2}}; 0; 1; 2; g; 0; 1; a]):

line 4 shareWithDone returns false, because the only node already in a partial

key is a _{4}, and it is not equivalent to any node in the graph. line 9 share does not modify the graph which is already of maximal sharing. line 22 before returning, D_{G} and D have been modified.

D_{G} is now { [figure: f; ε; g; a; ε; 1]→□_{2}, [figure: g; f; ε; 0; ε; a]→□_{3}}

and D is \{ \xymatrix{ & f \ar[dl] \ar[d] \ar[dr] \\ □_{2} & □_{3} & □_{4}}→□_{2}, \xymatrix{ & g \ar@{-->}[dl] \ar@{-->}[dr] \\ □_{2} &  & □_{3}}→□_{3}, a→□_{4}\}

shareWithDone( [figure: _{f _{1}}; 0; 1; 2; f; 0; 1; 2; g; 0; 1; g; 0; 1; a] ):

line 4 calls tryShare(□_{1}, □_{2}, 0, □_{2}) and returns true with D_{S} = {□_{1} → □_{2}, □_{5} →□_{3}} (line 6 of tryShare).

3.4 Algorithms on Shared Regular Trees

Trees are structures which are designed for algorithms, and usually, algorithms on trees are quite easy to describe. The main problem with shared regular trees, is that when an algorithm transforms a tree, its result must be shared. The second problem, of course, is the possibility for a regular trees to be infinite.

The basic property of shared regular trees, its main quality, lies in the equality testing. Two trees are equal if and only if they are represented by the same node.

3.4.1 Easy Algorithms

Subtrees

Considering a tree t and a path p of the tree, finding the representation of the subtree t_{[p]} is nearly immediate. We just have to follow the graph representing t according to p, and the resulting node is the representation of t_{[p]} with maximal sharing. This is because the property of being of maximal sharing is a global property of the graph and does not depend on the particular node that represents either t or t_{[p]}.

Determining whether a tree t_{1} is a subtree of t_{2} is easy too. We just have to compare the node representing t_{1} with every node in G_{t_{2}}. t_{1} is a subtree of t_{2} if and only if it is represented by a node of G_{t_{2}}.

Root Construction

Considering a label f and Ar_{F} (f) trees (t_{i})_{i<n} represented by the nodes (N_{i})_{i<n},

we want to represent the tree [figure: f; t_{0}; t_{n−1}]. The dictionary is called D. If the key

f, (N_{i})_{i<n} is in D, then the corresponding node represents [figure: f; t_{0}; t_{n−1}] and is sharing

(because, as we said above, any node of the dictionary represents a tree with maximal sharing). If the key is not in the dictionary, then there is no node representing this tree, and so we must use a new node and associate the key with the new node in the dictionary. Again, this node represents the tree with maximal sharing, without any additional work.

3.4.2 Generic Memoizing Algorithms

An algorithm is memoizing [Mic68] if it keeps a private dictionary mapping previous arguments to the results of the computation on them. Because in the case of shared regular trees equality testing is so easy, memoizing is well adapted, and it is the best technique to exploit this structure.

Tree Map

We present a schematic generic algorithm using memoizing on a simple tree. This algorithm, treeMap, applies a function F to a shared regular tree. We require that F be a function that takes a label f and Ar_{F} (f) values and gives a value. Moreover, there should be a tractable fixpoint computation strategy of F. We define a fixpoint equation Eq as being of the form:

Eq = { X_{1} = F (f_{1}, U_{1}^{0}, …, U_{1}^{n_{1}−1}) ; ⋮ ; X_{m} = F (f_{m}, U_{m}^{0}, …, U_{m}^{n_{m}−1})

where X_{i} are variables and U_{i}^{j} are either a value or one of the variables. A fixpoint computation strategy of F is a function fixpoint_{F} from fixpoint equations to vectors of values such that fixpoint_{F}(Eq) is a solution of Eq. Usually, the complexity of the fixpoint algorithm is more than linear. The tree map algorithm decompose the regular tree so that the fixpoint algorithm is applied to smaller parts of the trees, and as few times as possible.

The algorithm builds fixpoint equations through the use of partial values. A partial value is either a value, InCycle or InEvaluation. The current state of the computation is stored in the dictionary D_{mem} which links some nodes to a partial value. The current state of the computation defines the fixpoint equation with equations X_{N} = F(f_{N}, U_{N}^{0}, …, U_{N}^{n_{N} −1}), N being nodes of the graph labeled

by [figure: f_{N}; N_{0}; N_{n_{N} −1}] and U_{N}^{i} is D_{mem}(N_{i}) if it is a value, and X_{N_{i}} otherwise. This

fixpoint equation defines a relation between nodes of the graph: M ↢_{D_{mem}} N if X_{N} depends on X_{M}. The fixpoint computation strategy applied to a node N is considered as restricted to those variables X_{M} that are reachable from X_{N} in the fixpoint equation. We will write fixpoint_{F}(N) for the family of values indexed over the set of nodes M such that M ↢_{D_{mem}} N solution of this fixpoint equation.

treeMap(N, F):

  add N →InEvaluation to D_{mem}
  for for for i ← ← ← 0 to to to n − 1 do do do
   if if if N_{i} ∈ dom(D_{mem}) then then then

V_{i} ← ← ← D_{mem}(N_{i})

     if if if V_{i} = InEvaluationthen then then Cycle_{i} ← ← ← {N_{i}} else else else Cycle_{i} ← ← ← ∅

   else else else (V_{i}, Cycle_{i}) ← ← ← treeMap(N_{i}, F)

  Cycle ← ← ← ⋃_{i<n} Cycle_{i}

  if if if every V_{i} is a value then then then

V ← ← ← F (f, V_{0}, …, V_{n−1})

replace the value of N by V in D_{mem}

   return return return(V, ∅)
  else else else if if if Cycle = {N} then then then

(V_{M})_{M↢_{Dmem}N} ← ← ← fixpoint_{F}(N)

replace the value of every M such that M ↢_{D_{mem}} N by V_{M} in D_{mem}

   return return return(V_{N}, ∅)

  else else else

replace the value of N by InCycle in D_{mem}

   return return return(InCycle, Cycle\{N})

Tree Substitution

Tree substitution consists in replacing any subtree labeled by a given label x by a tree t given by the substitution. It is a typical example of memoizing algorithm, and it can be expressed using treeMap and the function F defined as:

F(x, N_{0}, …, N_{n−1}) = N, the node representing t
F(f, N_{0}, …, N_{n−1}) = the node labeled by [figure: f; N_{0}; N_{n−1}] if f ≠ x

The fixpoint equations of F are solved using the algorithm presented in repre-

sent.

Tree substitution is one of the basic operations on trees. It is the reason why we give the description of its algorithm. As the algorithm is not very different from the representation algorithm, we first give the simple modifications to give to this algorithm to obtain the tree substitution.

The only necessary modification is a test at the beginning of the algorithm to see whether the label of the current tree is x. If it is the case, we can return the substitute tree with an empty graph. Because the representation algorithm does not require that we always know when two subtrees are equal, no more modification is needed to compute the tree substitution.

In addition, we can use another optimization: because the tree is already shared, if a subtree does not contain x, then it does not need to be changed. It is an information that is easy to propagate while exploring the tree to perform the substitution. We add a new result to represent, a boolean value b. If we come to an x, b is true. Else, b is true if and only if the result of represent on one of its children is true. Children of t that are in T don’t participate to the computation of this value. As soon as b and S are computed^{4}, we can exploit them: if b is false and dom(S) ⊂ {t}, then there is no need to modify the subtree t. In this way, we avoid the possible computation of the strongly connected graph containing t and the painful algorithm to avoid duplication of the graph.

treeSubst(t_{1}, x, t_{2}):

(N, S, G, b) ← ← ← treeSubstRec(t_{1}, {t_{1}}, x, t_{2})

  return return return(N)

treeSubstRec( [figure: f; t_{0}; t_{n−1}] , T, x, u):

  if if if f = x then then then return return return(u, ∅, ∅^{G},true true true)

t ← ← ← [figure: f; t_{0}; t_{n−1}]

k is the partial key such that name(k) = f and dom(k) = ∅

S is a partial function from trees to sets of nodes and numbers and dom(S) = ∅ N is a new node

  b ← ← ← false false false
  for for for i ← ← ← 0 to to to n − 1 do do do
   if if if t_{i} ∈ T then then then add t_{i} →(N, i) to S

else else else (N_{i}, S_{i}, G_{i}, b_{i}) ← ← ← treeSubstRec(t_{i}, T ∪ {t_{i}}, x, u) b ← ← ← b ∨ b_{i} if if if dom(S_{i}) = ∅ then add i→N_{i} to k

     else else else add S_{i} to S
  if if if b = false false falseand and and dom(S) ⊂ {t} then then then return return return(t, ∅, ∅^{G},false false false)
  if if if dom(S) = ∅ then then then
   if if if k ∈ dom(D) then then then return return return(D(k), S, ∅^{G},true true true)

   else else else

Let N be labeled by f and N.i ← ← ← N_{i} add k →N to D

     return return return(N, S, ∅^{G},true true true)

  else else else

G^{N} ← ← ← ⋃_{i<n} G_{i}^{N} G^{E} ← ← ← ⋃_{i<n} G_{i}^{E} add N labeled by k to G^{N} add {(N, N_{i}, i) | dom(S_{i}) ≠ ∅} to G^{E}

   if if if t ∈ dom(S) then then then
     while while while S(t) ≠ ∅ do do do

4just after line 9 of represent.

take (M, i) out of S(t) add (M, N, i) to G^{E} delete t from dom(S)

   if if if dom(S) = ∅ then then then return return return(representCycle(N), S, ∅^{G},true true true)
   else else else return return return(N, S, G, b)

3.4.3 Recursive Construction

Recursive construction is the basic operation to build infinite looping trees. The idea is to solve the equation x = t where x is a label of arity zero which may appear in t, but t(ε) ≠ x. Formally, let u = recCons(t, x). the domain of u is defined by:

pos(u) = {p | ∃(p_{i})_{i≤n} ∈ pos(t), p = ⨀_{i≤n}^{<} p_{i} and and ∀i < n, t(p_{i}) = x}

The values of u on its domain are defined by a simple recursion:

u(p) = if (p = qp_{1}) and (t(q) = x) then u(p_{1}) else t(p)

As recursive construction is a basic algorithm, it is based on the representation algorithm. As for tree substitution, the algorithm does not change subtrees that do not contain x.

In representation, we call represent with the set {t, x} instead of {t}. The test to decide whether the current subtree can be left unchanged is per-

formed just after the line 9 of represent. The subtree can be left unchanged if dom(S) ⊂ {t}. It corresponds exactly to the test of line 26. So there is no need to

call representCycle in represent. We need only one call to representCycle,

in representation, after modifying the resulting graph of represent according to S, adding the edges corresponding to the different occurrences of x in t.

Using root construction and recursive construction, one can build any regular tree.

recCons(t, x):

(N, S, G) ← ← ← recConsRec(t, {t, x})

  if if if dom(S) = ∅ then then then return return return(N)
  while while while S(x) ≠ ∅ do do do

take (M, i) out of S(x) add (M, N, i) to G^{E}

  return return return(representCycle(N))

recConsRec( [figure: f; t_{0}; t_{n−1}] , T ):

t ← ← ← [figure: f; t_{0}; t_{n−1}] k is the partial key such that name(k) = f and dom(k) = ∅ S is a partial function from trees to sets of nodes and numbers and dom(S) = ∅ N is a new node

  for for for i ← ← ← 0 to to to n − 1 do do do
   if if if t_{i} ∈ T then then then add t_{i} →(N, i) to S

else else else (N_{i}, S_{i}, G_{i}) ← ← ← recConsRec(t_{i}, T ∪ {t_{i}}) if if if dom(S_{i}) = ∅ then add i→N_{i} to k

     else else else add S_{i} to S
  if if if dom(S) ⊂ {t} then then then return return return(t, ∅, ∅^{G})

G^{N} ← ← ← ⋃_{i<n} G_{i}^{N}

G^{E} ← ← ← ⋃_{i<n} G_{i}^{E}

add N labeled by k to G^{N}

add {(N, N_{i}, i) | dom(S_{i}) ≠ ∅} to G^{E}

  if if if t ∈ dom(S) then then then
   while while while S(t) ≠ ∅ do do do

take (M, i) out of S(t) add (M, N, i) to G^{E} delete t from dom(S)

  return return return(N, S, G)

3.4.4 Complexity Issues

Algorithms on shared regular trees are more difficult than standard algorithms on regular trees. Comparing complexities of algorithms on the two representations is difficult, though. The complexity is measured with respect to the size of the inputs of the algorithms, which can be reduced to the number of distinct subtrees of the inputs in our case. In the case of shared regular trees, the number of distinct subtrees is exactly the number of different subtrees of the tree, but when the tree is not shared, the number of subtrees that are distinguished by the representation can be of any value greater than the number of different subtrees. In the sequel, we denote by n this number, but we must keep in mind that this n can be much bigger in the case of non-shared trees.

Summary of worst case time complexities

sharing representation

naive representation

testing t_{1} = t_{2}  O(1)  O ((n_{1} + n_{2}) log(n_{1} + n_{2}))
testing t_{1} ⋖ t_{2}  O(n_{2})  O ((n_{1} + n_{2}) log(n_{1} + n_{2}))
building t_{[p]}  O(|p|)  O(|p|)
root construction  O(1)  O(1)
recursive construction  O(n^{2})  O(n)
tree substitution:(t_{1}, x, t_{2})  O(n_{1}n_{2})  O(n_{1})

In the case of equality testing with a non sharing representation, we must perform the eqTree algorithm and in the worst case compare any pair of distinguished subtrees^{5}. This would lead to a quadratic worst case complexity. However, we can always use the partitioning algorithm of Hopcroft [Hop71] to get an n log(n) complexity in the worst case. Although this algorithm seems less efficient in practice for equality testing, we assume the best possible bound for non-sharing representations.

For recursive construction, the prevailing operation seems to be the final share algorithm. In the worst case, though, the quadratic complexity of shareWithDone will take precedence.

For tree substitution, it is the possibly numerous calls to shareWithDone which can be the most costly. Remember that the worst case complexity seems rare in practice for this algorithm.

This summary suggests that if we are to perform equality testing, it can be beneficial to perform sharing during the calculus. What we show here are worst case complexity, though, and the difficult cases are quite pathological, and thanks to some simple optimizations, they are quite rare. The situation is quite similar to the complexity of operations on BDDs [Bry86] compared to the operations on boolean formulas. The size of the formula representing a given boolean function is unbounded, but the basic operations, like conjunctions are linear in the size of one of the formulas but the product of the size of the BDDs.

Conclusion

The series of basic algorithms we presented in this chapter allows the construction and the manipulation of regular trees while preserving property of maximal sharing for the representation of the trees. To maintain this property, constructing algorithms are more complex than traditional algorithms that cannot share any subtree because of their inability to deal with sharing of cyclic structures. The tradeoff for this increased complexity is a bounded compact representation of a regular tree, whereas in the classical case there is no bound on the size of the representation (due to cycle growth or root unfolding). Moreover, in the presence of memoizing, and everywhere where equality testing is required, these techniques allow in practice a substantial speed-up, especially when the number of operations performed on the trees is high.

5We cannot use the linear algorithm proposed in [AHU74] because we deal with possibly infinite trees, for which there is no notion of “level” for the nodes.

42 CHAPTER 3. SHARING REGULAR TREES

Representation of Relations

Relations and sets of trees are intimately bound: a set of trees puts in relation subtrees of common prefix path except for the last letter of the path.

For example the set of trees { [figure: f; a; b], [figure: f; a; c], [figure: f; b; c]} can be seen as the relation

{<ab> , <ac> , <bc>}. The connection between sets of trees and relations can also be emphasized by the study of the prefix regular relations of [AH84]. So relations are used in a way or another in the representation of sets of trees.

The problem is that we want to represent some possibly complex infinite sets of infinite trees, which means that we may need to represent infinite relations. These representations should even reflect the infinite behavior of the relations, distinguishing for example between different kind of fairness. To our knowledge, there is no such representation already available that would be tractable. The second problem attacked in this chapter concerns the possibility of approximating the relations whenever their representations are too big or impossible.

Because different kinds of relations and different kinds of approximation strategies can be adapted to different kinds of problems, we present in this chapter different ways of representing relations that can be useful in the representation of sets of trees. Some of these representations can be more or less efficient depending on the number of entries of the relation, the size of the sets associated with the entries, or the particular shape of the relation.

Thus, the first part of this chapter subsumes definitions and structures that are common to these different possible representations. The second part presents representations of relations based on decision diagrams. This section is focused on the representation of infinite relations and their infinite behavior and is the main contribution of this chapter. The third section presents algorithms to manipulate these possibly infinite relations based on decision graphs. It presents a first way to deal with approximated relations. The last section develops other representations of relations that allow different kinds of approximation. This last section is very short. It is there to show how we can build on the first section to represent different kinds of relations.

4.1 Definitions and Common Structures

The relations we want to represent are relations over sets of the form [n]. Moreover, as the relations bind nodes of a tree, their sets of indexes are subsets of ℕ^{∗}. Formally, they are elements of

Rel =^{def} {R | ∃(n_{i})_{i∈I} ∈ (ℕ\{0})^{I} , I ⊂ ℕ^{∗}, R ⊂ ⨂_{i∈I}[n_{i}]}

If I is finite, it is identified to [|I|], preserving the order ≺_{ℕ}^{∗} on I. In the same way, if I is infinite, it can be identified to the ordinal^{1} |I|. Thus, elements of the relations can be identified to words of ℕ^{∗} or infinite words. This relation between words and vectors is defined inductively by: word (<>) =^{def} ε, and if e ∈ ⨂_{i<k+1}[n_{i}],

word (e) =^{def} word (e_{([k])}) e_{(k)}. If e ∈ ⨂_{i∈λ}[n_{i}], with λ a limit ordinal, word (e) is

the limit of the word (e_{(k∈λ)}). The reverse of this operation is <.>, that is <word (e)> = e.

Each entry of the relation is associated with a name. This name is intended to be used as a way to share some entries of the relations. As a consequence, two entries that are not equivalent cannot be associated with the same name. The name of the entry i of the relation R is written name_{R}(i). The set of entry names of R, ⋃_{i∈I} name_{R}(i), is denoted ename(R). The projection of R according to an entry name is defined by R_{(name_{R}(i))} =^{def} R_{(i)}. As we will see, this definition does not depend on the particular choice of i for a given name.

4.1.1 Equivalent Entries

Basic Case

Let e ∈ ⨂_{i∈I} E_{i}, j, k ∈ I such that E_{j} = E_{k}. The element of ⨂_{i∈I} E_{i} obtained from e by exchanging its k^{th} and its j^{th} components is denoted e_{j↔k}. Formally,

∀i ∈ I, e_{j↔k}_{(i)} =^{def} e_{(i)} if i ≠ j ∧ i ≠ k
=^{def} e_{(j)} if i = k
=^{def} e_{(k)} if i = j

Let R be a relation. Two entries i and j of R are said to be equivalent if and only if:

∀e ∈ R, e_{i↔j} ∈ R

1The size of ℕ^{∗} is strictly greater than the size of ℕ. It means that, to be exact, we must consider transfinite relations. To simplify the presentation, we will restrict transfinite relations to relations that can be described by a mere infinite relation in the following way: an element of the transfinite relation is in the relation if and only if its first ω elements are in the infinite relation, and so on, ω elements by ω elements. So, we will mostly speak of infinite relations in the sequel of the chapter.

Equivalent Vectors of Entries

We consider the case where, instead of comparing the behavior of a relation on two entries, we compare its behavior on two disjoint sets of entries of the form [j, j + n[ and [k, k + n[ . If ∀i < n, E_{j+i} = E_{k+i}, we define the exchange of the two vectors of entries on e by:

∀i ∈ I, e_{[j,j+n[ ↔[k,k+n[}_{(i)} =^{def} e_{(i)} if i ∉ [j, j + n[ and i ∉ [k, k + n[
=^{def} e_{(k+l)} if i = j + l with l < n
=^{def} e_{(j+l)} if i = k + l with l < n

The two vectors of entries are equivalent for R if ∀e ∈ R, e_{[j,j+n[ ↔[k,k+n[} ∈ R. The definition is exactly the same as for single entries, and in fact reasoning about equivalent vectors of entries is the same as reasoning about equivalent entries. Thus, it is possible to give the same name to the corresponding entries of the vectors, if in the vector every entry has a distinct name. As these vectors of entries behave the same as a single entry, though, we will only consider single entries in this chapter, to improve the clarity of the presentation.

Infinite Sets of Equivalent Entries

In order to represent infinite relations, we must consider the possibility for infinite sets of entries to share the same name. But in this case, it must make sense even for the infinite behavior of the relation, which is not the case if we just require that any two given entries of the set are equivalent.

An infinite set of equivalent entries can share the same name if for any permutation of the entries^{2}, the relation is the same.

Example: Consider the relation containing any infinite vector of 0’s and 1’s such that there is an infinite number of 0’s followed by a 0. This relation contains (001)^{ω} but not (01)^{ω}. If we considered finite permutations only, that is permutations generated from finite exchange of entries, then every entry of this relation is equivalent. But there is an infinite permutation that transforms (001)^{ω} to (01)^{ω}:

\begin{matrix}σ(3 × k) = 2 × k \\ σ(3 × k + 1) = 4 × k + 1 \\ σ(3 × k + 2) = 4 × k + 3 \end{matrix} [figure: 0; 0; 1; 0; 0; 1; 0; 0; 1; 0; 0; 1; 0; 0; …; 0; 1; 0; 1; 0; 1; 0; 1; 0; 1; 0; 1; 0; 1; …]

2A permutation of the entries is a bijection from the set of entries to itself.

The idea is that we should have the possibility to present the values corresponding to entries with the same name in any order. But the meaning of this substitution is that, if a relation with all entries equivalent contains (001)^{ω} then there is a way of giving the values of (01)^{ω} such that it is accepted by the relation too. So, concerning our relation, it is consistent to forbid the equivalence of every entry.

♢

As an immediate consequence, we have the following properties for every relation R where all entries are equivalent:

Property 4.1 Let v be a word, and b a letter in v. Then <v^{ω} > ∈ R if and only if <(vb)^{ω} > ∈ R.

Property 4.2 Let e be a word where the letter b appears infinitely often. Then <e> ∈ R if and only if <be> ∈ R.

Proof: In both cases, we have an infinite permutation of the entries that transforms the first vector in the other one. In the second case, we just have to shift the b’s of be to the right, each b going at the entry of the next one. In the first case, we keep shifting by one more b for each vb. □

If the set of indexes of an infinite relation R is totally ordered, the sequence of the names of its entries forms an infinite word. We say that the entry names of the relation are ultimately periodic if the word they form is ultimately periodic. Then the periodicity of the entry names of the relation is the least k such that there is an N ∈ ℕ, ∀i > N, name_{R}(i) = name_{R}(i + k). The periodicity of a relation is the least periodicity of all the possible entry names for that relation.

4.1.2 Isomorphic Relations

Let R and S be two relations with named entries. R is a relation on ⨂_{i∈I} E_{i} and S a relation on ⨂_{j∈J} F_{j}. The two relations are said to be isomorphic, and we write R ≃ S , if there is a bijection σ : I →J such that:

∀i ∈ I, E_{i} = F_{σ(i)}

∀i ∈ I, name_{R}(i) = name_{S}(σ(i))

∀e ∈ ⨂_{i∈I} E_{i}, e ∈ R ⇔ σ^{⋆}(e) ∈ S

The extension of σ to ⨂_{i∈I} E_{i} → ⨂_{j∈J} F_{j}, σ^{⋆}, is defined, when ∀i ∈ I, E_{i} = F_{σ(i)}, by:

∀e ∈ ⨂_{i∈I} E_{i}, ∀j ∈ J, σ^{⋆}(e)_{(σ(j))} =^{def} e_{(j)}

In the case where I and J are ordered, we require moreover that σ respects the ordering, that is if i <_{I} i′, σ(i) <_{J} σ(i′).

4.1.3 Regular Relations

We introduce the notion of regular relation, which is used to characterize a class of infinite relations that can be finitely represented, in the same way as regular trees. Remember, though, that we are interested in relations with infinite number of entries, not to be mistaken for infinite binary relations of [GN84] for example. In our paradigm, an infinite relation can be seen as a set of infinite words, so it should be possible to use the notion of ω-regularity of Büchi [Büc60, Büc73]. We must be more restrictive, though, as we must deal with entry names in the representation too.

Prefix Regular Relations

A relation R of domain ⨂_{i∈I} E_{i}, with I an ordinal, is said to be prefix regular if:

∃N ∈ ℕ, ∀k > N, ∀e ∈ ⨂_{j<k} E_{j}, ∃l < l_{1} ≤ k, R(e_{([l])}) ≃ R(e_{([l_{1}])})

The idea is that the finite part of the relation can be finitely represented. An equivalent way of characterizing a prefix regular relation is the finiteness of the set {R(e) | e ∈ ⨂_{j<k} E_{j}, k ∈ ℕ} modulo ≃.

Iterative Relations

Prefix regularity only constrains the finite behavior of the relation. We describe the infinite behavior of the relation using what we call iterative relations. These relations are defined as a special interpretation of open relations.

An open relation R of domain ⨂_{i∈I} E_{i} is characterized by:

∀e ∈ R, ∃k ∈ ℕ, R (e_{([k])}) = ⨂_{i∈I\[k]} E_{i}

Open relations are used to describe the relation between finite parts of an infinite vector.

A relation R is said to be iterative if and only if it is described by a prefix regular open relation S in the following way: e ∈ R if and only if e ∈ S and ∃(k_{i})_{i∈ℕ} such that:

k_{0} = min {k | □ (S, [k], e_{([k])}) and nameiter(S, k)}
∀i ∈ ℕ, ∃k > k_{i}, □ (S, [k − k_{i}], e_{([k_{i},k[ )})

k_{i+1} = min {k | □ (S, [k − k_{i}], e_{([k_{i},k[ )}) and nameiter(S, k − k_{i})}

Where □(S, J, w) is a shortcut for S_{:J=w} = ⨂_{i∈I\J} E_{i} and nameiter(S, k) stands for ∀j ∈ ℕ, name_{S}(j + k) = name_{S}(j).

We write R = Ω (S).

Note that the empty relation is open and iterative.

Examples:

• The relation consisting of the set of every infinite vector beginning with a 0 is an open relation, and the iterative relation it represents contains only the infinite vector of 0’s (written 0^{ω}).

• The relation containing any vector with at least one 0 is an open relation, and the iterative relation it represents is the set of vectors with an infinite number of 0’s.

• The relation containing any vector with at least one 0 and one 1 is an open relation, and the iterative relation it represents is the set of vectors with an infinite number of 0’s and 1’s.

♢

Property 4.3 An iterative relation is prefix regular.

Proof: Let R = Ω (S), with S prefix regular. If S(u) ≃ S(v), then R(u) ≃ R(v). So the set of distinct R(u) modulo ≃ is smaller than the set of distinct S(u) modulo ≃, which is finite because S is prefix regular. Thus, R is prefix regular.

□

Definition of Regular Relations

A relation R is ω-regular if and only if it is prefix regular and there is a finite set of non-empty iterative relations iter(R) such that ∀e ∈ R, ∃k, ∃S ∈ iter(R), e_{(∁[k])} is in S and for all f in S, <word (e_{([k])}) word (f)> is in R.

A relation is regular if it is finite or ω-regular.

Properties of ω-regular Relations

This notion of ω-regularity is really closely related to the notion of ω-regularity of sets of words, although we don’t use exactly the ω-regularity of Büchi in regular relations. The link between the two notions can illustrate the expressive power of regular relations. This link is expressed by the following property:

Property 4.4 A relation R is ω-regular if and only if its entry names are ultimately periodic and the set {e | <e> ∈ R} is ω-regular in the sense of Büchi.

The idea of the presentation of ω-regular relations is the use of the characterization of ω-regular sets of words as finite unions of sets of the form U.V^{ω} with U and V regular sets of finite words [Büc60]. In the case of relations with named entries, the iterative relations can be seen as sets of the form V^{ω}.

Proof: Let R be an ω-regular relation. Because it is prefix regular, its entry names are ultimately periodic. Let iter(R) be (R_{i})_{i∈C}. Every iterative relation defines an ω-regular language: the Büchi automaton that accepts the language defined by an iterative relation represented by the open relation S is (Q, E, {S}, {S}) with:

Q = {S(<p>) | p ∈ ℕ^{∗}} modulo ≃
E = {(S(<p>), j, S_{pj}) | j ∈ [n_{|p|}]}
where S_{q} = if □ (S, [|q|], <q >) then S else S(<q >)

The transition set E is finite because of the prefix regularity of S.

R = ⋃_{p∈P} ⋃_{i∈{ j∈C | ∀ <e> ∈R_{i}, <pe> ∈R}} { <pe> | <e> ∈ R_{i}} by definition of the ω-regularity of R. Each set {pe | <e> ∈ R_{i}} is ω-regular because ω-regularity of words is closed under concatenation, and the number of such sets is finite by prefix regularity of R. Being a finite union of ω-regular languages, {e | <e> ∈ R} is ω-regular.

Now let (Q, E, I, F) be a Büchi automaton such that there is a relation R with {e | <e> ∈ R} = L^{ω}(Q, E, I, F) and the entry names of R are ultimately periodic. R is a relation on ⨂_{i∈ℕ}[n_{i}]. Let R_{q} = { <e> | e ∈ L^{ω}(Q, E, {q}, {q})}. Each R_{q} is an iterative relation represented by the open relation:

S_{q} = {e ∈ ⨂_{i∈ℕ}[n_{i}] | ∃k, word (e_{([k])}) ∈ L^{∗}(Q, E, {q}, {q})}

These relations are prefix regular because the automaton is finite and the entry names are ultimately periodic. ∀e ∈ L^{ω}(Q, E, I, F), e is the label of an infinite path such that there is a q in F and q is in the set of infinitely repeated states of the path. Thus, there is a k such that <e>_{(∁[k])} is in R_{q}, and for all f ∈ R_{q}, word (<e>_{([k])}) word (f) is in L^{ω}(Q, E, I, F). So R is an ω-regular relation and iter(R) = (R_{q})_{q∈F}. □

The notion of ω-regularity of relations is a strict restriction of the ω-regularity of languages:

Example: The set {a, bb}^{ω} is an ω-regular language, but not an ω-regular relation. Suppose two entries i < j are equivalent. Then a^{j−1}bba^{ω} is in the relation, so a^{i−1}ba^{j−i}ba^{ω} is in the relation too, because of the equivalence of entries i and j. ♢

This strict restriction is necessary, because in the case of relations we have a notion of entry which is of greater importance than the notion of rank in the case of words of a language. We need to have a notion of regularity for the entries. Moreover, this restriction will allow for an important optimization commonly used for finite relations, namely path compression in decision diagrams.

The ultimate periodicity of entry names is preserved by union, intersection and negation of relations. So, we can extend some closure properties of ω-regular languages [Büc60]:

Property 4.5 ω-regular relations are closed under union, intersection and negation.

4.2 Decision Diagrams

There are two ways of representing relations: either as sets of vectors, or using a divide and conquer strategy based on the following observation: if R ⊂ ⨂_{i∈I} E_{i}, then for all k of I,

e ∈ R ⇔ e_{(∁{k})} ∈ R(e_{(k)})

If, moreover, I is totally ordered, then it is easy to see that this property can be the basis of a decision procedure.

In this section, we study the representation of relations as decision diagrams. The most general diagram is the multiple decision diagrams (denoted MDD) which is a simple extension of binary decision diagrams [Bry86, Bry92]. This extension, which was already introduced in [SKMB90, CMR92] for finite relations, consists in replacing binary choices at each variable, by choices in [n] depending on the variables. We start from this decision diagrams because it is well known [BCM^{+}90] that it is a very efficient way of representing binary relations that have brought considerable breakthrough to many areas in computer science. Moreover, as this representation have been studied from some time now, some efficient implementations are available [BRB90].

In the case of finite relations, the decision process, based on a decision tree, is quite standard. In the case of infinite relations, though, we must introduce new concepts, that will lead to an extension of BDDs for finite relation. Some work has already been done to represent infinite sets of finite relations [GF93], but this work is not adapted to the representation of infinite relations, in particular it does not describe no infinite behavior. So this extension, which relies heavily on the possibility to represent regular trees with maximal sharing, is the main contribution of this section.

4.2.1 MDD for Finite Relations

Let R be a finite relation of Rel. R is a relation on ⨂_{i<k}[n_{i}]. The decision tree for R, dt, is defined by:

pos(dt) =^{def} {p | ∃e ∈ ⨂_{i<k}[n_{i}], p ⪯ word (e)}

∀p ∈ pos(dt), dt(p) =^{def} |p| if |p| < k
=^{def} true if <p> ∈ R
=^{def} false if <p> ∉ R

Example: Let R be the relation {<111>, <200>, <201>, <210>, <211>} on [3]×[2]×[2]. If we call e_{i} the i^{th} entry of the relation, another way of describing it is the logical formula: “(e_{0} = 1 and e_{1} = 1 and e_{2} = 1) or e_{0} = 2”. The decision tree for this relation is:

        \xymatrix{ &  &  &  &  &  &  &  &  &  & 0 \ar@{-->}[dlllllll] \ar[d] \ar@{-->}[drrrrrrr] \\  &  &  & 1 \ar[dll] \ar[drr] &  &  &  &  &  &  & 1 \ar[dll] \ar[drr] &  &  &  &  &  &  & 1 \ar[dll] \ar[drr] \\  & 2 \ar@{-->}[dl] \ar@{-->}[dr] &  &  &  & 2 \ar@{-->}[dl] \ar@{-->}[dr] &  &  & 2 \ar@{-->}[dl] \ar@{-->}[dr] &  &  &  & 2 \ar@{-->}[dl] \ar[dr] &  &  & 2 \ar[dl] \ar[dr] &  &  &  & 2 \ar[dl] \ar[dr] \\ false &  & false &  & false &  & false & false &  & false &  & false &  & true & true &  & true &  & true &  & true}

or if we represent the tree with maximal sharing,

\xymatrix{ &  & 0 \ar[dll]_{0} \ar[d]^{1} \ar[drr]^{2} \\ 1 \ar[d]_{0} \ar[d]^{1} &  & 1 \ar[dll]_{0} \ar[d]^{1} &  & 1 \ar[d]_{0} \ar[d]^{1} \\ 2 \ar[dr]_{0} \ar[dr]^{1} &  & 2 \ar[dl]_{0} \ar[dr]^{1} &  & 2 \ar[dl]_{0} \ar[dl]^{1} \\  & false &  & true}

♢

As for binary relations, this tree corresponds to a decision procedure to determine whether a given element of ⨂_{i<k}[n_{i}] is in R. This decision procedure is slightly different from the standard one, due to the possible use of common names for equivalent entries. To illustrate this, we will describe the elements of ⨂_{i<k}[n_{i}] as functions from names to sets of integers: e(x) =^{def} {e_{(i)} | name_{R}(i) = x}. We define a function to read and delete an element of e, read(e, x) = (e′, m). This function is defined on elements such that e(x) ≠ ∅. Its result has the following property: m ∈ e(x) and e′ = e_{(∁{j})}, where j is such that name_{R}(j) = x and e_{(j)} = m. Then the decision procedure is:

     decision(e, true) =^{def} true
    decision(e, false) =^{def} false

decision (e, [figure: k; t_{0}; t_{n−1}] ) =^{def} decision(e′, t_{i}) where (e′, i) = read(e, name_{R}(k))

Example: We keep our example of the relation “(e_{0} = 1 and e_{1} = 1 and e_{2} = 1) or e_{0} = 2”. In this relation, the entries 1 and 2 are equivalent. So, we can choose name_{R}(0) = x, and name_{R}(1) = name_{R}(2) = y. Suppose we want to decide whether the vector <010> is in the relation. This vector can be described by the function e : x → {0}, y → {1, 0}. Note that the vector <001> would be described by the same function. The decision process starts with

decision(e, \xymatrix{ & & 0 \ar[dll] \ar[d] \ar[drr] \\ 1 \ar[d] \ar[d] & & 1 \ar[dll] \ar[d] & & 1 \ar[d] \ar[d] \\ 2 \ar[dr] \ar[dr] & & 2 \ar@{-->}[dl] \ar[dr] & & 2 \ar[dl] \ar[dl] \\ & false & & true} ). As name_{R}(0) is x, we first call read(e, x), which

can only yield (y →\{1, 0\}, 0). So, the next step is decision(y →\{1, 0\}, \xymatrix{1 \ar[d] \ar[d] \\ 2 \ar[d] \ar[d] \\ false}).

This time, read can give either (y →{1}, 0) or (y →{0}, 1). In the first case, we

call decision(y →\{1\}, \xymatrix{2 \ar[d] \ar[d] \\ false}), then decision (∅, false), so the result of the

decision process is false. Of course, the second case would have led to the same result. ♢

The decision tree can be simplified by elimination of nodes of the form [figure: x; t; t]

which are called redundant , because whatever the set e(x), the result of the decision procedure on this node will be the same. It is true even if x is the name of equivalent entries because if one way of reading its values holds a result, any way holds the same result. In fact, there is an interesting property about such nodes:

Property 4.6 Whatever the redundant node labeled by x, in the subtree of this node, any node labeled by x is redundant.

Proof: Let p be a path such that dt(p) = x and ∀i < n_{|p|}, dt_{[pi]} = dt_{[p0]}, and q such that dt(p0q) = x. Then as the entries |p| and |p0q| are equivalent, ∀i, j ∈ [n_{|p|}], dt_{[piqj]} = dt_{[pjqi]}. So dt_{[p0qi]} = dt_{[piq0]} = dt_{[p0q0]}. □

This property justifies the use of names of entries instead of entries as labels of the decision tree. We use it to simplify the presentation of relations.

The tree obtained from the decision tree after the elimination of every redundant nodes and represented in the way defined in chapter 2 is the multiple decision diagram. In a direct way, the MDD for the finite relation R is defined by the following algorithm:

mdd(R):

  return return return(mddbuild(R, ε))
mddbuild(R, e):
  if if if |e| = k then then then
   if if if <e> ∈ R then then then return return return(true true true)
   else else else return return return(false false false)

  else else else

   for for for i ← ← ← 0 to to to n_{|e|} − 1 do do do

t_{i} ← ← ← mddbuild(R, ei)

   if if if all the t_{i} are equals then then then return return return(t_{0})

else else else x ← ← ← name_{R}(|e|)

     return return return( [figure: x; t_{0}; t_{n_{|e|}−1}] )

In the case of binary relations such that all entry names are different, this gives the BDD of the relation.

Example: For the relation which was already illustrated above, described by: “(e_{0} = 1 and e_{1} = 1 and e_{2} = 1) or e_{0} = 2”, with entry name x for e_{0} and y for the equivalent entries e_{1} and e_{2}, the MDD is:

[figure: x; 0; 1; 2; y; 0; 1; y; 0; 1; false; true]

♢

4.2.2 Regular Infinite Relations

If we start from the decision tree to define the MDD of an infinite relation, then we will have the same decision tree for every relation, up to a renaming of the names of the entries. This decision tree would not in any way represent the relation. This is because trees are defined as functions from finite paths to labels, so we cannot give directly the value of the relation if it depends on an infinite vector.

The first step towards a finite representation is the use of entry names to share some entries in the graph representing the decision procedure. The second step is to be able to represent the infinite behaviors of the relations.

Examples: We start with a few examples to illustrate the rest of the section. The exact meaning of the diagrams and how they are built will be specified later. Intuitively, they are read like a decision diagram for a finite relation, except we

can loop and some arrows are of the form \xymatrix{x \ar@{|->}[d] \\ t}, which means that we can start the

description of an infinite behavior.

\xymatrix{ & x \ar@{|->}[dl]_{0} \ar[dr]^{1} \\ true &  & false}

represents the relation containing every vector starting with a 0. This relation is open. The finite behavior is that we must start with a 0. The infinite behavior is described by true and means that we can end with anything.

\xymatrix{ & x \ar@{|->}[dl]_{0} \ar@{|->}[dr]^{1} \\ x \ar[d]_{0} \ar[drr]^{1} &  & x \ar[dll]_{1} \ar[d]^{0} \\ true &  & false}

represents the relation containing the two vectors 0^{ω} and 1^{ω}. The finite behavior is that starting by a 0 or a 1, we get a different behavior. We have two possible infinite behaviors,

0^{ω}, represented by \xymatrix{0 \ar[d] & x & 1 \ar[d] \\ true & & false} , and 1^{ω}. The idea when decid-

ing whether a vector is in the relation is that we must start again the latest infinite behavior when we reach a true.

[figure: x; 0; 1; true]

represents the relation R containing any vector ending with 0^{ω}. The finite behavior of the relation does not describe the relation, because whatever the finite vectors u and v, R(u) ≃ R(v). The infinite behavior is 0^{ω}, and can be started after any 1. Intuitively, the decision process is a success if we reach a true infinitely often, but we must reset our count each time we start a new infinite behavior.

Note that in the last two examples, all entries are equivalent (i.e. if a vector is in the relations, whatever the permutations of the entries, the permuted vector is in the relation too). ♢ Open Relations

In the case of open relations, the only infinite behaviors are square relations. So, if we start the decision tree with such parts already shared and the empty sets shared too, the decision tree will represent the relation.

Let R ∈ Rel be an open relation. R is a relation on ⨂_{i∈ℕ}[n_{i}].

dt_{op}(R)(p) =^{def} true if □(R, [|p|], <p>) and nameiter(R, |p|)
=^{def} false if R(<p>) = ∅
=^{def} name_{R}(|p|) otherwise

With the convention that □(S, J, w) is S_{:J=w} = ⨂_{i∈I\J} E_{i} and nameiter(S, k) is ∀j ∈ ℕ, name_{S}(j + k) = name_{S}(j).

For a given naming of the entries, this leads to a canonical representation of an open relation, assuming there is a canonical representation of the tree (chapter 3).

Iterative Relations

An iterative relation is represented by an open relation. Given the decision tree of this open relation, the decision procedure uses a stacking mechanism: an infinite vector is considered as an infinite word and the decision tree is used as a determinist automaton. Each time the process of reading the vector reaches a true, we stack a true, and we read the rest of the vector, starting from the beginning of the decision tree. The process stops if we reach a false. The process is successful if it does not stop and we stack an infinite number of true.

Examples: Remember that iterative relations are used to represent the infinite behavior of the relations. For these examples to be more meaningful, we describe the type of infinite property they represent from the point of vue of temporal logic [Lam77, MP88].

  \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ true &  & false}

represents the relation containing just the vector 0^{ω}. It is an example of infinite behavior representing a safety property.

  [figure: x; 0; 1; true]

represents the relation that accepts any vector not ending by 1^{ω}, that is, with an infinite number of 0’s. It is an example of infinite behavior representing a liveness property.

[figure: x; 0; 1; x; 0; 1; x; 0; 1; true]

represents the relation with any vector with an infinite number of 0’s and 1’s. It is an example of infinite behavior representing a fairness property.

The problem with representing an iterative relation by an open relation, is that there are many open relations that can represent a given iterative relation.

In the first example (\{0^{ω}\}), we could have used \xymatrix{ & & x \ar@{-->}[dl] \ar[dd] \\ & x \ar[dl] \ar@{-->}[dr] \\ true & & false}. This looks like a

special instance of cycle growth, but we can have more complicated cases, as for the last example (every vector with an infinite number of 0’s and 1’s), where

we could have used [figure: x; x; true] or [figure: x; x; x; true] . It is an important result of this

chapter that there is indeed a canonical open relation for every iterative relation:

Property 4.7 Let R be an iterative relation. The relation S = {e| ∃u≺word (e), <u^{ω} > ∈ R and R(<u>) ≃ R} is the greatest (for set inclusion) open relation such that R = Ω (S).

Proof: In order to simplify the proof, we will consider that all entries of R are equivalent. It is easy to reduce the problem to this case by considering the relation on the product of every different entry name on the period of the relation. We will also ignore the distinction between vector and words, forgetting the casts for a better clarity.

S is an open relation, because whatever the element e of S, there is a u ≺ e such that ∀f, u.f ∈ S. R is iterative, so there is an open relation S′ such that R = Ω (S′). ∀e ∈ S′, there is a k such that □(S′, [k], e_{([k])}). Let k_{0} be the least such k. Because R = Ω (S′), e_{([k_{0}])}^{ω} is in R, and R(e) ≃ R. So e ∈ S, which means that S′ ⊂ S. To prove the property, we just have to prove that R = Ω (S). We will start by R ⊂ Ω (S), then prove Ω (S) ⊂ R.

Lemma: Let v be a vector such that □(S, [k], v) and for all j < k, not □(S, [j], v_{([j])}). Then v^{ω} ∈ R and R(v) ≃ R. Whatever e, v.e ∈ S. Because of the minimality of v with respect to the “square” property, for each e, there is a l such that (v.e_{([l])})^{ω} ∈ R and R(v.e_{([l])}) = R. Let e = v_{(0)}^{ω}. There is an l such that (v.v_{(0)}^{l})^{ω} ∈ R. Because all entries of R are equivalent, by property 4.1, v^{ω} ∈ R. Let e ∈ R. Because R is an infinite relation, e is infinite, so there is an i ∈ ℕ that is repeated infinitely often in e. But there is an l such that R(v.i^{l}) ≃ R. So v.i^{l}.e ∈ R, and by the equivalence of all entries (property 4.2), v.e ∈ R, which means that e ∈ R(v). Conversely, if e ∈ R(v), v.i^{l}.e ∈ R, and so e ∈ R. Thus R ≃ R(v). ∘

Let e ∈ R. We suppose e ∉ Ω (S). If there is a k such that □(S, [k], e_{([k])}), let k_{0} be the least such k. Then e_{(∁[k_{0}])} ∉ Ω (S), but R(e_{([k_{0}])}) ≃ R, so e_{(∁[k_{0}])} ∈ R. So we can iterate on e_{(∁[k_{0}])}. This iteration is finite because e ∉ Ω (S), so we come to a point where there is no k such that □(S, [k], e_{([k])}). But e ∈ R, so there is a k_{0} such that □(S′, [k_{0}], e_{([k_{0}])}), and e_{([k_{0}])}^{ω} ∈ R and R(e_{([k_{0}])}) ≃ R, and so □(S, [k_{0}], e_{([k_{0}])}), which contradicts the hypothesis. Thus R ⊂ Ω (S).

Let e ∈ Ω (S). Let (k_{i})_{i∈ℕ} be the sequence: k_{0} = min {k | □(S, [k], e_{([k])})} and k_{i+1} = min {k | □(S, [k − k_{i}], e_{([k_{i},k[ )})}. We call u_{0} = e_{([k_{0}])}, and u_{i+1} = e_{([k_{i},k[ )}. Some u_{i}’s appear infinitely often in e, and some u_{i}’s appear only finitely often in e. So there is a permutation of the entries such that the result of the permutation on e is e_{f}.e_{ω}, where e_{f} is the concatenation of all u_{i}’s that appear finitely in e (times the number of times they appear), and e_{ω} is composed of those u_{i}’s that appear infinitely in e only. By definition of Ω (S), e_{ω} ∈ Ω (S), and because all entries of R are equivalent, e_{f}.e_{ω} is in R if and only if e is in R. But whatever u_{i}, R(u_{i}) ≃ R (see the lemma). So R(e_{f}) ≃ R. And so e is in R if and only if e_{ω} is in R. Either e_{ω} contains a finite number of distinct u_{i}’s, or an infinite one.

If e_{ω} contains a finite number of distinct u_{i}’s, we call them (v_{i})_{i∈[m+1]}. Then there is a permutation of the indexes such that the result of the permutation on e_{ω} is (v_{0}.v_{1} … v_{m})^{ω}. We know that v_{m}^{ω} ∈ R (see the lemma), and for all i, R(v_{i}) ≃ R, so v_{0}.v_{1} … v_{m−1}.(v_{m})^{ω} ∈ R. We call f = v_{0}.v_{1} … v_{m−1}.(v_{m})^{ω}. Because f ∈ R, there is a sequence (k′_{i})_{i∈ℕ} such that: k′_{0} = min {k | □(S, [k], f_{([k])})} and k′_{i+1} = min {k | □(S, [k − k′_{i}], f_{([k′_{i},k[ )})}. So there is a j such that f_{([k′_{j}])} = v_{0}.v_{1} … v_{m−1}.v_{m}^{n}.w with w ≺ v_{m}. Whatever i, f_{([k′_{i}])}^{ω} ∈ R, because R = Ω (S′). So, by property 4.1, (v_{0}.v_{1} … v_{m})^{ω} ∈ R. This, in turn, means that e_{ω} ∈ R.

If e_{ω} contains infinitely many distinct u_{i}’s, we call them (v_{i})_{i∈ℕ}. Because the relation is over a finite set [n_{0}], e is composed of finitely many letters, (a_{i})_{i≤m} (and m < n_{0}). Each a_{i} appears in one v_{j} at least, so it appears infinitely often in e. Because this set of letters is finite, there is a finite sequence (v_{i})_{i∈J} such that for each letter, there is an i ∈ J such that v_{i} contains the letter. So there is a permutation of the entries that transforms e_{ω} into (⨀_{i∈J}^{<} v_{i})^{ω}. So we are back to the problem with e_{ω} containing a finite number of u_{i}’s.

Thus, e_{ω} ∈ R whatever the case, which proves that e ∈ R. We started from e ∈ Ω (S), so Ω (S) ⊂ R. Because we already proved R ⊂ Ω (S), we have R = Ω (S). □

With this property, we now have a canonical representation for an iterative relation, that is, the canonical representation (defined by dt_{op}) of the greatest open relation representing the iterative relation.

Sets of Iterative Relations

Let R be the union of a finite set of iterative relations. Let these relations be indexed: R = ⋃_{i∈C} R_{i}. Each R_{i} is represented by an open relation S_{i}. Then, it is possible to build a decision tree representing R based on the decision trees of the open relations. Here is an algorithm building such a tree: dt_{set}(R):

  return return return(dtset((dt_{op}(S_{i}))_{i∈C}, 0))

dtset((t_{i})_{i∈C}, p):

  node ← ← ← false false false

K ← ← ← ∅

  ∀i ∈ C do do do
   if if if t_{i} = false false falsethen then then
     for for for j ← ← ← 0 to to to n_{p} − 1 do do do t_{i}_{j} ← ← ← false false false
   else else else if if if t_{i} = true true truethen then then
     if if if node = false false falsethen then then node ← ← ← true true true

K ← ← ← K ∪ {i}

     for for for j ← ← ← 0 to to to n_{p} − 1 do do do t_{i}_{j} ← ← ← s_{i}_{[j]}

else else else t_{i} ← ← ← [figure: x; u_{0}; u_{np−1}]

     node ← ← ← x
     for for for j ← ← ← 0 to to to n_{p} − 1 do do do t_{i}_{j} ← ← ← u_{j}
  if if if node = false false falsethen then then return return return(false false false)
  if if if node = true true truethen then then return return return(true true true_{K})

for for for j ← ← ← 0 to to to n_{p} − 1 do do do v_{j} ← ← ← dtset((t_{i}_{j})_{i∈C}, p + 1)

  return return return( [figure: x_{K}; v_{0}; v_{np−1}] )

The decision procedure starts with an empty stack and a set of valid indexes of iterative relations V = C. Each time we encounter a node x_{K}, we stack the set V ∩ K. If we encounter a node false, we stop. If we encounter a node true_{K}, we stack V ∩ K and we keep going with the new set of valid indexes, V ∩ K. The process is successful if it doesn’t stop and if there is an element of C such that there is an infinite number of sets in the stack containing it. We can notice that false is the same as true_{∅}, and that we can stop as soon as the set of valid indexes is empty.

Examples:

         \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ true &  & false} ⋃ \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ false &  & true} = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ _{true_{\{1\}}} &  & _{true_{\{2\}}}}

[figure: x; 0; 1; x; 0; 1; x; 0; 1; true] ⋃ \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ true & & false} = [figure: x; 0; 1; x_{\{2\}}; 0; 1; x; 1; 0; _{true_{\{1\}}}]

♢

Regular Relations

Let R be an ω-regular relation. Then R is associated with a finite set of iterative relations, iter(R) = (R_{i})_{i∈C}. We define a function to describe the infinite behavior of the relation:

∀p ∈ ℕ^{∗}, infbehave_{R}(p) =^{def} {i ∈ C | ∀f ∈ R_{i}, <p. word (f)> ∈ R}

The decision tree for a regular relation is the same as for a finite relation, except that when the prefix p of a vector is such that infbehave_{R}(p) is not empty, we use the representation of the set of iterative relations associated with p. In order to mark the switch between the standard interpretation of the decision tree, and the interpretation as a set of iterative relations, we use a new node, which is not a decision node, iter. These nodes replace the true nodes in order to take into account the fact that even when we start a process of infinite behavior, there can still be finite decisions that lead to another infinite behavior.

dt_{reg}(R):

  return return return(dtfinite(ε))
dtfinite(p):
  if if if infbehave_{R}(p) = ∅ then then then

x ← ← ← name_{R}(|p|)

   for for for i ← ← ← 0 to to to n_{|p|} − 1 do do do t_{i} ← ← ← dtfinite(pi)

   return return return( [figure: x; t_{0}; t_{n_{|p|}−1}] )

else else else t ← ← ← dtinf (dt_{set}(⋃_{j∈infbehave_{R}(p)} R_{j}), p)

   return return return( \xymatrix{_{iter_{∅}} \ar[d] \\ t} )

dtinf(t, p):

  if if if t = false false falsethen then then return return return(dtfinite(p))
  else else else if if if t = true true true_{K} then then then

u ← ← ← dtinf (dt_{set}(⋃_{j∈infbehave_{R}(p)} R_{j}), p)

   return return return( \xymatrix{_{iter_{K}} \ar[d] \\ u} )

else else else t is of the form [figure: X; t_{0}; t_{n−1}], with n > 0

   for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← dtinf(t_{i}, pi)

   return return return( [figure: X; u_{0}; u_{n−1}] )

The decision process is still a stacking mechanism. While reading an infinite vector, we stack K each time we encounter a x_{K}, and iter_{K} each time we go through these nodes. The process is successful if, after some point in the stack, we can treat each iter_{K} as a true_{K} as in sets of iterative relations and this new stack is a successful one for a set of iterative relations.

Examples: The empty relation (false) will be represented by an infinite decision tree of the form [figure: x] and the square relation (true) by an infinite

decision tree of the form [figure: rec_{{0}}; x].

\xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ _{iter_{\{1\}}} \ar[ur] &  & _{iter_{\{2\}}} \ar[ul]} is the relation with any vector ending by 1^{ω} or 0^{ω}.

♢

4.2.3 ω-deterministic Relations

The representation of regular relations as decision trees is not very efficient, in the sense that there are many sources of non-uniqueness, and therefore many algorithms on these decision trees are not efficient. The worst problem is the choice of iterative relations and of the indexes of these relations. In particular, the relations must be reindexed for any basic boolean operation. These problems come from the non deterministic nature of ω-regular languages, and in fact the decision process itself is non deterministic.

So we introduce a new class of relations, ω-deterministic relations. The idea is to restrict the possible infinite behavior of the relation for a given prefix to at most one iterative relation. It is obvious then that this class of relations is not closed under union, but it seems to be dense enough to be used as an approximation of regular relations. This approach is easy to exploit in the framework of abstract interpretation.

We first start by a definition of the iterative behavior of a relation at a vector u: a relation R defines an iterative relation for each vector u. This relation is denoted R_{[u]}^{Ω}. It is the iterative relation represented by the open relation:

{e | ∃v ≺ word (e) , (word (u) .v^{ω}) ∈ R and R(<word (u) .v >) ≃ R(u)}

Definition: A relation R is said to be ω-deterministic if and only if R is prefix regular and for all u, R_{[u]}^{Ω} ⊂ R(u). The following property justifies the denomi-

nation “deterministic”, because it shows that there is always a canonical iterative relation representing the infinite behavior at a given point:

Property 4.8 An ω-deterministic relation R is ω-regular, and whatever the relations in iter(R) representing the infinite behavior at a given point u, there is an iterative relation representing the infinite behavior at u and containing all of them.

Proof: Let R be an ω-deterministic relation. We first prove that R is ω-regular. We define iter(R) = {R_{[u]}^{Ω} | R_{[u]}^{Ω} ≠ ∅}. This set is finite because R is prefix regular. Let e ∈ R. If e is ultimately periodic, as R is prefix regular, there is a u and a v such that R(<u.v >) = R(<u>) and e = <u.v^{ω} >. Then R_{[u]}^{Ω} ≠ ∅, and for all f ∈ R_{[u]}^{Ω}, <u. word (f)> is in R because R is ω-deterministic. If e is not ultimately periodic, as the entry names are ultimately periodic, there is a permutation of the entries which transforms e in f which is ultimately periodic. Moreover, it is possible to choose the permutation that it leaves u unchanged (we start after the last letter that appears finitely many times and after the looping of the relation) such that f = <u.v^{ω} > as above. As the R_{[u]}^{Ω} have the same equivalence of entries as f(u) (at least), we have the postfix of e after u is in R_{[u]}^{Ω}.

Concerning the canonicity of the iterative relation at a given point, we have the fact that for all iterative relation at u of R, the iterative relation is included in R_{[u]}^{Ω}. □

Decision Tree

Let R be an ω-deterministic relation. Each R_{[u]}^{Ω} is represented by the decision tree of the greatest possible open relation, dt_{u}. The idea is the same as for a regular relation, but there is no need for indexes, and each time we come to a true, we don’t have to take into account the possibility of another infinite behavior. Thus, the only iter nodes will be iter_{∅}. We can see the use of these nodes as a tagging

of some edges. Thus, as a shorthand, we will sometime write \xymatrix{x \ar@{|->}[d] \\ t}for \xymatrix{x \ar[d] \\ iter \ar[d] \\ t}.

dt_{ω}(R):

  return return return(dtfinite_{ω}(ε))
dtfinite_{ω}(p):
  if if if R(<p>) = ∅ then then then return return return(false false false)
  else else else if if if R_{[p]}^{Ω} = ∅ then then then

x ← ← ← name_{R}(|p|)

   for for for i ← ← ← 0 to to to n_{|p|} − 1 do do do t_{i} ← ← ← dtfinite_{ω}(pi)

   return return return( [figure: x; t_{0}; t_{n_{|p|}−1}] )

else else else

t ← ← ← dtinf_{ω} (dt_{p}, p)

return return return( \xymatrix{iter \ar[d] \\ t})

dtinf_{ω}(t, p):

if if if t = false false falsethen then then return return return(dtfinite_{ω}(p))
else else else if if if t = true true truethen then then return return return(true true true)

else else else t is of the form [figure: x; t_{0}; t_{n−1}], with n > 0

for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← dtinf_{ω}(t_{i}, pi)

return return return( [figure: x; u_{0}; u_{n−1}] )

The decision process reads a vector and uses a stack S and a current iterative tree, r. At the beginning, the stack is empty and r = dt_{ω}(R). When we come

to a true node, we stack it and start again at r. When we come to a \xymatrix{iter \ar[d] \\ t} node,

r becomes t and we empty the stack. If we come to a false node, we stop the process. The process is a success if it doesn’t stop and the stack is infinite. If t is such a decision diagram, we denote by R_{ω}(t) the set of vectors for which this process is a success.

Examples:

\xymatrix{ & x \ar@{|->}[dl]_{0} \ar@{|->}[dr]^{1} \\ x \ar[d]_{0} \ar[drr]^{1} &  & x \ar[dll]_{1} \ar[d]^{0} \\ true &  & false}

when we read a 0, the current iterative tree becomes

\xymatrix{ & x \ar[dl] \ar@{-->}[dr] \\ true & & false} . If we read a 1 after that, we stop on a failure,

and if we read a 0, we stack a true and start again with the same iterative tree. So, after a 0, we can only have 0^{ω}. After

a 1, the iterative tree becomes \xymatrix{ & x \ar@{-->}[dl] \ar[dr] \\ false & & true} , and this time, we

can only have 1^{ω}. So this relation is {0^{ω}, 1^{ω}}.

[figure: x; 0; 1; true]

during the decision process, the iterative tree never changes. When we read a 0, we stack a true and start again. But each time we read a 1, we empty the stack. So the only vectors that stack an infinite number of true are the vectors ending by 0^{ω}.

[figure: x; 0; 1; x; 0; 1; true]

after the first 1 is read, the current iterative tree does not change. If we have read an odd number of 1’s, when we read a 0, we stack a true and start the process again. So any vector with an odd number of 1’s is in the relation. If we read a 1, we cannot stack another true before emptying the stack. So the relation contains no vector with an infinite number of 1’s. Finally, if the number of 1’s is even, we cannot stack any more true if there is no more 1. So, the relation is exactly the set of vectors with a finite odd number of 1’s (and so ending with 0^{ω}).

♢

Open relations are ω-deterministic. Their representation as an ω-deterministic relation is the same tree as dt_{op}, with a iter node before the true nodes.

Redundant Nodes

A node is redundant if it is either of the form [figure: x; t; t]or of the form [figure: x; t; t]. In the

first case, we can replace it by the t node, and in the second case by the \xymatrix{iter \ar[d] \\ t}

node. Having two consecutive iter nodes is impossible, as we forbid the empty relation in the set of iterative relations. Note that this elimination of redundant nodes may lead to a recursive process if the current node is also a subtree of t (it is in a loop). In this case, we can directly have any arrow that pointed to the node point to t.

After elimination of redundant nodes, we obtain the MDD of the relation. If we consider finite relations as open relations (which is usually the case when using BDD), we obtain the same decision diagram, except for the iter node before true nodes.

Property 4.9 The representation of an ω-deterministic relation by means of the tree dt_{ω}, where every redundant node have been eliminated, and represented with maximal sharing is unique.

This property is a consequence of the canonicity of the iterative relations and the canonicity of the open relations representing these iterative relations.

4.2.4 MDD with Large Sets of Choice

The power of MDD comes from the sharing and the elimination of redundant nodes. But the larger the choice space for a given entry, the less likely a node for this entry is to be redundant.

A natural solution^{3} to this problem is the representation of a given entry with choice space [n] by ⌈log_{2}(n)⌉ binary variables. A given integer of [n] is written as a binary word. The only problem with this solution is that the access time is longer, since you need ⌈log_{2}(n)⌉ times more indirections to read the values of a vector.

In our case, this representation is not very well suited, as we will need for each variable an entire new set of fresh variables which needs to be stored too. This results in a new indirection in the use of relations, but experience proves, that this technique provides good results as soon as the set of choice is “large enough”.

4.3 Algorithms on ω-deterministic Relations

These algorithms manipulate ω-deterministic relations represented by a decision diagram, as defined in the previous section.

4.3.1 Canonicity of the representation

The representation of the decision tree for an ω-deterministic relation relies on shared regular tree (see chapter 3). By property 4.9, the decision tree for a relation is unique, so we have a unique representation of ω-deterministic relations. But the problem is that not all regular trees are valid decision trees of a relation, so we must maintain some properties on the decision trees when manipulating relations. Those properties concern the “special” nodes of the decision trees: true, false and iter. For example, if during the computation, we obtain [figure: x] or [figure: x] , we must recognize false.

The idea is that we will describe the algorithms on ω-deterministic relations as regular tree transformations. The problem of the uniqueness will be supposed to be taken care of by treating the “special” nodes in the way described below. In this way, we will separate the two algorithmic problems. Moreover, the treatment of special nodes is not too hard to handle as they correspond to graph properties that can easily be verified.

The iter Node

4.3. ALGORITHMS ON ω-DETERMINISTIC RELATIONS 65

From the decision procedure for ω-regular relations, it is easy to see when the iter node is not useful. It is not useful if the iterative tree it points to is never used to restart the decision process. That is, there is no path from the iter node to a true node that does not go through another iter node. Thus, when we create a new iter node, the only information we need is whether the node it points to may lead to a true node, which is easily performed by returning this information for each node. In order to exclude paths going through an iter node, the iter node then returns false.

3See [SKMB90] for an example of implementation.

If the iter node is inside a cycle, though, deciding whether there is a path from this node to a true node is a little more complex. The point is that we must avoid infinite computation by considering some edges as not relevant because they cannot add a correct path to true if there is not one revealed by the edges considered as relevant. If the iter node is the root of the cycle we consider, the return edges are exactly the non relevant edges. Thus all we have to do is consider the iter node as the root of the cycle, that is we forget any node of the cycle that was already visited to compute whether this node is useful.

If the iter nodes are correct, then we can use them to help the computation of the other special nodes. For example, we know that there is a path leading from the iter node to a true node, so the iter node is not equivalent to false.

The false Node

Once again, the decision procedure gives a straightforward algorithm to determine whether a newly created node is equivalent to false. It is the case if there is no path leading from this node to true. This information is very easy to extract from the graph we are building too. If the node is not in a cycle, then we suppose that its children are uniquely represented, thus the node is equivalent to false if and only if all its children are false. Note that this operation is already automatically performed by the elimination of redundant nodes.

If the node is in a cycle, we just return the pertinent information, that is, whether there is a path leading from this node to true. If any node in the cycle is equivalent to false, then every node in the cycle is equivalent to false. Thus, the information that will decide whether the entire cycle is equivalent to false is the information returned by the root of the cycle. In the cycle, return edges return the information that they don’t lead to a true node, because they don’t add no new path that would lead to true.

The true Node

In fact true nodes can be seen as tags on some return edges. Thus striving for canonicity of the representation will raise again the problems of cycle growth and root unfolding that are inherent in regular trees. The problems are a little different, though, because the equivalent of cycle growth reduction for tagged cycles is the determination of the greatest open relation. Concerning root unfolding, the problem is a little simpler in the case of these cycles, though, because the root of the tagged cycle is always an iter node (although it is not always the root of non tagged cycles, as the representation of the relation containing a finite odd number of 1 shows).

The Greatest Open Relation Finding the greatest open relation representing a given iterative relation is very similar to cycle growth reduction, because if an open relation is greater than another one representing the same iterative relation, the length of the cycles is smaller for the greater relation (we arrive sooner to a

true).

In order to keep things simple, we start by describing the algorithm to build the greatest open relation for an iterative relation. In the general case, this corresponds to an iterative relation which never leads to an iter node.

Examples: We present a few examples of open relations and the greatest open relation representing the same iterative relation. The first two examples have already been presented when proving that such a greatest open relation exists (page 56). The first one corresponds to the relation {0^{ω}} and the second one to the relation with every vectors containing an infinite number of 0’s and an infinite number of 1’s. The last example is more complicated and shows the interest of some parts of the algorithm, namely the distinction between the different R(v). This relation R is the set of all vectors with an infinite number of 1’s, and if the total number of 0’s and 1’s in the vector is finite, the number of 0’s is equal to the number of 2’s modulo 2. Here, R ≃ R(<1>) ≃ R(<02>) but is different from R(<0>).

            [figure: bestOpen; (; x; 0; 1; x; 0; 1; true; false; ); =; x; 0; 1; true; false]

[figure: bestOpen; (; x; 0; 1; x; 0; 1; true; ); =; x; 0; 1; x; 0; 1; x; 0; 1; true]

[figure: bestOpen; (; x; 1; 0; 2; x; 0; 1; 2; x; 0,2; 1; x; 0,2; 1; x; 0,2; 1; true; ); =; x; 1; 0,2; x; 0,2; 1; x; 0,2; 1; true]

♢

bestOpen(R):

R is a relation on ⨂_{i∈ℕ}[n_{i}] L is the function defined as L(R(e)) = ∅, for all e finite vector

  for for for i ← ← ← 0 to to to n_{0} − 1 do do do t_{i} ← ← ← bestOpenRec(ε, i, ∅, L, ∅,false false false)
  if if if all t_{i} are equal then then then return return return(t_{0})

x ← ← ← name_{R}(0)

  return return return( [figure: x; t_{0}; t_{n_{0}−1}] )

bestOpenRec(v, a, V, L, T, omega):
  if if if R(<va>) = ∅ then then then return return return(false false false)

x ← ← ← name_{R}(|va|) and n ← ← ← n_{|va|}

  if if if nameiter(R, |a|) then then then
   if if if omega or <va^{ω} > ∈ R then then then
     if if if R(<va>) ≃ R then then then return return return(true true true)

     else else else omega′ ← ← ← true true true
   else else else omega′ ← ← ← false false false

V′ ← ← ← V ∪ {a}

   if if if V′ ⊂ L(R(<va>)) then then then return return return(T (R(<va>)))

Let X be a new label

T′ ← ← ← T with R(<va>)→X L′ ← ← ← L with R(<va>)→V′

   for for for i ← ← ← 0 to to to n − 1 do do do t_{i} ← ← ← bestOpenRec(va, i, V′, L′, T′, omega′)
   if if if all t_{i} are equal then then then return return return(recCons(t_{0}, X))

   return return return(recCons ( [figure: x; t_{0}; t_{n−1}] , X))
  else else else

   for for for i ← ← ← 0 to to to n − 1 do do do t_{i} ← ← ← bestOpenRec(v, ai, V, L, T, omega)
   if if if all t_{i} are equal then then then return return return(t_{0})

   return return return( [figure: x; t_{0}; t_{n−1}] )

Proof: Let dt = bestOpen(R). S is the greatest open relation representing R. In order to simplify the proof, we suppose all entries of R are equivalent.

Whatever the word v such that the algorithm actually reaches v and decides that dt(v) = true or false, v ∈ pos(dt_{op}(S)) and dt(v) = dt_{op}(S)(v). The reason of this fact is: whatever u ≺ v, u is actually reached by the algorithm, so (u^{ω} ∈ R and R(u) ≃ u) is false, and R(u) = ∅ is false (or else the algorithm would have stopped at u), so v ∈ pos(dt_{op}(S)). If dt(v) = false, then R(<v >) = ∅, so dt_{op}(S)(v) = false. If dt(v) = true, then R(<v >) ≃ R, and either <v^{ω} > ∈ R or omega is true. But if omega is true, then there is u ≺ v such that <u^{ω} > ∈ R. v = uw. Because R(<v >) ≃ R, <uw(u)^{ω} > ∈ R. By equivalence of the entries of R, <w(u)^{ω} > ∈ R, so <(wu)^{ω} > ∈ R, and finally <(uw)^{ω} > ∈ R. Thus dt_{op}(S)(v) = true.

All we have to prove now, to show that dt = dt_{op}(S)^{4}, is that every return edge introduced in the algorithm (by the new labels and recCons construction) is valid. We prove that whatever such return edge at word v, going back to u ≺ v, whatever w, dt_{op}(S)(vw) = dt(vw). Because dt_{[v]} = dt_{[u]}, we just have to prove that dt_{op}(S)(vw) = dt(uw). We use the property that R(<u>) ≃ R(<v >), and every letter in v is in u.

Suppose dt_{op}(S)(vw) = false. Then R(<vw >) = ∅ and for all v′ ≺ vw, R(<v′ >) ≠ ∅, and <v^{′ω} > ∉ R or R(<v′ >) ≄ R. Because R(<u>) ≃ R(<v >), R(<uw >) = ∅. If there is u′ ≺ uw such that dt(u′) = false, u′ cannot be a prefix of u, else u′ is a prefix of v, and so of vw, and we cannot have a prefix of vw such that the relation is empty on that prefix. So u′ = uw′ with w′ ≺ w. But R(<uw′ >) ≃ R(<vw′ >) and vw′ ≺ vw. Suppose dt(u′) = true, we still have u′ = uw′. We prove in the next paragraph that dt_{op}(uw′) is true. So dt(uw) = false. The converse is obvious.

Suppose dt_{op}(S)(vw) = true. Then R(<vw >) ≃ R and <(vw)^{ω} > ∈ R and for all v′ ≺ vw, R(v′) ≠ ∅, and <v^{′ω} > ∉ R or R(<v′ >) ≄ R. Because R(<u>) ≃ R(<v >), R(<uw >) ≃ R. Because every letter of v is in u and every entry of R is equivalent, we know from property 4.1 that <(uw)^{ω} > ∈ R. If there is u′ ≺ uw such that dt(u′) = false, then R(<uw >) would be empty. If dt(u′) = true, u′ = uw′. We would have R(<vw′ >) ≃ R(<uw′ >) ≃ R, and because <(uw′)^{ω} > ∈ R, <(vw′)^{ω} > ∈ R (because u ≺ v), which is forbidden by maximality of S. So dt(uw) = true. Conversely, we already proved that if dt(uw) = true, then R(<vw >) ≃ R and <(vw)^{ω} > ∈ R. If v′ ≺ vw is such that dt_{op}(S)(v′) = false, we cannot have R(<vw >) ≃ R. If there is a v′ ≺ vw such that dt_{op}(S)(v′) = true, we cannot have v′ ≺ v, or else the algorithm would not have gone beyond v′, so v′ = vw′. We already proved that in this case, dt(uw′) = true, and uw′ ≺ uw. So dt_{op}(S)(vw) = true. □

Note that the algorithm terminates because, at each recursive call, one element of the function L increases, and by prefix regularity of R, the number of distinct R(e) is finite, and the number of different choices over a period of the entries of R is finite too.

For this algorithm to be complete, we must also explain how we test <v^{ω} > ∈ R and the equivalence of different R(e). R is represented by the decision tree dt of an open relation, which, at this point, is not necessarily the greatest one.

Concerning <v^{ω} > ∈ R, we use the fact that it is a necessary and sufficient condition that there is a k > 1 such that in the decision process, v^{k} reaches a true. All we have to do is to perform the decision process while storing the pairs (u, t) where u ⪯ v and t ⋖ dt, and if we come to such a pair twice, we stop in failure, and if we reach a truewe stop in success.

Concerning the equivalence of R(e) and R(f), we start from the two subtrees of dt, t_{e} and t_{f} which are reached respectively from the decision process on e and f. We compare every pair of subtrees which we can reach from t_{e} and t_{f}, and every time we come again on this pair on the decision process, we must have passed through true in both subtree or in none. The algorithm is:

4up to elimination of redundant nodes, which is not performed in dt_{op}(S).

compareRel(t, u, S, dt):
  if if if t = u then then then return return return(true true true)
  if if if (t, u) ∈ dom(S) then then then

(b_{1}, b_{2}) ← ← ← S(t, u)

   return return return(b_{1} = b_{2})
  S′ ← ← ← S with (t, u)→(false false false,false false false)

t is [figure: x; t_{0}; t_{n−1}], and u is [figure: x; u_{0}; u_{n−1}]

  for for for i ← ← ← 0 to to to n − 1 do do do
   if if if u_{i} = false false falsethen then then
     if if if t_{i} ≠ false false falsethen then then return return return(false false false)
   else else else if if if t_{i} = false false falsethen then then return return return(false false false)
   else else else if if if t_{i} = true true truethen then then
     if if if u_{i} ≠ true true truethen then then

S′ ← ← ← S′ with all values (b_{1}, b_{2}) of S′ become (true true true, b_{2})

       if if if compareRel(dt, u_{i}, S′, dt) = false false falsethen then then return return return(false false false)
   else else else if if if u_{i} = true true truethen then then

S′ ← ← ← S′ with all values (b_{1}, b_{2}) of S′ become (b_{1},true true true)

     if if if compareRel(t_{i}, dt, S′, dt) = false false falsethen then then return return return(false false false)

   else else else

     if if if compareRel(t_{i}, u_{i}, S′, dt) = false false falsethen then then return return return(false false false)
  return return return(true true true)

If the iterative relation is inside a loop, or if there is a path from the decision tree of the iterative relation to an iter node, we must consider this node as a falsewhile performing the construction of the greatest open relation. We must also propagate this information upward, as in the general treatment of the false nodes. Because this last node must be restored after the computation, we introduce false nodes subscripted by the nodes to which they are equivalent in the general decision diagram. In this way, they are treated as different nodes by the sharing algorithm on trees. If the iterative relation is inside a loop, it is possible that there is a path from a node N in one of the false_{N} to the original iter node starting the iterative relation. In this case, we must replace in N this iter node by the new one corresponding to the greatest open relation representing the iterative relation.

Root Unfolding In classical cycles, we need to build a complex key (a tree) and a simple key (a label plus the children nodes) to deal with root unfolding, for each node in the cycle. In the case of tagged cycles, there is no need for the complex key, as they are already represented by trees. But we must still define the simple keys, and for each simple key the tree representing the tagged cycle rooted at this node. The problem with tagged cycles, is that not every node in the cycle can be the root of the cycle. Only the nodes corresponding to iterative relations can be the root of the cycle.

Example: This representation has only one possible key , because, if R is the relation it represents, R(<1>) is not iterative. (R is the set of vectors with either an infinite number of 1’s, or an even number of 1’s.)

[figure: _{x _{1}}; 0; 1; x; 0; 1; true; and the key is; x; 0; 1; x; 0; 1; □_{1}]

♢

Property 4.10 Let R be an iterative relation represented by the tree dt. The relations R(<u>) is iterative if and only if for every path v that goes from the root of dt to true, there is a w ≺ v such that R(<w >) ≃ R(<u>). Such a relation is called unavoidable^{5} for dt.

Proof: Let R(<u>) be unavoidable. Then R(<u>) is iterative and represented by the decision tree defined as dt(u) where true have been dt in which every node equivalent to R(<u>) is replaced by true. It is obvious that any vector recognized by this “sliding” of the decision tree is in R(<u>), and reciprocally.

If R(<u>) is not unavoidable, then there is a path v such that dt(v) = true and for all w ≺ v, R(<w >) ≄ R(<u>). There is a path u′ such that dt(u.u′) = true. Then <u′.v^{ω} > ∈ R(<u>). But in this path, there is no point such that R(<u′.v^{k}.w >) ≃ R(<u>, so R(<u>) is not iterative. □

Because we already performed the bestOpen algorithm, we know already which nodes correspond to equivalent relations. We note R_{t} for the relation corresponding to the subtree t of the decision tree. The following algorithm computes the set of unavoidable relations.

5Such sets of nodes would be called dominators of true in [AHU74], if we were in an acyclic graph.

unavoidableSet(dt):
return return return(unavoidableSetRec(dt, {false false false})
unavoidableSetRec(t, T):
if if if t ∈ T then then then return return return({∅})
if if if t = true true truethen then then return return return(∅)

t is [figure: x; t_{0}; t_{n−1}]

T′ ← ← ← T ∪ {t} i ← ← ← 0

 do do do

  E ← ← ← unavoidableSetRec(t_{i}, T′)

i ← ← ← i + 1

while while while E = {∅} and i < n
if if if E = {∅} then then then return return return(E)
for for for j ← ← ← i to to to n − 1 do do do
  E′ ← ← ← unavoidableSetRec(t_{i}, T′)
  if if if E′ ≠ {∅} then then then E ← ← ← E ∩ E′
return return return(E ∪ R_{t})

When this set of relations is computed, we just add in the key dictionary the trees and unfoldings corresponding to each unavoidable node. The decision tree corresponding to the unavoidable relation R is called dt_{R}. Remind that D is the set of keys used for the uniqueness of the trees.

addKeys(dt):
US ← ← ← unavoidableSet(dt)
S is the function true true true→ \xymatrix{iter \ar[d] \\ dt}, false false false→false false false
return return return(addKeysRec(dt, S))

addKeysRec(t, S):
if if if t ∈ dom(S) then then then return return return(S(t))

t is [figure: x; t_{0}; t_{n−1}]

if if if R_{t} ∈ US then then then

  w ← ← ← \xymatrix{iter \ar[d] \\ _{dt_{R_{t}}}}

S′ ← ← ← S with t→w and without all s→Y

  for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← addKeysRec(t_{i}, S′)

k is the key (x, u_{0}, …, u_{n})

change in D the value associated with k to be w

  return return return(w)

  else else else

X is a new label of arity 0 S′ ← ← ← S with t→X

   for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← addKeysRec(t_{i}, S′)

   return return return(recCons ( [figure: x; u_{0}; u_{n−1}] , X))

We must also deal with root unfolding each time we build a new cycle, either tagged or not. This is performed for generic trees through the use of the shareWithDone algorithm. We can still use the same algorithm (it must be used each time we introduce a iter node also), but with the modification that each time we go through a iter node in the sub-algorithm tryShare, we must use a comparison based on compareRel instead of compareWithDone.

Example:

[figure: _{x _{1}}; 0; 1; _{x _{2}}; 0; 1; _{x _{3}}; 0; 1; _{x _{4}}; 0; 1; true; is equivalent to; _{x _{2}}; 0; 1; _{x _{3}}; 0; 1; _{x _{4}}; 0; 1; true]

The algorithm will find that the relation at □_{1} is the same as the relation at □_{2}.

♢

Recapitulation on Canonicity

All the algorithms that have been describing in this subsection are to be integrated in the representation algorithm for any tree representing an ω-deterministic relation, so that the representation is indeed unique. Here is a sketch of the new algorithm, including the elimination of redundant nodes:

• In addition to other useful informations, represent returns a boolean r indicating whether there is a path from the current node to a true node without going through an iter node.

• if the current node is not in a cycle (line 11 of represent) then

– if the node is an iter node ∗ if the boolean returned by represent on its child is false, then

return the child.

∗ look for root unfolding. If there is an equivalent node, return the equivalent node (don’t perform the sequel).

∗ perform bestOpen on the relation represented by the node, where every iter node M directly reachable from the current node is replaced by false_{M}, and recursively for every node such that all its children is a false_{M}.

∗ on the result of bestOpen, restore every false_{M} to M.

∗ perform addKeys on the current node to update D.

– if every child of the current node is the same, return the first child (redundant nodes elimination and treatment of false).

• if we have identified an independent cycle (test of line 24 of represent is true)

– look all nodes in the cycle. If no partial key leads to a non false node, then the entire cycle is equivalent to false.

– perform shareWithDone with the new comparison in case of iter node.

– for all iter nodes in the cycle,

∗ look for a path starting from this node and going to a true node without going through an iter node. If there is no one, suppress this iter node, and every node in the cycle that pointed to the iter node now points to its child

∗ perform the same operations as when the iter node is not in a cycle

∗ if the node changes, make any node that pointed to the old node in the cycle point to the new one.

• after sharing (line 10 of representCycle), eliminate redundant nodes in the cycle.

4.3.2 Entry Names

At the beginning of the chapter we described the relations as “coming with entry names”, and indeed, entry names are determined by the applications using the relations. But when we want to perform any operation between two relations, we need to compute valid entry names for the result of the operation. If the operation preserves the action of entry substitution, we can take any entry name that is valid for both relations. So, we describe a kind of name merging algorithm, that will give such a set of entry names.

Representation

In many algorithms of this chapter, we used the function name_{R} that is supposed to come with R. To know the values of this function, we cannot rely on the decision diagram, because, due to redundant nodes elimination, every entry is not necessarily represented in the diagram. In the case of classical BDDs, one can see the ordering on the variables as the representation of the function name_{R} for every R in a given BDD manager.

In the general case, we cannot use an ordering, as different entries may have the same name (which would lead to x < y < x if the entries 0 and 2 have the same name x, for example). In order to keep a unique representation of name_{R}, we use a regular tree, which is in fact equivalent to a regular word: each node is labeled by an entry name, of arity 1. We call this tree nt_{R}. It is defined formally as:

pos(nt_{R}) =^{def} {0}^{∗}
nt_{R}(0^{n}) =^{def} name_{R}(n)

Thus, the name tree of an infinite relation with all entries equivalent named x is [figure: x] .

Once we have the name tree of the relation, it is easy to restore the decision tree with the redundant nodes. So, while performing most algorithm on decision trees, we go through the name tree at the same time, so that we can keep track of the actual entry number associated with a given node. This technique is presented in the first basic algorithm, instantiate. In the other ones, we will describe the algorithm as if there were no elimination of the redundant nodes, ignoring the name trees so that the description is a little more simple.

Entry Names Merging

Let R and S be two regular relations. We suppose that we have a way of determining for the entry e and the entry names name_{R}(e) and name_{S}(e) what entry name choose(e, name_{R}(e), name_{S}(e)). It can be one of the entry names of R or S, or an entirely new one. The idea is that for every couple (x, y) of entry names of R and S, we must have a distinct entry name. In this way, the new set of entry names is compatible with both R and S.

mergeEntries(t, s, n, S):
  if if if (t, s) ∈ dom(S) then then then return return return(S(t, s))

t is of the form \xymatrix{x \ar[d] \\ t′}and s of the form \xymatrix{y \ar[d] \\ s′}

z ← ← ← choose(n, x, y)

add (t, s)→X_{n} to S (X_{n} is a label of arity 0)

u ← ← ← mergeEntries(t′, s′, n + 1, S)

  return return return(recCons ( \xymatrix{z \ar[d] \\ u}, X_{n}))

When we use this name tree in algorithms, we refer to a given choose(n, x, y) as xy.

4.3.3 Basic Algorithms

Emptiness

Thanks to the algorithms guarantying the uniqueness of the representation up to entry names, there is only one MDD representing the empty relation, false.

Equality Testing

Because of the uniqueness of the representation, equality testing is trivial. Note that we consider that two relations with different entry names cannot be equal.

Inclusion Testing

The following algorithm returns true if the first relation, considered as a set of vectors, is a subset of the second relation. It is similar in the spirit to the

compareRel algorithm.
inclusionRel(dt_{1}, dt_{2}):
  return return return(inclusionRelRec(dt_{1}, dt_{2}, dt_{1}, dt_{2}, ∅))
inclusionRelRec(t, u, r_{1}, r_{2}, S):
  if if if t = false false falsethen then then return return return(true true true)
  if if if u = false false falsethen then then return return return(false false false)
  if if if u = \xymatrix{iter \ar[d] \\ u′} then then then
   if if if u′ = true true truethen then then return return return(true true true)

S′ ← ← ← S where all (b_{1}, b_{2}, o_{1}, o_{2}) have been replaced by (b_{1},false false false, o_{1},false false false)

   return return return(inclusionRelRec(t, u′, r_{1}, u′, S′))
  if if if t = \xymatrix{iter \ar[d] \\ t′} then then then
   if if if t′ = true true truethen then then return return return(false false false)

S′ ← ← ← S where all (b_{1}, b_{2}, o_{1}, o_{2}) have been replaced by (false false false, b_{2},false false false, o_{2})

   return return return(inclusionRelRec(t′, u, t′, r_{2}, S′))
  if if if t = true true truethen then then

S′ ← ← ← S where all (b_{1}, b_{2},true true true, o_{2}) have been replaced by (true true true, b_{2},true true true, o_{2})

   return return return(inclusionRelRec(r_{1}, u, r_{1}, r_{2}, S′))
  if if if u = true true truethen then then

S′ ← ← ← S where all (b_{1}, b_{2}, o_{1},true true true) have been replaced by (b_{1},true true true, o_{1},true true true)

  return return return(inclusionRelRec(t, r_{2}, r_{1}, r_{2}, S′))
if if if (t, u) ∈ dom(S) then then then

(b_{1}, b_{2}, o_{1}, o_{2}) ← ← ← S(t, u)

  if if if b_{1} = true true truethen then then return return return(b_{2} = true true true) else else else return return return(true true true)
S′ ← ← ← S with (t, u)→(false false false,false false false,true true true,true true true)

t is [figure: x; t_{0}; t_{n−1}] and u is [figure: y; u_{0}; u_{m−1}]

if if if m < n then then then return return return(false false false)
for for for i ← ← ← 0 to to to n − 1 do do do
  if if if inclusionRelRec(t_{i}, u_{i}, r_{1}, r_{2}, S′) = false false falsethen then then return return return(false false false)
return return return(true true true)

Instantiation

Given a relation R represented by the decision diagram dt and the name tree nt_{R}, an entry name x in ename(R), a possible value v for the entries named x, R_{:x=v} is represented by:

instantiate(dt, nt_{R}, x, v):
return return return(instantiateRec(dt, nt_{R}, x, v, dt))
instantiateRec(t, s, x, v, r)):
if if if t = \xymatrix{iter \ar[d] \\ t′} then then then return return return(instantiateRec(t′, s, x, v, t′))
if if if t = false false falsethen then then return return return(false false false, instNameTree(s, x))
if if if t = true true truethen then then return return return( \xymatrix{iter \ar[d] \\ r}, instNameTree(s, x))

t is of the form [figure: y; t_{0}; t_{n−1}], and s of the form \xymatrix{z \ar[d] \\ s′}

if if if x = z then then then
  if if if x = y then then then return return return(unfoldTrue(t_{v}, r), s′)
  else else else return return return(unfoldTrue(t, r), s′)
else else else if if if y = z then then then
  for for for i ← ← ← 0 to to to n − 1 do do do (t′_{i}, u) ← ← ← instantiateRec(t_{i}, s′, x, v, r)
  if if if all the t′_{i} are equal then then then return return return(t_{0}, \xymatrix{y \ar[d] \\ u})

  return return return( [figure: y; t′_{0}; t′_{n−1}] , \xymatrix{y \ar[d] \\ u})

(t′, u) ← ← ← instantiateRec(t, s′, x, v, r)

return return return(t′, \xymatrix{y \ar[d] \\ u})

instNameTree( \xymatrix{y \ar[d] \\ s}, x):
if if if x = y then then then return return return(s)
t ← ← ← instNameTree(s, x)

return return return( \xymatrix{y \ar[d] \\ t})

unfoldTrue(t, r):
if if if t(ε) = iterthen then then return return return(t)
if if if t = false false falsethen then then return return return(false false false)
if if if t = true true truethen then then return return return( \xymatrix{iter \ar[d] \\ r})

t is [figure: x; t_{0}; t_{n−1}]

for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← unfoldTrue(t_{i}, r)

return return return( [figure: x; u_{0}; u_{n−1}] )

4.3.4 Intersection

Let dt_{1} and dt_{2} be decision trees of ω-deterministic relations. As was announced earlier, to simplify the presentation of the algorithms, we get rid of the elimination of redundant nodes from now on.

The following algorithm returns the decision tree representing the intersection of the relations represented by dt_{1} and dt_{2}. It shows that ω-deterministic relations are closed by finite intersection.

interRel(dt_{1}, dt_{2}):
return return return(interRelRec(dt_{1}, dt_{2}, dt_{1}, dt_{2}, ∅))

interRelRec(t, u, r_{1}, r_{2}, S):

if if if t = false false false or u = false false falsethen then then return return return(false false false)
if if if t = \xymatrix{iter \ar[d] \\ t_{0}} then then then
  if if if t_{0} = true true truethen then then return return return(unfoldTrue(u, r_{2}))

S′ ← ← ← S with every value (X, old_{1}, old_{2}, new_{1}, new_{2}) becomes

                                      (X, old_{1}, old_{2},false false false,false false false)
  if if if u = \xymatrix{iter \ar[d] \\ u_{0}} then then then s ← ← ← interRelRec(t_{0}, u_{0}, t_{0}, u_{0}, S′)
  else else else s ← ← ← interRelRec(t_{0}, u, t_{0}, r_{2}, S′)

  return return return( \xymatrix{iter \ar[d] \\ s})

if if if u = \xymatrix{iter \ar[d] \\ u_{0}} then then then

   if if if u_{0} = true true truethen then then return return return(unfoldTrue(t, r_{1}))

S′ ← ← ← S with every value (X, old_{1}, old_{2}, new_{1}, new_{2}) becomes

                                        (X, old_{1}, old_{2},false false false,false false false)

s ← ← ← interRelRec(t, u_{0}, r_{1}, u_{0}, S′)

   return return return( \xymatrix{iter \ar[d] \\ s})

  if if if t = true true truethen then then

S′ ← ← ← S with every value (X, old_{1}, old_{2}, new_{1}, new_{2}) becomes

                                        (X, old_{1}, old_{2},true true true, new_{2})

   return return return(interRelRec(r_{1}, u, r_{1}, r_{2}, S′))
  if if if u = true true truethen then then

S′ ← ← ← S with every value (X, old_{1}, old_{2}, new_{1}, new_{2}) becomes

                                        (X, old_{1}, old_{2}, new_{1},true true true)

   return return return(interRelRec(t, r_{2}, r_{1}, r_{2}, S′))

X is a new label of arity 0

  if if if (t, u) ∈ dom(S) then then then

(Y, old_{1}, old_{2}, new_{1}, new_{2}) ← ← ← S(t, u)

   if if if new_{1} = new_{2} = true true truethen then then return return return(true true true)
   if if if (old_{1} = true true true or new_{1} = false false false) and
            (old_{2} = true true true or new_{2} = false false false) then then then return return return(Y)

S′ ← ← ← S with (t, u)→(X, new_{1}, new_{2}, new_{1}, new_{2})

  else else else S′ ← ← ← S with (t, u)→(X,false false false,false false false,false false false,false false false)

t is [figure: x; t_{0}; t_{n−1}], and u is [figure: y; u_{0}; u_{n−1}]

  for for for i ← ← ← 0 to to to n − 1 do do do s_{i} ← ← ← interRelRec(t_{i}, u_{i}, r_{1}, r_{2}, S′)

  return return return(recCons ( [figure: xy; s_{0}; s_{n−1}] , X))

Proof: Let dt = interRel(dt_{1}, dt_{2}). Remember that a vector is an element of the ω-deterministic relation represented by a decision diagram if and only if, in the decision process, after some point, we don’t go through any iter node, and we go through an infinite number of true nodes. Because we add a iter node in dt for any iter node in either dt_{1} or dt_{2}, we don’t go through any iter node in dt after some point if and only if it is the case for both dt_{1} and dt_{2}. If there is an infinite number of true in the decision process in dt, then we go infinitely often through pairs of subtrees of dt_{1} and dt_{2}, (t, u), such that when going back to t and u, we have been through a true in both dt_{1} and dt_{2}. Conversely, if the vector is in both dt_{1} and dt_{2}, because the decision trees are regular, during the decision process performed simultaneously on both trees, we go infinitely often through at least one pair of subtrees of the decision trees, (t, u). Because we stack an infinite number of true, there is an infinite number of paths that goes from (t, u) to (t, u) in the vector, such that the decision process of dt_{1} goes through a true, and an infinite number such that the decision process of dt_{2} goes through true. So there is an infinite number of paths that go from (t, u) to (t, u) and goes through a true in both dt_{1} and dt_{2}. So R_{ω}(dt) = R_{ω}(dt_{1}) ∧ R_{ω}(dt_{2}). □

Example:

[figure: x; 0; 1; true] ⋀ [figure: x; 0; 1; true] = [figure: x; 0; 1; x; 0; 1; x; 0; 1; true]

♢

4.3.5 Approximation

ω-deterministic relations are not closed by union. It is proved by the following example:

Example: Let R_{1} be the set of all vectors with a finite number of 1’s, and R_{2} be the set of all vectors with a finite number of 0’s. R_{1} and R_{2} are represented by:

[figure: x; 0; 1; true; and; x; 0; 1; true]

Let R = R_{1} ∨ R_{2}. We have R_{[ε]}^{Ω} is the set of all possible vectors, because R(<0>) ≃ R, <0^{ω} > ∈ R, R(<1>) ≃ R and <1^{ω} > ∈ R. But <(01)^{ω} > ∉ R, so R_{[ε]}^{Ω} ⊄ R, and so R is not ω-deterministic (although it is ω-regular). ♢

The case is not desperate, though, because this representation is intended to be used in the framework of abstract interpretation. We consider as concrete domain the set of regular relations (which are closed by all boolean operations) and as abstract domain the set of ω-deterministic relations, each of them ordered by the inclusion of the relations. It is a consequence of the following property that there is a Galois insertion between the two domains.

Property 4.11 Whatever the regular relation R, there is a least ω-regular relation S such that R ⊂ S.

The least ω-regular relation is the decision tree dt_{ω}(R). As the definition of dt_{ω}(R) is a semi-algorithm we present the algorithm to compute the least ω-regular relation containing the regular relation R:

leastDeterministic(R):

S is the function ∅→false false false

  return return return(leastDeterFinite(R, S))
leastDeterFinite(R, S)
  if if if R ∈ dom(S) then then then return return return(S(R))

X is a new label of arity 0 S′ ← ← ← S with R→X

  if if if R_{[ε]}^{Ω} = ∅ then then then

x ← ← ← name_{R}0, and n is the arity of x

   for for for i ← ← ← 0 to to to n − 1 do do do t_{i} ← ← ← leastDeterFinite(R(<i>), S′)

   return return return(recCons ( [figure: x; t_{0}; t_{n−1}] , X))
  else else else

   t ← ← ← leastDeterInf (bestOpen (R_{[ε]}^{Ω}) , R, S′)

   return return return(recCons ( \xymatrix{iter \ar[d] \\ t}, X))

leastDeterInf(t, R, S):
  if if if t = false false falsethen then then return return return(leastDeterFinite(R, S))
  if if if t = true true truethen then then return return return(true true true)

t is [figure: x; t_{0}; t_{n−1}]

  for for for i ← ← ← 0 to to to n − 1 do do do u_{i} ← ← ← leastDeterInf(t_{i}, R(<i>), S)

  return return return( [figure: x; u_{0}; u_{n−1}] )

Proof: The algorithm terminates because the relation R is prefix regular. The bestOpen algorithms terminate because R is regular, so at a given point, the infinite behavior is prefix regular. Let e ∈ R. If e is ultimately periodic, because R is prefix regular, there is a u and a v such that e = <u.v^{ω} > and R(<u.v >) = R(<u>). So e is recognized by the decision tree leastDeterministic(R). If e is not ultimately periodic, as the entry names are ultimately periodic, there is a permutation of the entries which transforms e in f which is ultimately periodic. Moreover, it is possible to choose the permutation such that it leaves u unchanged and f = <u.v^{ω} > as above. f is in R, so f is recognized by the decision tree, and by equivalence of the entries, so is e. This proves that R is contained in the ω-deterministic relation. It is obvious that it is the least such ω-deterministic relation. □

A consequence of this property is that we can compute the least ω-determi-nistic relation containing the union of two ω-deterministic relations dt_{1} and dt_{2}.

Examples:

[figure: x; 0; 1; true; ⋃; x; 0; 1; true; will be approximated by true]

[figure: x; 0; 1; x; 0; 1; x; 0; 1; true] ⋃ \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ true & & false} = [figure: x; 0; 1; x; 0; 1; x; 0; 1; x; 0; 1; true]

♢

This operation is performed by the following algorithm:

unionRel(dt_{1}, dt_{2}):
return return return(unionRelFinite(dt_{1}, dt_{2}, dt_{1}, dt_{2}, ∅))
unionRelFinite(t, u, r_{1}, r_{2}, S):
if if if t = false false falsethen then then return return return(unfoldTrue(u, r_{2}))
if if if u = false false falsethen then then return return return(unfoldTrue(t, r_{1}))
if if if t = true true truethen then then t ← ← ← r_{1}
else else else if if if t = \xymatrix{iter \ar[d] \\ t_{0}} then then then
  if if if t_{0} = true true truethen then then return return return(t)

r_{1} ← ← ← t ← ← ← t_{0}

if if if u = true true truethen then then u ← ← ← r_{2}
else else else if if if u = \xymatrix{iter \ar[d] \\ u_{0}} then then then
  if if if u_{0} = true true truethen then then return return return(u)

r_{2} ← ← ← u ← ← ← u_{0}

if if if (t, u) ∈ dom(S) then then then return return return(S(t, u))

X is a new label of arity 0 S′ ← ← ← S with (t, u)→X

t is [figure: x; t_{0}; t_{n−1}], and u is [figure: y; u_{0}; u_{n−1}]

for for for i ← ← ← 0 to to to n − 1 do do do
  (s_{i}, b_{i}) ← ← ← unionRelInf(t_{i}, u_{i}, r_{1}, r_{2}, S′, t, u,false false false,false false false)

s ← ← ← recCons ( [figure: xy; s_{0}; s_{n−1}] , X)

if if if ⋁_{i<n} b_{i} = false false falsethen then then return return return(s)

else else else return return return( \xymatrix{iter \ar[d] \\ s})

unionRelInf(t, u, r_{1}, r_{2}, S, iter_{1}, iter_{2}, omega_{1}, omega_{2}):
if if if t = false false falsethen then then return return return(unfoldTrue(u, r_{2}),false false false)
if if if u = false false falsethen then then return return return(unfoldTrue(t, r_{1}),false false false)
if if if t = true true truethen then then

t ← ← ← r_{1}

  if if if omega_{1} = false false falsethen then then omega′_{1} ← ← ← true true true

  else else else omega′_{1} ← ← ← omega_{1}

else else else if if if t = \xymatrix{iter \ar[d] \\ t_{0}} then then then
  if if if t_{0} = true true truethen then then return return return(t,false false false)

r_{1} ← ← ← t ← ← ← t_{0}

  omega′_{1} ← ← ← iter
else else else omega′_{1} ← ← ← omega_{1}

if if if u = true true truethen then then

u ← ← ← r_{2}

  if if if omega_{2} = false false falsethen then then omega′_{2} ← ← ← true true true

  else else else omega′_{1} ← ← ← omega_{1}

else else else if if if u = \xymatrix{iter \ar[d] \\ u_{0}} then then then
  if if if u_{0} = true true truethen then then return return return(u,false false false)

r_{2} ← ← ← u ← ← ← u_{0}

  omega′_{2} ← ← ← iter
else else else omega′_{2} ← ← ← omega_{2}

if if if omega′_{1} = omega′_{2} = iterthen then then

S′ ← ← ← S with (iter_{1}, iter_{2})→ \xymatrix{iter \ar[d] \\ S(iter_{1},iter_{2})}

  return return return(unionRelFinite(t, u, r_{1}, r_{2}, S′),false false false)
if if if (t, u) = (iter_{1}, iter_{2}) then then then
  if if if omega′_{1} = true true trueor or or omega′_{2} = true true truethen then then return return return(true true true,true true true)
  else else else return return return(S(t, u),false false false)
if if if (t, u) ∈ dom(S) then then then return return return(S(t, u),false false false)

X is a new label of arity 0 S′ ← ← ← S with (t, u)→X

t is [figure: x; t_{0}; t_{n−1}], and u is [figure: y; u_{0}; u_{n−1}]

for for for i ← ← ← 0 to to to n − 1 do do do

(s_{i}, b_{i}) ← ← ← unionRelInf(t_{i}, u_{i}, r_{1}, r_{2}, S′, iter_{1}, iter_{2}, omega′_{1}, omega′_{2})

if if if ⋁_{i<n} b_{i} = false false falsethen then then

S′ ← ← ← S with (iter_{1}, iter_{2})→ \xymatrix{iter \ar[d] \\ S(iter_{1},iter_{2})}

  return return return(unionRelFinite(t, u, r_{1}, r_{2}, S′),false false false)

  else else else return return return(recCons ( [figure: xy; s_{0}; s_{n−1}] , X))

4.4 Other Representations

Decision diagrams have proved very useful for finite relations, and they seem quite efficient for infinite relations too. But other representations might have different qualities, for example more efficiency and less expressive power, or different operations that can be performed more easily. Because we separate the representation of the relations from the representation of the structure of the sets of trees, we can parameterize the representation of the sets of trees by the representation of relations as defined at the beginning of this chapter. We present briefly two such representations that can be of interest.

4.4.1 A Set of Vectors is a Set of Trees

A relation is defined as a set of vectors. But a set of vectors is a set of words, which are trees, so we can use the techniques developed in this thesis to represent sets of trees in order to represent relations. This is legitimate, because these techniques don’t use relations in the representation of sets of words, except possibly for the infinite behavior.

Of course, this representation will be less efficient than MDD, because it is not specialized on relations. In facts, it looks like a MDD without the false node (see the small example). But we introduce in chapter 7 the possibility of having counters in the representation. This might add interesting possibilities of widening on sequences of relations. Such widening would be more intelligent than the crude ones of [Mau98] for finite relations. The decision to use this representation in addition to decision diagrams (which are still needed for the infinite behavior) would reduce the efficiency but give more precise results. Its usefulness depends on the application.

4.4.2 Exact Relations

The most common relation introduced in the representation of sets of trees is the equality relation. So we propose a class of relations containing equality relations, simple enough to have a more efficient representation than decision diagrams, and such that they can approximate any relations.

Let R be a relation of domain ⨂_{i∈I} E_{i} with each E_{i} finite. We say that R is a basic exact relation if and only if there is a family (E_{ij})_{i∈I, j∈J} such that R = ⋃_{j∈J} ⨂_{i∈I} E_{ij} and for any i, E_{ij} ∩ E_{ij′} ≠ ∅ ⇔ j = j′. The relation is said to be exact if it can be independently decomposed in basic exact relations.

A basic exact relation can be represented using the words (E_{i,j})_{i∈I} and as usual the word representing the naming of the entries. As a consequence, we can represent infinite basic exact relations such that these words are ultimately periodic. In this case, we can use the techniques to represent a regular tree developed in chapter 3.

Examples: The relation x = y = z over the domain [2] is represented by the representation of the names, xyz, and the set {000, 111, 222}.

The infinite relation such that all entries 2i equals the entry 2i + 1 will be

represented by \xymatrix{x \ar[d] \\ y \ar[u]}and the set \{00, 11\}. Note the difference with the relation

where all entries are equal: [figure: x] and { [figure: 0] , [figure: 1] }. ♢

This class of relations is not closed under union, but it is closed by intersection and we can find the exact closure and the exact part of any relation. It means that we can find a least exact relation containing a given regular relation, as for ω-deterministic relations.

Such a representation might be used when we want more efficiency at the expense of the precision.

4.5 Conclusion

This chapter presented the class of relations which will be used in the representation of sets of trees, that is regular relations. Such relations might be infinite and we introduced the notion of equivalent entries to cope with the problem of representing infinite relations. Regular relations are nearly as expressive as ω-regular languages of Büchi. They are closed by all boolean operations. They can be represented by reduced decision diagrams in the way BDD are represented, but the representation of regular relations in general is not very efficient [SVW85]. Thus we introduced a subclass of regular relations, the ω-deterministic relations which can be used as an approximation (for relation inclusion) of regular relations. Their representation as a reduced decision diagram is canonical. They are an extension of the BDDs and have great expressive power for the infinite behavior of the relation. Because this class seems to give a good tradeoff between accuracy and efficiency, we developed the algorithms that are used to manipulate ω-deterministic relations. They can be used as such to represent finite or infinite relations over finite domains. They will be used in the next chapter for an efficient representation of sets of trees.

Tree Schemata

In this chapter, we attack the problem central to this thesis, namely representation of sets of trees. To be more precise, we try to represent any (or as many as possible) possibly infinite set of possibly infinite trees. To concentrate on the set of trees representations problem, we suppose that we only have a finite ranked set of labels. In this chapter, F will denote this set.

Because the problem is difficult, there can be different solutions, each of them with there advantages and drawbacks. It is the reason why we start this chapter by a presentation of other possible approaches, either found in the literature or explored during the course of the thesis. After this presentation, we expose our solution, which we call tree schemata.

A tree schema can be decomposed in two parts, the skeleton and the links. The skeleton can be seen as an upper approximation^{1}. This approximation is easy to understand and most operations will be very efficient on the skeleton. The links are a way to reduce the approximation at the cost of a worse complexity.

5.1 Different Approaches

5.1.1 Representations Based on Automata

The most classical way of representing a regular set of trees is the tree automaton. Tree automata for finite trees have been studied for a long time [TW68, GS84]. Although their practical use is not so easy, they have been used in practice, and efficiency of the implementations have been investigated [BMW91, HJJ^{+}96, BKR97]. The problem is that bottom-up tree automata, the most general ones, are complex to manipulate^{2}. For example, Seidl showed in [Sei90] that deciding the equivalence of two tree automata is EXPTIME-hard. Moreover, tree automata lack relational expressive power, that is they cannot

1That is, the skeleton represents a supset of the set represented by the schema.

2In fact, in order to have a realistic implementation, a deterministic top-down tree automaton is used in [BKR97] to partition the set of trees, each subset being represented by a more powerful bottom-up tree automaton.

represent sets of terms like { [figure: f; t; t]| t ∈ H(F)}. Of course, they cannot be used

to represent infinite trees either.

To increase the expressive power of tree automata, we can add equality constraints between subtrees, as proposed in [MS81]. The problem is that with this extension the emptiness problem is no longer decidable. It seems that these constraints must be restricted to brother subtrees for this problem to be decidable [BT92]. To represent infinite trees, we can use infinite tree automata, as proposed in [Rab69]. These automata are even more complex [Saf88], and although their potential practical usefulness has been pointed out many times [Var94, Sch90, ES88], I do not know of any efficient implementation^{3}.

Another problem with tree automata (and even word automata) is the difficulty of approximating accurately limits of sequences of automata (of growing size for example). We tried to investigate automata based on cycles, where a tree is presented as a cycle of trees, these trees being presented as cycles until we come to basic cycles. In this way, we could have detected the growth of any level of cycle and approximated it by an infinite cycle, or approximate the depth of these cycles^{4}. To give an idea of this kind of automata, we present the decomposition in cycles of a regular infinite word. A basic cycle is a finite or infinite sequence of the same letter, say a. It is represented by a^{n} if the sequence is finite of length n and a^{ω} if the sequence is infinite. If a word is not a basic cycle, it is represented by a number, a letter and a tuple of words, one for each different letter in the word. The number and the letter in this representation are the first letter of the word and the number of times it appears before the first other letter of the word. Each word in the tuple corresponds to the followers of the letter with which it is associated. The letters of these words are the basic cycles representing the followers. These words are themselves represented in the same way. For example, the word (ababb)^{ω} is represented by (1, a, b→a^{1}^{ω}, a→(1, b^{1}, b^{1} →b^{2}^{1}^{ω}, b^{2} →b^{1}^{1}^{ω})). In the case of trees, we must use bigger ordinal numbers to deal with infinite cycles containing infinite cycles. We don’t describe these automata (or in fact hyper-automata) further because our investigations showed that these representations, although very precise, are too inefficient. For example tree substitution is exponential. This is because we tried to achieve too much sharing, and for each little change in the set, we had to perform too much calculation for a very thigh sharing.

3In fact, even infinite words automata seem difficult, and other representations may be used to reduce the complexity (e.g. [CNP93]).

4In [Ven97], Arnaud Venet uses classical word automata with counters on productions of the automata to deal with cycles.

5.1.2 Representations Based on Expressions

A first motivation to tree automata [TW68] was to prove decidability of some logics. Thus sets of trees can be represented by logical formulae using expressions on set of trees variables. To represent sets of possibly infinite trees, μ-calculus [EC80, Koz83, AN92] seems a good framework. The problem is that it seems better as a description (by the user or for the user) than as a representation. It is the same problem as with boolean functions: it is easier to write or read a boolean formula, but it is well-known such formulae are not well-suited for the manipulation of boolean functions. That is the reason why, when manipulating sets of trees, μ-calculus formulae are usually translated into tree automata^{5}, or we just consider fragments of the μ-calculus [CS91, EJS93].

But with the notion of expressions on set of trees variables, we can go further. Exploiting the fact that variables represent sets, we can express sets constraints over these variables. The first use of this notion is in regular tree grammars, where non-terminals can be seen as the variables, productions as inclusion constraints, and right-hand sides as simple expressions with just union and terms. In fact, such representations of sets of trees have been used (for example in [Rey69, JM79, And86, Sør94]) to approximate more complex sets of trees. This representation, though, is far from ideal, mainly because of the use of variable names. Indeed this extensive use of variable names raises the problem of the uniqueness of the representation. It leads to inefficiency when comparing two sets of trees, and when performing some basic operations. For example intersection may require the creation of an exponential number of new variable names (in the implementation of regular tree expressions of [AM91] for example). Of course, we still lack the relational expressive power.

Other systems of constraints with more complex expressions have been studied since the reformulation of some program analyzes in term of “set based analysis” by Heintze [Hei92]. The representations they propose suffer from the same drawback as regular tree grammars (with the additional constraint, if we follow their formalism, that we must use the approximation of no relation between variables). For example, in [HJ90], there is a new variable for each union, and intersection requires an exponential number of variables. Thanks to the studies motivated by this work, there are many results of theoretical complexity or decidability of many set constraints systems. For example, in [AW92], Aiken and Wimmers showed that sets of constraints with union and intersection lead to an emptiness problem of complexity EXPTIME-hard. To represent infinite trees, we can use the co-definite set constraints studied in [CP98a], but the complexity is of course still EXPTIME-hard. A survey of different systems of set constraints is proposed in [Aik94]. Some extensions are studied in [Cha94], but they don’t seem very encouraging. In order to achieve efficiency, some authors propose the use of tree automata [DTT97], as for the μ-calculus.

5In fact, Emerson and Jutla showed in [EJ91] that the μ-calculus is as expressive as infinite tree automata.

In a more expressive framework, sets of trees have been studied in [AN80] from the point of vue of recursive program schemes. Such program schemes can have non deterministic choice, and as such look like the skeletons we introduce in this chapter. They are a lot more expressive, as they amount to context-free tree grammars. Such models have been studied from a theoretical point of vue, and to my knowledge, no implementation uses program schemes.

5.1.3 Tree Schemata

Tree schemata are based on skeletons, which can be seen as tree automata. The first difference between skeletons and classical automata is that it is the states of the skeleton that are labeled, and not the arrows. A first consequence is that the skeleton is closer to the trees of the set it represents. For instance, the skeleton representing one tree is the tree itself. Skeletons have the expressive power of deterministic top down tree automata (except for the unusual greatest fixpoint semantics). They share the common prefixes and subtrees of the trees they represent.

Full tree schemata are skeletons augmented with links. This decomposition separates the tree structure of the set of trees from the relations induced by the

set of trees. For example, in the set { [figure: f; a; b], [figure: f; c; d]}, the tree structure is that every

tree starts with a f, and its first child is either a or c, and its second child b or d. The relation is that when the first child is a a, the second child is a b, and when it is a b, the second child is a d. This separation has two advantages: first it allows structural sharing of the trees, and second we can use the expressive power of regular relations. It allows for example the representation of the set f(a^{n}, b^{n}, c^{n}), n ∈ ℕ. The automaton part of the representation (either in the tree structure or the relations) is always maintained in a kind of minimal state number, through the use of the techniques of chapter 3.

5.2 The Skeleton

The skeletons are very intuitive representations of some sets of trees. They are the structures on which links are built to represent more complex sets. In the sequel, the set of all possible skeletons for a tree schema over F will be denoted Sk(F).

5.2.1 A Set of Trees is a Tree

The easiest way of representing a set of objects consists in representing the elements of the set, and then using a sequence of arrows towards these representations. This presents two drawbacks: The sequential aspect of the representation allows many ways of representing the same set; the representation does not forbid the same object to be represented twice in a given set.

In our case, though, this method shows a very useful quality: a sequence of arrows is nothing less than a tree and representing a tree is easy. Thus, to represent a set of trees, we start by adding a new label to F, ◯, called the choice label and representing a kind of union. This new label does not have any fixed arity, but we shall see in the sequel that we can consider this label as representing |F | + 1 labels (◯_{i})_{i≤|F |}, ◯_{i} being of arity i. The set of trees labeled by F ∪ {◯} with this special convention for the arity of ◯ will be denoted H_{◯}(F).

The set of trees represented by a tree of H_{◯}(F) is defined by the function Ens : H_{◯}(F)→℘(H(F)):

∀f ∈ F, Ens ( [figure: f; t_{0}; t_{n−1}] ) =^{def} { [figure: f; u_{0}; u_{n−1}] | ∀i < n, u_{i} ∈ Ens (t_{i})}

Ens ( [figure: ◯; t_{0}; t_{n−1}] ) =^{def} ⋃_{i<n} Ens (t_{i})

The functions of H_{◯}(F) → ℘(H(F)) are ordered pointwise by the inclusion of the image. With this ordering, H_{◯}(F) → ℘(H(F)) is a complete lattice and the function defining Ens is monotone, so its greatest fixpoint is well defined.

In order to solve the uniqueness problem of this representation, when keeping the same easy semantic, the set of trees of H_{◯}(F) considered as valid must be restrained. These restrictions concern the subtrees of the choice nodes only.

Three types of restrictions must be considered to define the final version of the tree schemata skeletons. The obvious restrictions suppress the trees that are equivalent to smaller trees. The conventional restrictions choose some trees among many equivalent ones of the same size. Finally, the simplification restrictions decrease the class of sets of trees that can be represented by a skeleton.

Obvious Restrictions:

Starting from any element of H_{◯}(F), it is possible to build a sequence of elements of H_{◯}(F) of increasing size, representing the same tree of H(F). We can always add useless choice nodes for example. Two kinds of useless choice nodes can be distinguished: the choices of a unique subtree and successive choices. These kind of choices and their simplified equivalents are:

\xymatrix{◯ \ar[d] \\ t} is equivalent to t

[figure: ◯; t_{0}; ◯; t_{n}; u_{0}; u_{m}; is equivalent to; ◯; t_{0}; u_{0}; u_{m}; t_{n}]

To avoid these unwanted trees, the following rules are respected by every skeleton of tree schemata of F:

Rule 1 : ∀t ∈ Sk(F), ∀[figure: ◯; t_{0}; t_{n−1}]⋖ t, n > 1

Rule 2 : ∀t ∈ Sk(F), ∀[figure: ◯; t_{0}; t_{n−1}]⋖ t, ∀i < n, t_{i}(ε) ≠ ◯

We can also build a sequence of elements of H_{◯}(F) of increasing size starting from ◯ of zero arity, which represents the empty set. The equivalence is:

[figure: f; t_{0}; ◯; t_{n}] is equivalent to ◯

The corresponding rule, assuming rule number 2 is enforced, is: Rule 3 : ∀t ∈ Sk(F), if ◯ ⋖ t, then t = ◯

Conventional Restrictions:

Another problem with this representation —we already mentioned it— is its sequential aspect. In order to limit the number of possible representations of a given set, when possible, an order relation on the elements of the set can be used. The restriction consists in considering only increasing sequences of object instead of any sequence. If the ordering is total, the representation is then unique. In addition to allowing the sharing of equal sets, this convention allows algorithms on the sets to use the ordering.

This technique can be efficient if the algorithm deciding the order between the elements is fast. In the case of sets of trees, it would be too costly in the perspective of a first approximation to use a total ordering that could require to cover the entire trees before deciding which one is the smaller. Thus a mere preorder will be used to reduce the number of possible representations.

Let <_{F} be a total ordering on F. The preorder imposed to the subtrees of a choice node will be the order of their root. Thus the rule:

Rule 4 : ∀t ∈ Sk(F), ∀[figure: ◯; t_{0}; t_{n−1}]⋖ t, ∀ 0 < i < n, t_{i−1}(ε) ≤_{F} t_{i}(ε)

Simplification Restrictions:

This time, only elements of H_{◯}(F) that represent efficiently some sets of trees will be chosen. The choice made in this thesis consists in favoring prefix sharing.

Incidentally, this restriction allows the resolution of the uniqueness problem of the representation. The rule is the following:

Rule 5 : ∀t ∈ Sk(F), ∀[figure: ◯; t_{0}; t_{n−1}]⋖ t, ∀i < n, ∀j < n, i ≠ j ⇔ t_{i}(ε) ≠ t_{j}(ε)

This rule may suppress some representations that are equivalent to smaller

valid ones, but in general it forces to approximate some sets. For example [figure: ◯; g; g; a; b]

and [figure: g; ◯; a; b]represent the same set, but [figure: ◯; f; f; a; b; c; d]cannot be represented in Sk(F).

The best upper approximation will be [figure: f; ◯; ◯; a; c; b; d]. This approximation may seem

crude, but it is commonly used in set based analysis [HJ90] under the name of cartesian approximation.

5.2.2 Definition of the Set of Tree Schema Skeletons

The set of tree schema skeletons is denoted Sk(F). It is defined using rules 1 to 5:

Sk(F) =^{def} {t ∈ H_{◯}(F) | t is regular and ∀[figure: ◯; t_{0}; t_{n−1}]⋖ t, n > 1 ⋀ ∀i < n, t_{i}(ε) ≠ ◯ ⋀ ∀0 < i < n, t_{i−1} <_{F} t_{i} }∪{◯}

The set of trees represented by a skeleton is defined using the same function Ens as the other elements of H_{◯}(F). The set of sets of trees representable by a skeleton will be denoted Sk^{∴}(F). Its formal definition is:

Sk^{∴}(F) =^{def} {A ⊂ H(F) | ∃s ∈ Sk(F), Ens(s) = A}

Thanks to the rules defining the valid skeletons, every set of trees representable by a skeleton is uniquely represented. So the representation allows maximal sharing of prefix parts and subtrees of these sets. In this way, it is at the same time compact and easy to use.

Note that the representation of a singleton {t} is the same as the representation of t, even if t is an infinite regular tree, thanks to the greatest fixpoint semantics of the skeletons.

The empty set is in Sk^{∴}(F). It is represented by ◯. The set of all trees H(F) is also in Sk^{∴}(F), because F is finite. It is represented by a choice node, with all possible labels as its children, and each child then goes back to the choice node. For example, if F = {a, b, f} of arity 0, 0 and 2, H(F) is represented by

[figure: ◯; a; b; f] . We denote this skeleton 1_{F}.

The main flaw of this representation is its lack of algebraic property: Sk^{∴}(F) is not closed for union, neither for infinite intersection. In particular, there is no best approximation of every set of H(F) by an element of Sk^{∴}(F).

Examples:

[figure: f; a; a] represents the tree f(a^{ω}, a^{ω}).

[figure: ◯; a; b] represents the set a^{∗}b ∪ a^{ω}.

[figure: f; ◯; a; b]

represents the set of trees f(a^{∗}b, a^{∗}b) ∪ f(a^{ω}, a^{∗}b) ∪ f(a^{∗}b, a^{ω}) ∪

f(a^{ω}, a^{ω}).

♢

5.2.3 The Choice Nodes

The use of rule 4 is not the only possibility to ensure the uniqueness of the representation. It allows the representation of the set of labels in the choice as a vector (following the total ordering). But when the set of labels is really big, it is not the best representation possible for this set. An alternative representation is the use of a BDD ([Bry92]), but this representation uses variable names which may jeopardize the canonicity of the representation. Moreover, we don’t need BDDs, but multi-valued BDDs, that is BDDs with other leaf values than true and false. Such BDDs are less efficient than classical ones.

We have the possibility of using as variable names for the choice nodes the same names as the variables representing the entry^{6} corresponding to the choice node in the relation which is linked to the choice node (see next section). This implementation gives a satisfying uniformity which can ease some operations on tree schemata. The problem is that it forces the range of the choice to be the whole set of labels, which might be much bigger than the actual choice at this point. The result is a bigger relation representing the link.

6See Sect. 4.2.4, page 63, for the possibility of using many binary variables instead of one variable ranging over a large set, thus transforming an MDD into a BDD.

The choice between an ordered set and a BDD to represent the choice node is a parameter of the tree schemata. We can choose one of the possibilities depending on the kind of sets of trees we represent. If the set of trees present choice nodes over a small number of labels in general, we should use the ordered sets.

5.3 The links

As the tree schema skeletons are not very powerful, they must be enriched to be able to represent a greater diversity of sets of trees. The idea of the links of the tree schemata is to increase the number of sets a skeleton can represent by suppressing some elements of these sets. Thus the skeleton can be seen as an upper approximation of the set represented by the tree schema, and the links as a set of constraints on the set represented by the skeleton.

5.3.1 The Choice Space

In order to restrain the elements of the sets represented by a tree schema, we must define the set of possible restrictions. Restrictions will only be imposed on

choices. Let [figure: ◯; t_{0}; t_{n−1}] be a choice node. The choice space of this node will be

described by a choice in [n]. Now, let S be a skeleton. The set of paths of S labeled by a choice will be denoted:

cps(S) =^{def} {p ∈ pos(S) | S(p) = ◯}

Let p ∈ cps(S). Then S_{[p]} = [figure: ◯; t_{0}; t_{n−1}]. We define choice(p) =^{def} [n]. The choice

space of S, CS(S), is defined by:

CS(S) =^{def} ⨂_{p∈cps(S)} choice(p)

A skeleton S can be seen as a function ⟨S⟩ : CS(S)→H(F) defined by:

⟨S⟩ =^{def} ˜⟨S⟩(ε)

and ∀p ∈ pos(S), ∀c ∈ CS(S):

∀f ∈ F, \begin{matrix}&  \\ ⟨ & [figure: f; t_{0}; t_{n−1}] & ⟩ \end{matrix}(p)(c) =^{def}  [figure: f; u_{0}; u_{n−1}] such that ∀i < n, u_{i} = ˜⟨t_{i}⟩(p.i)(c)

\begin{matrix}&  \\ ⟨ & [figure: ◯; t_{0}; t_{n−1}] & ⟩ \end{matrix}(p)(c) =^{def}  ; ⟨t_{c_{(p)}}⟩ (p.c_{(p)}) (c)

That gives a new possible definition for Ens:

Ens(S) = {⟨S⟩ (c) | c ∈ CS(S)}

It is easy then to reduce the size of the set represented by a skeleton, by reducing its choice space.

Example: Let S be the skeleton [figure: f; ◯; ◯; a; c; b; d]. Then cps(S) = {0, 1}, choice(0) =

[2], choice(1) = [2]. So the choice space of S is [2]_{0} × [2]_{1}.

⟨ [figure: f; ◯; ◯; a; c; b; d]⟩ (<01>) = [figure: f; a; d]

♢

5.3.2 Links as Relations

Reducing the choice space of a skeleton is choosing a subset of this space. A subset of a cartesian product is a relation. A relation may be decomposed in independent smaller relations. When it is the case, the smaller relations take less space than the original one, and moreover they carry a more local information. The links of a tree schema are based on these independent relations over subsets of the set of choice nodes of the skeleton. The idea of decomposing the global relations into smaller ones leads to a more compact representation even if the decomposition is not independent (see [BCL91, HD93, GB94] for a study in the case of relations represented by BDDs).

The different ways of representing a relation are discussed in chapter 4. These different ways of representing relations might have different expressive power, thus leading to tree schemata with different expressive power. In order to keep things simple we represent in this chapter every link through the use of basic multiple decision diagrams. A very common relation is the equality relation. We will write it =.

5.3.3 Links are Local

As a first description, a tree schema can be seen as a skeleton together with a global relation on the choice nodes of the skeleton represented by a set of links.

But if these links are just the independent relations, then their indexes will be the global paths of the skeleton. Then, they must be changed each time a single part of the skeleton is changed, and they cannot be shared.

In order to give them a better autonomy, links are represented by relations with set of indexes an ordinal, which is always possible according to chapter 4. Each choice which should be restrained by a particular relation is just associated with the corresponding link and to the entry in the link. In this way, links are local to the particular choice nodes they put in relation and they don’t have to be modified as long as these nodes are left unchanged.

Now we can give a new way of representing a set of tree: a tree schema T on F is a tree on F ∪ {(◯, e, l) | l is a link, and e is an entry of l}. Of course we will have to restrict this definition to characterize tree schemata. We can still give some basic definitions that do not depend on these restrictions. The skeleton of T, skel (T), is the tree obtained from T by changing every node (◯, e, l) into ◯. The link associated with a choice node C of T is denoted link (C).

Example: Consider the following skeleton:

[figure: g; f; ◯; ◯; a; b; c; d]

Its choice space is [2]_{00} × [2]_{01}. A possible restriction would be to consider the set

{ [figure: g; f; a; c], [figure: g; f; a; d], [figure: g; f; b; d]}. The associated global relation would be {0_{00}0_{01}, 0_{00}1_{01},

1_{00}1_{01}}. The local link l would be based on the relation r = {0_{x}0_{y}, 0_{x}1_{y}, 1_{x}1_{y}} and in the tree schema, the first choice node would be associated with (x, l) and the second one with (y, l). It would be represented this way:

[figure: g; f; ◯; x; y; r; ◯; a; b; c; d] r = \xymatrix{ & x \ar[ddl]_{0} \ar[dr]^{1} \\ & & y \ar[dll]_{1} \ar[d]^{0} \\ true & & false}

♢

5.3.4 The Names of the Links

In order to manipulate links, to associate them with choice nodes, and in particular to share some of the links, we must give them a name. As we want to avoid as much as possible the use of arbitrary (variable) names, we use a part of the tree schema itself. The only way to distinguish between any global relation decomposed independently as much as possible is through the use of global paths. As we want to avoid the use of such a global information that would require a too costly maintenance, we can’t distinguish between any set of partial relation. This means that in some cases, links will be based on relations that could be furtherly independently decomposed, and we can’t divide them in smaller links. This will be illustrated in the next paragraph.

The minimum amount of information we need to know about a link is the relation it is based on. As we already pointed out, we would not have enough information in the tree schema for some configurations of links if we just used the relation as the name of the link. Suppose for example that we have two different sets of choice nodes linked by the same relation: we could not infer from the tree schema which sets are linked.

Example: Suppose we have four choice nodes of global paths p_{1}, p_{2}, p_{3} and p_{4} with the same choice space. If the relation binding these nodes is p_{1} = p_{2} and p_{3} = p_{4}, then we can’t divide it in two smaller relations, because these relations being the same, we would not know whether p_{1} is linked to p_{2} or p_{4}. ♢

The most local information we can gather about a link is the relation it is based on and the nodes or subtrees of the tree schema it binds. It is this information we use as the name of the links. There are still some cases were we cannot decompose the relation as much as possible, but in the next section on sharing, we will discuss some of these cases where we can distinguish between shared link names. In the graphic representation of tree schemata, a link is represented by a wavy line between the subtrees it binds, labeled by the relation.

5.3.5 Sharing

With the links, the names of the choice nodes are augmented with a link name and an entry name. In this way, some choice nodes which were shared in the skeleton are distinguished. In some cases, this distinction is not necessary. More sharing can be achieved by the entry names and by the link names.

Entry names

In order to share some entries which are in a sense equivalent, the entries the relations the links are based on are named. The case whenever the entries of a relation can be merged is discussed in detail in the section on the representation of relations. The most common case is the equality relation where all entries are equivalent. This sharing is necessary to represent some infinite relations.

Example: The link l is based on the identity relation, and the choice entry x is associated with the entries {0, 1}.

[figure: f; ◯; x; =; t_{0}; t_{n}]

♢

Example: The link l is an infinite relation with all entries equivalent. This tree schema represents the set of finite words a^{∗}b.

[figure: ◯; x; l; b; a] l = [figure: x; 0; 1; true]

♢

Link Names

Considering two sets of paths of choice nodes linked by the same relations, and such that the two links binding these sets would have the same name, the problem is to decide whether we must combine the two sets or we can share them. Two sets of paths bound by the same link can be shared if they can be distinguished by the way the skeleton is covered. They can be distinguished if one of them appears after the other. In that case, it is easy to consider that each time a choice node associated with an entirely instantiated link is encountered, then this choice node is in the second set, and it is associated with a new fresh version of this link. It is even possible, following the same idea, to use a stack mechanism to distinguish between more intertwined sets of paths. The covering of the skeletons defines an order <_{cover} on the paths of the skeletons. The standard covering of the skeletons described in this chapter induces the alphabetic ordering.

Let S_{1} and S_{2} be two sets of paths, linked by the same relation r, such that the two links binding these sets would have the same name. We write T the tree schema obtained if we share the two sets. S_{1} is said to be before S_{2}, if and only if, ∀e entry of r, ∀p_{1} ∈ S_{1} with entry (T (p_{1})) = e, and ∀p_{1} ∈ S_{1} with entry (T (p_{1})) = e, p_{1} <_{cover} p_{2}. A set L of sets of paths bound by the same link does not have to be combined if it is totally ordered for the ordering “is before”.

The problem with those two possible sharing is that they may be incompatible: a set of paths S_{1} can be before S_{2} if the entries of the relation are not shared, and S_{1} and S_{2} are not comparable after the sharing of some entries. In this case, the sharing of link names takes precedence.

Examples: An infinite tree schema that can take advantage of this sharing:

[figure: f; ◯; x; y; r; ◯; g; a; b; h]

In this example, if r is the equality and if we share the equivalent entries, we must combine the links, and so the tree schema becomes infinite.

Using the same principles, we can easily represent the set f(a^{n}e, b^{n}e, c^{n}e), n ∈ ℕ:

[figure: f; ◯; x; r; y; ◯; y; r; z; ◯; a; b; c; e] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[d]_{0} \ar[dr]^{1} & & y \ar[dl]_{0} \ar[d]^{1} \\ z \ar[dr]_{0} \ar[r]^{1} & false & z \ar[l]_{0} \ar[dl]^{1} \\ & true}

Note that r is the equality relation. ♢

5.3.6 Set Represented by a Tree Schema

We give two definitions of the set represented by a tree schema. The first one is in line with what was presented so far and hopefully easier to understand than the second one, which is a constructive definition.

First Characterization

The main problem in characterizing the set represented by a tree schema is the reconstruction of the global relation defined by the links of the tree schema.

Let T be a tree schema, and l a link of T, based on the relation R. The link defines relations on any subset P of cps(T) such that there is an injective function σ from P to the set of entries of R, and ∀p ∈ P, T (p) = (◯, name_{R}(σ(p)), l). These relations, denoted GlobRel(l, P) are defined by:

∀x ∈ ⨂_{p∈P} choice(p), x ∈ GlobRel(l, P) ⇔^{def} ∃y ∈ R, ∀p ∈ P, x_{(p)} = y_{(σ(p))}

The next step is to define the correct subsets of cps(T) that are bound by a given link, according to the rules of link sharing. The size of an entry name x of l, |(l, x)| is defined as the number of entries of R named x. We write least(E, n, <) the n least elements of the totally ordered set E, <. If there is less than n elements in E, then least(E, n, <) = E. The ordered partition of E, OrdP art(E, n, <) is the transfinite sequence defined by OrdP art(E, n, <)_{i} =^{def} least (E\ ⋃_{j<i} OrdP art(E, n, <)_{j}, n, <). The set of subsets of cps(T) that are bound by l is defined by:

P athP art(T, l) =^{def} {⋃_{x} OrdP art ({p | T (p) = (◯, x, l)} , |(l, x)|, <_{cover})_{i} | i ∈ ℕ}

Now, we can define the relation associated with a tree schema T, rel (T) as:

rel (T) =^{def} \overline{⋀}_{l link of T} ⋀_{P ∈P athP art(T,l)} GlobRel(l, P)

The set represented by a tree schema T can be seen as:

Set(T) = ⋃_{c∈rel(T)} {⟨skel (T)⟩ (c)}

Constructive Definition

This construction of the set represented by a tree schema illustrates the way an algorithm can work on tree schemata. A temporary global information is used to store the partial evaluations of the links. As a link may be shared, many different version of a given link can be partially evaluated. So the global information will be a function which associates with each link a list of partial evaluations of the relation it is based on. These lists will be denoted (R_{1} : …: R_{n}). The function that associates with every link of a tree schema T the empty list will be denoted T_{∅}.

Let G be a temporary global information for a given covering of a tree schema T. Let l be a link of T, R the relation of the link, and x an entry name of l. Let G(l) = (R_{1} : …: R_{n}). The set of possible choices for l on entry name x according to G is written G(l)_{(x)}. By definition, if no relation of G(l) contains an entry named x in its domain, then G(l)_{(x)} =^{def} R_{(e)} where e is an entry named x, and else if R_{i} is the first relation of G(l) containing an entry e named x in its domain, G(l)_{(x)} =^{def} R_{i}_{(e)}. The new global information after the choice v for the entry name x of the link l is written G_{x=v}^{l} . Following the same cases as in the definition of G(l)_{(x)}, if no relation of G(l) contains an entry named x in its domain, then G_{x=v}^{l}(l) =^{def} (R_{1} : …: R_{n} : R_{:e=v}) where e is the first entry of R named x, and if R_{i} is the first relation of G(l) containing an entry named x in its domain, G_{x=v}^{l}(l) =^{def} (R_{1} : …: R_{i−1} : R_{i}_{:e=v} : R_{i+1} : …: R_{n}) where e is the first entry of R_{i} named x. In any case, ∀l′ ≠ l, G_{x=v}^{l}(l′) =^{def} G(l′).

In order to define the behavior of relations on infinite instantiations, we have to define a progression order on the global informations. A global information G_{1} comes after a global information G_{2} on the same tree schema T, written G_{2} ↣^{T} G_{1} if and only if for all l link of T, let G_{1}(l) = (R_{1}^{1} : …: R_{n}^{1}) and G_{2}(l) = (R_{1}^{2} : …: R_{m}^{2}), then m ≤ n and ∀i ≤ m, l_{i}^{1} is a positive instantiation of l_{i}^{2}. A relation R is a positive instantiation of the relation S if and only if there is a set of entries I of S and an element v ∈ S such that R = S_{:I=v_{(I)}}.

The function translating the tree schemata into sets of trees, Set, is defined by:

Set(T) = {t ∈ H(F) | ∃G, (t, G) ∈ S̃et (T, T_{∅})}

and ∀f ∈ F,

S̃et ( [figure: f; t_{0}; t_{n−1}] , G_{0}) =^{def} {( [figure: f; u_{0}; u_{n−1}] , G_{n}) | ∀i < n, (u_{i}, G_{i+1}) ∈ S̃et(t_{i}, G_{i})}

S̃et ( [figure: ◯; x; l; t_{0}; t_{n}] , G) =^{def} ⋃_{i∈G(l)_{(x)}} {(u, H) | (u, H) ∈ S̃et (t_{i}, G_{x=i}^{l}) ∧ G_{x=i}^{l} ↣^{T} H }

The function S̃et is defined as usual as the greatest fixpoint of this fixpoint equation. The ordering is the pointwise ordering of inclusion of the images. It is easy to see that this fixpoint equation is monotone for this ordering.

Obviously, any element of Set(T) is an element of Ens(skel (T)). Whatever the finite tree in Set(T), it is associated with a unique global information by S̃et(T). In the case of infinite trees, there is at least one global information associated that contains no empty relation.

Example: Let T be [figure: ◯; x; l; b; a] and l = [figure: x; 0; 1; true] . We define G_{T} the set of

all possible global informations on T. G_{n} is the relation l is based on, partially evaluated on its n − 1 first entries, with value 1. G_{n}^{0} is the same relation partially evaluated on its n^{th} entry with value 0. Then:

S̃et(T, G_{n}) = \{(b, G_{n}^{0})\} ∪ \{( \xymatrix{a \ar[d] \\ u}, H) | (u, H) ∈ S̃et (T, G_{n+1}) ∧ G_{n+1} ↣^{T} H\}

We show the part of the iteration sequence [CC79] of S̃et on T:

S̃et_{0}(T, T_{∅}) = H(F) × G_{T}
S̃et_{1}(T, T_{∅}) = \{(b, G_{0}^{0})\} ∪ \{( \xymatrix{a \ar[d] \\ u}, H) | u ∈ H(F) ∧ G_{1} ↣^{T} H\}

S̃et_{2}(T, T_{∅}) = \{(b, G_{0}^{0}) , ( \xymatrix{a \ar[d] \\ b}, G_{1}^{0})\} ∪ \{( \xymatrix{a \ar[d] \\ a \ar[d] \\ u}, H) | u ∈ H(F) ∧ G_{2} ↣^{T} H\}

⋮
S̃et_{i}(T, T_{∅}) = ⋃_{n<i} {(a^{n}b, G_{n}^{0})} ∪ {(a^{i}u, H) | u ∈ H(F) ∧ G_{i} ↣^{T} H}
⋮
S̃et_{ω}(T, T_{∅}) = ⋂_{i<ω} S̃et_{i}(T, T_{∅})

Thus S̃et(T, T_{∅}) contains every couple {(a^{n}b, G_{n}^{0})}. If it contained a couple (a^{ω}, H), then ∀i, G_{i} ↣^{T} H. This means that H would contain a version of the relation of l entirely instantiated on 1^{ω}, which is impossible, because it does not belong to the relation. ♢

5.3.7 Restrictions on the Links

If a skeleton could be associated with any relation, then the tree schemata would be able to represent any set of trees. The problem is that tree schemata must be kept finite, so we must restrict the links that can be associated with a particular skeleton.

Finiteness

In order to have finite tree schemata, we require that a tree schema is a regular tree, and that each link is based on a regular relation. For a practical use, we will actually restrict the relations even more, to ω-deterministic relations.

Only Choice Nodes that Depend on Another One are Linked

Finding out whether a given relation can be independently decomposed is a hard problem, which we don’t solve efficiently in this thesis. There is an easy case, though, where we know the choice node (◯, x, l) does not depend on the other choice nodes of the link l: it is the case if and only if the entry does not appear in the decision diagram representing the relation of l (it happens because of redundant nodes elimination). Thus we require that for any choice node (◯, x, l), either l is the true relation (and we denote the choice node by just ◯), or the entry name x appears in the decision diagram of the relation of l.

Keeping the Skeleton a Good Approximation

The skeleton is supposed to be a good upper approximation of the set represented by the tree schema. If the relation associated with the skeleton is too restrictive, then it may be better to build the tree schema on a smaller skeleton. In order to avoid some redundancy, we forbid some of these relations. The problem is that for some sets of trees, there is no best skeleton approximating the set. The only property we can enforce on tree schemata is:

Property 5.1 For any tree schema T such that Set(T) admits a best skeleton approximation, skel (T) is this best approximation.

To enforce this property (even on independent subtree schemata), we restrict the possible links. First, every relation on which a link is based must be full, that is, for all entries and all possible value of the entry, there is a vector of the relation with this value on this entry. The formal definition is given bellow. Second, we forbid any link between a choice node and one of its subtree except in two cases. The first case allows to link a choice node and one of its subtrees to another node, provided there is no real relation between the choice node and its subtree. This case allows the elimination of some infinite trees from the set represented by the skeleton, as in this case there is no real prefix relation. The second case allows the representation of some sets with no best skeleton approximations.

Definition: Let R be a relation on ⨂_{i∈I}[n_{i}]. R is full if and only if ⨂_{i∈I}[n_{i}] = Support(R).

We first prove that with such restriction on the links, assuming there is no exception, the skeleton of the tree schema is the best approximation of the set represented by the tree schema. We will show later that the two cases where we can have a link between a node and its subtree don’t make the skeleton greater than the best possible if there is a best one.

Proof: Let T be a tree schema such that each link of T is based on a full relation and there is no link between a choice node and one of its subtrees. Suppose there is a skeleton S such that Set(T) ⊂ Ens(S) ⊂ Ens(skel (T)). If S ≠ skel (T), then there is a path p such that S_{[p]} and skel (T)_{[p]} are choice nodes and there is a value i of skel (T)_{[p]} that is not a value of S_{[p]}. T_{[p]} is labeled by (◯, x, l), and l is based on R, which is full. It means that there is a v ∈ R such that v_{(e)} = i (e is an entry of name x). As there is no link between parent nodes, the fact that a value c ∈ rel (T) validates the path p (∀q ∈ cps(T), q ≺ p ⇒ qc_{(q)} ≺ p) does not depend on the projection of c on the entries of the link. Thus there is a c in rel (T) such that the projection of c on the entries of l is v, and so the choice i is taken at p. This means that Set(T) ⊄ Ens(S). □

First Case: Links with no Real Relation between Parent Nodes Let N_{1} be a node labeled by (◯, x_{1}, l) and N_{2} a node labeled by (◯, x_{2}, l)^{7} such that there is a path from N_{1} to N_{2}. l is based on the relation R. Let B = {b ∈ R_{(x_{1})} | ∃p, N_{1}.bp = N_{2}} be the set of output values of the choice node N_{1} that can lead to N_{2}. Then the link does not impose any real relation between N_{1} and N_{2} (and so is valid) if:

∀b ∈ B, ∀i ∈ R_{(x_{2})}, ∃v ∈ R such that v_{(x_{1})} = b and v_{(x_{2})} = i

Tree schemata with links between first case parent nodes still represent sets with best skeleton approximation the skeletons of the tree schemata^{8}.

Proof: We start again with the same objects as in the proof for the general case. The difference with the general case is that there may be a link between T_{[p]} and a parent node. But if there is a q ≺ p such that T_{[q]} is linked to T_{[p]}, whatever j such that qj ⪯ p, there is a v such that v_{(e)} = i and the projection of v on the entry of T_{[q]} is j. So a c in rel (T) such that its projection on the entries of the link is v exists. □

Examples: This tree schema with a link between parent nodes is valid.

[figure: f; ◯; x; r; ◯; y; a; b; c; d; r; ◯; z; a; b] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[dd]_{0} \ar[dr]^{1} & & y \ar[dd]_{0} \ar@{-->}[dr]^{1} \\ & z \ar[dl]_{0} \ar[dr]^{1} & & z \ar[dl]_{0} \ar[dr]^{1} \\ true & & false & & true}

7It is possible that x_{1} = x_{2} or even N_{1} = N_{2}.

8We must be careful, though, in the presence of infinite relations, as the first case does not impose anything on the infinite behavior of the relation and the skeleton of the tree schema could be greater than the best skeleton if we don’t respect the rules of infinite behaviors of tree schemata.

The set represented by the tree schema is { [figure: f; a; c], [figure: f; a; d; a], [figure: f; b; d; b] } The tree schema

representing the set of finite trees of the form a^{∗}b also falls in this case:

[figure: ◯; x; r; a; b] with r = [figure: x; 0; 1; true]

♢

Second Case: Sets with no Best Skeleton Approximation In the case when the set represented by the tree schema does not have any best skeleton approximation, we cannot refine the links until as much as possible is represented by the skeleton. Thus we allow any link between two parent nodes if with this link, the sets they represent does not have any best skeleton approximation.

In practice, it is a difficult problem to characterize tree schemata with best skeleton approximation and links with real relations between parent nodes (although we know that such tree schemata are equivalent to tree schemata without such links, and as such are forbidden). Thus, for practical use, we can restrict the second case to allow only a subclass of tree schemata representing sets with no best skeleton approximations which is easier to identify. For example, there is no best skeleton for Set(T) if there is a link l, a node N labeled by (◯, x, l) reachable, a path p that can be taken and such that N.p = N without going through another node linked to l (the independent loop), and another node M labeled by (◯, y, l) reachable from N whatever the number of loops and such that each choice in N leading to p allows a choice of M leading to a path coming back to M.

Example: The following tree schema is valid, because there is no best skeleton for this set of trees. We can even identify an independent loop.

[figure: ◯; a; c; ◯; 1; x; 0; =; b; ◯; 0; 1; y; =; c]

The set of trees represented by this tree schema is {a^{n}b^{n}c | n ∈ ℕ}. ♢

Infinite Behavior

Because skeletons approximate sets of possibly infinite trees from above, their infinite behavior is a greatest fixpoint. In order to discard some infinite trees from those sets, we use links. The problem is that these links will relate some nodes and their subtrees, and thus the structure of the skeleton (or even the tree schema) may interfere with them.

Example: The following three tree schemata are equivalent:

[figure: ◯; x; r; a; b]  [figure: ◯; a; b; ◯; x; r; b]  [figure: ◯; a; b; ◯; x; r; a; b]  with r = [figure: x; 0; 1; true]

♢

It can even be worse, as if we don’t link every node in a given cycle, it is possible that the infinite behaviors of some nodes are not compatible.

Example:

[figure: ◯; x; r_{1}; a; b; ◯; x; r_{2}; a; b] with r_{1} = [figure: x; 0; 1; true] and r_{2} = [figure: x; 0; 1; true]

♢

In order to avoid this case, and more generally to have a uniform representation (and in particular no strictly monotone sequence of tree schemata representing the same set), we just have to link all these nodes. In fact, it is the opposite of the general policy with links: instead of decomposing independent parts as much as possible, we try to link independent nodes.

These cases are easily characterized: we must try to incorporate the current choice node if it is either in a cycle with another choice node that is linked or if one of the children of the choice nodes is a cycle with another choice node that is linked. The latter case is easily handled by the dictionary of keys of cycles. In the former case, we merely don’t allow the relation between the different nodes of a given cycle (which may be the true relation) to be decomposed in independent relations.

5.4 The Set of Tree Schemata, T S(F)

5.4.1 Definition

A tree schema T on F is a regular tree on F ∪ {(◯, x, l) | l is a link, and x is an name entry of the relation of l} such that:

• a link l is a regular relation R and a map f : ename(R) → ℘(Subtrees(T)) such that ∀x ∈ ename(R),

– f(x) is the set of subtrees of T labeled by (◯, x, l);

– f(x) is not empty;

– x appears in the decision diagram of R, if this decision diagram is not

         true.

• if t is a subtree of T labeled by [figure: ◯; x; R; t_{0}; t_{n−1}] then:

– n = 0 and t = T, or n > 1 and the t_{i} are labeled by elements of F and ordered according to these elements (that is skel (T) is a skeleton);

– R_{(x)} = [n] (that is R is full);

• Whatever the cycle in T, every choice node in the cycle is associated with the same link.

• for all subtree S of T that is a tree schema, either Set(S) does not have any best skeleton approximation or for any u and t subtrees of S labeled by (◯, x, l) and (◯, y, l), if there is a path from u to t, the choice on u does not restrict the choice on t (see previous section).

The set of all such tree schemata on F is denoted T S(F).

5.4. THE SET OF TREE SCHEMATA, T S(F) 107

5.4.2 Description of the Sets of Trees Representable by Tree Schemata

In order to give a formal definition of the sets of trees representable by tree schemata and a flavor of the expressive power (and limitations) of tree schemata, we use formal language transformers as defined in [CC95]. In order to have the necessary expressive power, in particular concerning the infinite behavior, we enrich the formal language transformers with regular relations. Then, we restrict the set of formal language transformers with regular relations so that their semantics is exactly the set of tree schemata.

Formal Language Transformers

First, let us recall the notations of [CC95]. A non-ground term is a tree^{9} on F ∪v, where v is a set of term variables. The semantics of a non-ground term T is the map [ ; |T | ; ] ∈ (v → H(F)) → H(F) defined as the function mapping any function κ : v →H(F) to the tree substitution of every label x ∈ v of T by κ(x). Because we deal with infinite trees, we need a little restriction on some terms: we say that a term T′ is of finite non groundness if the set of paths p such that T′(p) is a variable is finite.

A meta expression e denotes a language transformer. Meta expressions can be defined as:

e ::= X | {T′ : T_{1} ∈ e_{1}, …, T_{n} ∈ e_{n}} | e_{1} ∪ e_{2}

where T′ is a term of finite groundness, the T_{i} are terms, and X is a set variable in V. These set variables are free in meta expressions, but term variables are local to meta expressions of the form {T′ : T_{1} ∈ e_{1}, …, T_{n} ∈ e_{n}} which are used

to describe intersection ({x : x ∈ e_{1}, x ∈ e_{2}}), projection ({x : [figure: f; x; y]∈ e}), sets

denoted by terms of finite groundness ({T′}) and many others. The semantics of a meta expression e is the map { ; |e| ; } ∈ (V → ℘(H(F))) → ℘(H(F)) inductively defined by:

{ ; |X | ; } ρ =^{def} ρ(X)
{|{T′ : T_{1} ∈e_{1}, …, T_{n} ∈e_{n}}|} ρ =^{def} {[|T′|] κ | κ ∈ v →H(F) ⋀_{1≤i≤n}[ ; |T_{i}| ; ] κ∈{ ; |e_{i}| ; } ρ}
{ ; |e_{1} ∪ e_{2}| ; } ρ =^{def} { ; |e_{1}| ; } ρ ∪ { ; |e_{2}| ; } ρ

With this definition, { ; |e| ; } is monotonic. So it can be used to describe sets of languages by means of systems of equations of the form X = e_{X}. The semantics of such systems of equations would be the greatest fixpoint of ρ(X) = { ; |e_{X} | ; } ρ.

9We extend the languages of [CC95] to infinite trees. Thus a term can be any regular tree.

We will show in the next chapter that if ρ maps every set variable to a set representable by a tree schema, then ρ′ defined as ρ′(X) = { ; |e_{X} | ; } ρ maps every set variable to a tree schema too.

Formal Language Transformers with Relations

Tree schemata can be transformed by even more powerful operations, as we can add relations to the system of equations. These relations can be described by boolean formulae f over guards of the form X = a where a ∈ F.

f ::= (X = a) : f | true | f_{1} ∨ f_{2} | iter(f) | R

R is a relation variable in V. The semantics of a formula f is the map ( ; |f| ; ) : (V→Rel)→Rel defined inductively by:

( ; |(X = a) : f| ; ) τ =^{def} {aα | α ∈ ( ; |f| ; ) τ and the name of the first entry is X }
\begin{matrix}( \\ | & true & | \\ ) \end{matrix} τ =^{def} ⨂_{i∈ℕ^{∗}}F
( ; |f_{1} ∨ f_{2}| ; ) τ =^{def} ( ; |f_{1}| ; ) τ ∨ ( ; |f_{2}| ; ) τ
( ; |iter(f)| ; ) τ =^{def} Ω (( ; |f| ; ) τ)
( ; |R| ; ) τ =^{def} τ(R)

With this semantics, formulae are monotonic, except for the iter definition. It means that we can define the relation imposed on the system of equations as one of the relation variable, whose value is defined by a system of relation equations of the form R = f_{R} such that for every R that appears inside an iter definition in any f_{S}, there is no iter in f_{R}. The semantics of this system of relation equations is the least fixpoint of τ(R) = ( ; |f_{R}| ; ) τ

The semantics of a set of formal languages equations (X = e_{X}) constrained by a relation (R) is the greatest fixpoint over the set V ×AllProj(R)→℘(H(F)× AllProj(R)) of the set of equations:

ϱ(X , S) = {(t, Q_{:X =t(ε)}) | (t, Q) ∈ { ; |e_{X} | ; } ϱ_{S}}

In order to give sense to these equations, we must extend the semantics of meta expressions to deal with relations:

{ ; |X | ; } ϱ_{S} =^{def} ϱ(X , S)
{|{T′: T_{1} ∈e_{1}, …, T_{n} ∈e_{n}}|} ϱ_{S_{0}} =^{def} {([|T′|]κ, S_{n}) | ⋀_{1≤i≤n}([ ; |T_{i}| ; ]κ, ϱ_{S_{i}})∈{ ; |e_{i}| ; } ϱ_{S_{i−1}}}
{ ; |e_{1} ∪ e_{2}| ; } ϱ_{S} =^{def} { ; |e_{1}| ; } ϱ_{S} ∪ { ; |e_{2}| ; } ϱ_{S}

The set associated with X by ϱ is {t ∈ H(F) | (t, S) ∈ ϱ(X , R) and S ≠ ∅}.

Restrictions on Meta Expressions

It is easy to see that any set represented by a tree schema is a solution of such system of equations constrained by a relation. Moreover, meta expressions with relations applied to tree schemata can be represented by tree schemata, and the set of all trees, which is the starting point of the iteration sequence leading to the greatest fixpoint can be represented by a tree schema. The problem is that the set of tree schemata is not closed under infinite union or intersection. Thus, for some meta expressions, the greatest fixpoint cannot be represented by a tree schema.

The minimal generating meta expressions are easy to extract from the very structure of the tree schemata: we keep the union, for the choice node, the set

variables, for the loops, and expressions of the form { [figure: f; x_{0}; x_{n−1}] : (x_{i} ∈ e_{i})_{i<n}},

for the root construction of sets. With these meta expressions and the regular relations, we can define any tree schema as representing a greatest fixpoint of a meta expression equation as defined above.

5.5 Discussion

The representation presented in this chapter can be viewed as a special case or an extension of the notion of automaton. But it really brings new elements in the representation of sets of trees. The first element is the strong expressive power of the representation, which is a concern in abstract interpretation. The second element is a strong notion of determinism with good consequences on the algorithmic of the representation. The third element is an efficiency concern in the design of the representation which led to the sharing of many elements of the set of trees.

5.5.1 Expressive Power

Skeletons are related to deterministic top-down finite tree automata. If we remove the infinite trees from their interpretation, then they are as expressive as deterministic top-down tree automata. If we add finite relations and still consider finite trees, we get non-deterministic tree automata. With infinite relations, we encompass tree automata with equality constraints between brothers.

Although Tree schemata can represent most sets of trees representable by tree automata of many kind, not every useful set of trees is representable by a tree schema, of course.

Example: Because of the regularity of relations in the links, the following set of trees cannot be represented by a tree schema:

{ [figure: f; t]| t ∈ H(F)}

This set corresponds to the meta-expression semantics of a term of infinite non-

groundness: {| [figure: f; x]|}. Note the difference with the following set of trees which

can be represented by a tree schema:

X = { [figure: f; x; y] | x ∈ X and y ∈ H(F)} is represented by [figure: f; _{1_{F}}]

♢

5.5.2 Strong Determinism

The empty set admits a best skeleton representation, and so any tree schema representing the empty set is based on this skeleton. But as the skeleton of a tree schema represents a supset of the set represented by the tree schema, testing emptiness is just testing whether the tree schema is labeled by some (◯, x, l) of arity 0. So emptiness is decidable in constant time.

This good algorithmic result is a consequence of a strong notion of determinism in the procedure deciding membership in tree schemata. This procedure is deterministic in the usual sense, that we don’t have to backtrack on a decision in the process. Moreover, in the course of the decision process, we know at every point that there is a tree in the set represented by the tree schema that would lead the decision precess to that point.

5.5.3 Sources of Non-Uniqueness

Tree schemata use the algorithms to maintain a kind of minimalization properties that come from the representation of regular trees. Yet, sets of trees may be non-uniquely represented by tree schemata. This is a bad point for tree schemata, as because of this non-uniqueness, the representation does not get the full benefit from the minimalization. Mostly, non-uniqueness stems from the links. These sources of non-uniqueness have not been treated in this presentation of tree schemata, because the cost to treat them was deemed to high. In some cases, though, we can present heuristics to limit non-uniqueness.

Decomposition in Independent Relations

Allowing decomposition of the links in independent relations is one of the big algorithmic issues of tree schemata. This decomposition may come naturally, for free, when building the tree schemata. But it does not mean that we get the most decomposed relations, which would lead to more efficient algorithms. The problem is that, except in some rare cases, deciding whether a given relation can be decomposed is difficult.

Entry Names

Entry names are the only place were we introduced variables. They raise two problems: the choice of the names, as only the fact that they are different matters, and finding out equivalent entries.

Concerning the choice of the names, we can give two possible heuristics. The first one consists in giving to a set of equivalent entries the index of the first entry as the entry name for these entries. Note that there is no problem of interference between variable names of different relations. The problem of this choice is that we must then maintain this property when modifying the relation. In particular, we need the knowledge of which entry comes first. The second heuristic consists in giving to the entries the node to which they are related in the tree schema. Because for some equivalent entries, the nodes will be different, this will differentiate some equivalent entries. If two nodes that are equal are associated with a relation through non equivalent entries, we can use the first heuristic.

Concerning the discovery of the equivalence sets of entries, the problem is quite similar to the decomposition in independent relations. For the most common relation, equality, we know that the different entries are equivalent, but the problem is to hard in general.

Never Instantiated Relations

When defining the possible links imposed on a tree schemata, we were mainly concerned by the best skeleton approximation and the necessity that links don’t restrict too much the set of trees. But sometimes, the links simply don’t add (or rather remove) anything, or could be smaller and have the same effect. Finding out whether it is the case might be too costly, but we can come with this knowledge when performing some necessary algorithms. So it can be useful to identify those cases.

The first case is when a given entry in a relation is never reached. Although we always check that each entry name is associated with one node at least, it is more difficult to check that the number of different paths leading to nodes with that entry name is the same as the number of entries with that name. The main reason is that a given node may be accessed from more than one path. Note that it is a non local information.

The second case involves the relation between two nodes that cannot be both visited during the decision procedure of a given tree. This cannot concern parent nodes. But it is the case if every closest common ancestor of the two nodes is a choice node. This property is not always checked, because it is not local.

Algorithms on Tree Schemata

In this chapter, we show some algorithms on tree schemata that may be useful in abstract interpretation. These algorithms prove constructively some properties of the tree schemata, such as the decidability of the inclusion testing. They may also serve as guidelines for the development of other algorithms on tree schemata.

The essence of the representation by tree schemata is the decomposition of the set of trees in a tree structure (the skeleton) and relations (the links). Algorithms manipulating relations have already been presented in chapter 4. In order to introduce progressively the different concepts and difficulties of the algorithms, we first present the algorithms on skeletons, and then the definitive algorithms combining the difficulties of both skeletons and relations.

6.1 Auxiliary Informations on the Links

Links are local in the way they are accessed and shared, but they require a global information structure when building constructively the set represented by a tree schema (page 99). When we are just interested by the finite behaviors of the links, we can use these global informations when going through the tree schemata to compare different links with different entry names and even different sets of entries. But sometime, we may need a more global information on the links to perform operations on the entire relations. In this case, it is useful to know the scope of the links, and to be able to compare the entries of two links on different tree schemata. Such informations can be computed, but if they are needed often enough, they should be kept once for all while building the tree schemata. That is, if the information can be made local and does not add any new source of non-uniqueness.

The scope of the link can be defined as follows: when going through the tree schema, the scope of a link l starts at the first choice node linked to l we can encounter and stops at the last choice node linked to l that we can encounter. This intuitive definition has two drawbacks: it depends on the particular way of going through the tree schema (the covering ordering), and if we follow the loops indefinitely, there is no reason why we should have a “last” choice node. But we can give another notion of scope that is still local and does not depend on the particular covering of the trees: the scope of a link is the smallest (for ⋖) subtree of the tree schema that contains every choice node linked to l.

The scope of a link is indeed a good place (or key to the place) to store information about the link: we know that the link does not have to be taken into account until we first encounter the scope, and we don’t have to care anymore once every subtree of the scope have been treated. Moreover, as soon as we don’t modify any subtree of the scope, the scope does not change, so the information is still local and can be shared, without maintenance. In order to be able to compare links coming from different tree schemata, we need to make a correspondence between the different entries of the links, that is, we need to now the entry index as a path in the tree schema. This information can be stored relative to the scope by a tree, whose root corresponds to the scope, and which is labeled by entry names plus a new label, -.

Example: The following schema is the scope of l. The second tree is the entry tree associated with l:

[figure: f; ◯; x; y; l; ◯; g; a; b; h; -; x; y]

♢

Another useful information that we can store is whether the link corresponds to a best skeleton or not. This information can allow the use of optimizations based on the fact that the skeleton are best upper approximations.

6.2 Inclusion

Inclusion testing is a basic operation that is performed in the iteration sequences, at each iteration, to see if we have reached a fixpoint or a post fixpoint.

6.2.1 Inclusion of Skeletons

The idea of the algorithms deciding whether a skeleton T represents a subset of the skeleton U is to find a t ∈ Ens(T) that is not in Ens(U). It is performed by going through T and U at the same time. We don’t need to enumerate all the trees in Ens(T) because of the regularity properties of T and U.

inclusionSkel(T, U):
if if if T = ◯ then then then return return return(true true true)
if if if U = ◯ then then then return return return(false false false)
return return return(inclusionSkelRec(T, U, ∅))
inclusionSkelRec(T, U, A):
if if if (T, U) ∈ A then then then return return return(true true true)

A′ ← ← ← A ∪ {(T, U)}

if if if T = [figure: ◯; T_{0}; T_{n}] then then then
if if if U = [figure: f; U_{0}; U_{m−1}] then then then return return return(false false false)

U is [figure: ◯; U_{0}; U_{m}]

for for for i ← ← ← 0 to to to n do do do

T_{i} is [figure: f_{i}; _{T_{i}_{0}}; _{T_{i}_{p−1}}]

if if if ∃j such that U_{j} is [figure: f_{i}; _{U_{j}_{0}}; _{U_{j}_{p−1}}] then then then

A′ ← ← ← A′ ∪ {(T_{i}, U_{j})}

  for for for k ← ← ← 0 to to to p − 1 do do do
   if if if inclusionSkelRec(T_{i}_{k}, U_{j}_{k}, A′) = false false falsethen then then return return return(false false false)
else else else return return return(false false false)
return return return(true true true)
else else else T is [figure: f; T_{0}; T_{n−1}]
if if if U = [figure: g; U_{0}; U_{m−1}] then then then
if if if g ≠ f then then then return return return(false false false)
for for for i ← ← ← 0 to to to n − 1 do do do
  if if if inclusionSkelRec(T_{i}, U_{i}, A′) = false false falsethen then then return return return(false false false)
return return return(true true true)

U is [figure: ◯; U_{0}; U_{m}]

if if if ∃U_{i} such that U_{i} = [figure: f; V_{0}; V_{n−1}] then then then

A′ ← ← ← A′ ∪ {(T, U_{i})}

for for for j ← ← ← 0 to to to n − 1 do do do
  if if if inclusionSkelRec(T_{j}, U_{i}_{j}, A′) = false false falsethen then then return return return(false false false)
return return return(true true true)
else else else return return return(false false false)

6.2.2 Inclusion of Tree Schemata

In the case of tree schemata, we must also check the inclusion of the relations represented by the links. But it can be performed in the way described by the constructive definition of the set represented by a tree schema (page 99) while going through the skeleton. This traversal of the tree schemata is necessary anyway to find the links and compare them. It is used to test the inclusion of the finite parts of the relations. For the infinite parts of the relations, we must compare the links globally, using the auxiliary informations.

The Algorithm

inclusion(T, U):
  if if if T = ◯ then then then return return return(true true true)
  if if if U = ◯ then then then return return return(false false false)
  Links ← ← ← ∅^{G}
  return return return(inclusionRec(T, U, {<T_{∅}, U_{∅} >}, ∅) ≠ (∅, ∅))
inclusionRec(T, U, Γ, A):
  if if if (T, U) ∈ A then then then

l_{1} is the link in the loop of T, and l_{2} is the link in the loop of U add (l_{1}, l_{2}) to Links^{E} (and l_{1} and l_{2} to Links^{N} if necessary)

   return return return(Γ, ∅)
  if if if T = [figure: ◯; x; l; T_{0}; T_{n}] then then then
   if if if U is labeled by a f ∈ F then then then

if if if l is a link that preserves the best skeleton approximation then then then

       return return return(∅, ∅)

     else else else

∀T_{i} not labeled by f do do do (Γ′, b) ← ← ← instGlobRels(Γ, l, x, i, 0)

        if if if Γ′ ≠ ∅ then then then return return return(∅, ∅)

Let T_{i} be the only possible choice. (T_{i} is labeled by f)

(Γ′, b) ← ← ← instGlobRels(Γ, l, x, i, 0)

A′ ← ← ← A ∪ {(T, U)}

(Γ′′, L) ← ← ← inclusionChildren(T_{i}, U, Γ′, A′) if if if T is the scope of some links in Links^{N} then then then

add these links to L

if if if a subset of L is a connected part of Linksthen then then L′ ← ← ← the biggest such subset of L remove L′ from Links^{N} if if if the links in L′ of T are included in the links in L′ of U then then then

     return return return(Γ′′, L\L′)
   else else else return return return(∅, ∅)
return return return(Γ′′, L)

U is [figure: ◯; y; h; U_{0}; U_{m}]

A′ ← ← ← A ∪ {(T, U)}

for for for i ← ← ← 0 to to to n do do do

Γ_{res} ← ← ← ∅, L_{res} ← ← ← ∅

T_{i} is [figure: f_{i}; _{T_{i}_{0}}; _{T_{i}_{p−1}}]

if if if ∃j such that U_{j} is [figure: f_{i}; _{U_{j}_{0}}; _{U_{j}_{p−1}}] then then then

(Γ′, b) ← ← ← instGlobRels(Γ, l, x, i, 0)

if if if Γ′ ≠ ∅ then then then

(Γ_{0}, b) ← ← ← instGlobRels(Γ′, h, y, j, 1)

  if if if b then then then return return return(∅, ∅)

(Γ′, L) ← ← ← inclusionChildren(T_{i}, U_{j}, Γ_{0}, A′)

  if if if Γ′ = ∅ then then then return return return(∅, ∅)

Γ_{res} ← ← ← Γ_{res} ∪ Γ′, L_{res} ← ← ← L_{res} ∪ L else else else if if if l is a link that preserves the best skeleton approximation then then then

return return return(∅, ∅)

else else else

(Γ′, b) ← ← ← instGlobRels(Γ, l, x, i, 0)

if if if Γ′ ≠ ∅ then then then return return return(∅, ∅)

if if if T or U are scopes of some links in Links^{N} then then then add these links to L_{res} if if if a subset of L_{res} is a connected part of Linksthen then then

L′ ← ← ← the biggest such subset of L_{res} remove L′ from Links^{N} if if if the links in L′ of T are included in the links in L′ of U then then then

  return return return(Γ_{res}, L_{res}\L′)
else else else return return return(∅, ∅)

return return return(Γ_{res}, L_{res})

else else else T is [figure: f; T_{0}; T_{n−1}]
if if if U = [figure: g; U_{0}; U_{m−1}] then then then
if if if g ≠ f then then then return return return(∅, ∅)
return return return(inclusionChildren(T, U, Γ, A))

U is [figure: ◯; y; h; U_{0}; U_{m}]

  if if if ∃U_{i} labeled by f then then then

(Γ′, b) ← ← ← instGlobRels(Γ, l, x, i, 1)

   if if if b then then then return return return(∅, ∅)

A′ ← ← ← A ∪ {(T, U)}

Γ′′, L ← ← ← inclusionChildren(T, U_{i}, Γ′, A′) if if if U is the scope of some links in Links^{N} then then then

add these links to L if if if a subset of L is a connected part of Linksthen then then

L′ ← ← ← the biggest such subset of L remove L′ from Links^{N} if if if the links in L′ of T are included in the links in L′ of U then then then

        return return return(Γ′′, L\L′)
       else else else return return return(∅, ∅)
   return return return(Γ′′, L)
  else else else return return return(∅, ∅)
inclusionChildren(T, U, Γ_{0}, A):

T is [figure: f; T_{0}; T_{n−1}], and U is [figure: f; U_{0}; U_{n−1}]

A′ ← ← ← A ∪ {(T, U)}

for for for i ← ← ← 0 to to to n − 1 do do do

(Γ_{i+1}, L_{i}) ← ← ← inclusionRec(T_{i}, U_{i}, Γ_{i}, A′)

L′_{i} ← ← ← L_{i} with the relative paths updated by i

  if if if Γ_{i+1} = ∅ then then then return return return(∅, ∅)

L ← ← ← ⋃_{i<n} L′_{i} if if if T or U are scopes of some links in Links^{N} then then then

add these links to L

if if if a subset of L is a connected part of Linksthen then then L′ ← ← ← the biggest such subset of L remove L′ from Links^{N} if if if the links in L′ of T are included in the links in L′ of U then then then

     return return return(Γ_{n}, L\L′)
   else else else return return return(∅, ∅)
return return return(Γ_{n}, L)
instGlobRels(Γ, l, x, v, i):

Γ′ ← ← ← ∅

b ← ← ← false false false
∀G ∈ Γ do do do

G ← ← ← G_{(i)}

  if if if v ∈ G(l)_{(x)} then then then

G′ ← ← ← G where the i^{th} component has been replaced by G_{x=v}^{l} Γ′ ← ← ← Γ′ ∪ {G′}

   else else else b ← ← ← true true true
  return return return(Γ′, b)

Inclusion of the Links

To decide the inclusion of the links of a tree schema in the links of another tree schema, we use an extended version of inclusionRel (or another basic inclusion algorithm for relations if they are represented by another mean than ω-deterministic relation). The only difference is that we use sets of independent relations instead of relations. We just have to use the couples of sets instead of the couples of relations. As a guideline, we evaluate in sequence the entries in a vector of equivalent entries.

Example: We try to decide whether T is included in U:

T = [figure: f; ◯; x; y; r; ◯; g; a; b; h] , U = [figure: f; ◯; x; s; ◯; g; a; b; h]

r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar@{-->}[dr]^{1} \ar[ddr]_{0} &  & y \ar[dl]_{0} \ar[ddl]^{1} \\  & true \\  & false}  s = [figure: x; 0; 1; true]

The result of the computation on the finite part is that T can be included in U. But when we compare the links, r for T, and s and true for U, we see that the evaluation 01 on entries 0 and 1 (relative paths to the root) give the same relations, but going through true for r, and not for s. Thus, T is not included in U: f(g^{ω}, h^{ω}) is in T but not in U. ♢

6.3 Intersection

6.3.1 Intersection of Skeletons

Skeletons are closed by intersection, most of the work in the intersection of skeletons is performed by the algorithms on regular trees. The only thing that must be performed to ensure the uniqueness of the representation is the propagation of the empty set.

interSkel(T, U):
if if if T = ◯ or or or U = ◯ then then then return return return(◯)
return return return(interSkelRec(T, U, ∅))
interSkelRec(T, U, A):
if if if T = U then then then return return return(T)
if if if {T, U} ∈ dom(A) then then then return return return(A({T, U}))

X is a new label of arity 0 A′ ← ← ← A with {T, U}→X

if if if T = [figure: ◯; T_{0}; T_{n}] then then then
  if if if U = [figure: ◯; U_{0}; U_{m}] then then then

i ← ← ← 0

   for for for j ← ← ← 0 to to to n do do do

if if if ∃U_{k} with the same label as T_{j} then then then S_{i} ← ← ← interSkelRec(T_{j}, U_{k}, A′)

       if if if S_{i} ≠ ◯ then then then i ← ← ← i + 1
   if if if i = 0 then then then return return return(◯)
   if if if i = 1 then then then return return return(recCons(S_{0}, X))

   return return return^{(recCons ( [figure: ◯; S_{0}; S_{i}], X))}

  else else else U is [figure: f; U_{0}; U_{m−1}]
   if if if ∃T_{i} labeled by f then then then return return return(recCons(interSkelRec(T_{i}, U, A′), X))
   return return return(◯)
else else else if if if U = [figure: ◯; U_{0}; U_{n}] then then then
  if if if ∃U_{i} with the same label as T then then then return return return(recCons(interSkelRec(T, U_{i}, A′), X))
  else else else return return return(◯)

T is labeled by [figure: f; T_{0}; T_{n−1}], and U is labeled by [figure: g; U_{0}; U_{m−1}]

if if if f ≠ g then then then return return return(◯)
for for for i ← ← ← 0 to to to n − 1 do do do

S_{i} ← ← ← interSkelRec(T_{i}, U_{i}, A′)

  if if if S_{i} = ◯ then then then return return return(◯)

return return return(recCons ( [figure: f; S_{0}; S_{n−1}] , X))

6.3.2 Intersection of Tree Schemata

In the intersection of tree schemata, we can use global informations to take advantage of the necessary traversal of the tree schemata to deal with the finite parts of the relations at the same time, as for inclusion. But it leads to a quite intricate algorithm. Instead, we just partially deal with the finite part of the relations. The property that we use is the following: Set(T) ∩ Set(U) ⊂ Ens(interSkel(skel (T) , skel (U))). This property holds even if there is no best skeleton approximation. So the algorithm proceeds in three steps: we go through the schemata to compute the intersection of their skeletons and the least common scopes. When we reach an independent least common scope, we compute the intersection of the relations represented by the links on the new skeleton. Then, we may update the skeleton so that we still have the best skeleton approximation, if possible.

Main Algorithm: Traversal of the Tree Schemata

The main algorithm consists in going through the tree schemata to compute, as a first approximation, the intersection of their skeletons. Meanwhile, we collect some informations on the links to help the computation of their intersection when we reach a common scope. This information consists in a sequence associated with every entry name of every link. This sequences are made of subsets of the range of the entries, corresponding to the entries that are kept in the intersection of the skeletons.

intersection(T, U):
  if if if T = ◯ or or or U = ◯ then then then return return return(◯)
  Links ← ← ← ∅^{G}

Restrictions is a function that associates the empty sequence with each entry

name of each link (S, L) ← ← ← interRec(T, U, ∅)

  return return return(S)
interRec(T, U, A):
  if if if T = U then then then return return return(T, ∅)
  if if if {T, U} ∈ dom(A) then then then return return return(A({T, U}), ∅)

X is a new label of arity 0

A′ ← ← ← A with {T, U}→X

  if if if T = [figure: ◯; x; l; T_{0}; T_{n}] then then then
   if if if U = [figure: ◯; y; h; U_{0}; U_{m}] then then then

i ← ← ← 0

I ← ← ← ∅, J ← ← ← ∅

for for for j ← ← ← 0 to to to n do do do

if if if ∃U_{k} with the same label as T_{j} then then then (S_{i}, L_{i}) ← ← ← interRec(T_{j}, U_{k}, A′)

   if if if S_{i} ≠ ◯ then then then

I ← ← ← I ∪ {j} J ← ← ← J ∪ {k} i ← ← ← i + 1

if if if i = 0 then then then return return return(◯, ∅)
add I to Restrictions(l, x), and J to Restrictions(h, y)

add (l, h) to Links^{E} L ← ← ← ⋃_{j<i} L_{j}

if if if i = 1 then then then S ← ← ← recCons(S_{0}, X)
else else else S ← ← ← recCons ( [figure: ◯; S_{0}; S_{i}], X)
else else else U is [figure: f; U_{0}; U_{m−1}]
if if if ∃T_{i} labeled by f then then then

add {i} to Restrictions(l, x)

(S, L) ← ← ← recCons(interRec(T_{i}, U, A′), X)

else else else return return return(◯, ∅)
else else else if if if U = [figure: ◯; x; l; U_{0}; U_{n}] then then then

if if if ∃U_{i} with the same label as T then then then add {i} to Restrictions(l, x) (S, L) ← ← ← recCons(interRec(T, U_{i}, A′), X)

else else else return return return(◯, ∅)

else else else T is labeled by [figure: f; T_{0}; T_{n−1}], and U is labeled by [figure: g; U_{0}; U_{m−1}]

if if if f ≠ g then then then return return return(◯, ∅)
for for for i ← ← ← 0 to to to n − 1 do do do

(S_{i}, L_{i}) ← ← ← interRec(T_{i}, U_{i}, A′)

if if if S_{i} = ◯ then then then return return return(◯, ∅)

L′_{i} ← ← ← L_{i} with the relative paths updated by i L ← ← ← ⋃_{i<n} L′_{i}

S ← ← ← recCons ( [figure: f; S_{0}; S_{n−1}] , X)

return return return(interLink(T, U, S, L))

interlink(T, U, S, L):

if if if T or U is the scope of a link then then then L′ ← ← ← L plus those links if if if a subset of L′ is a connected part of Linksthen then then

L′′ ← ← ← the biggest such subset of L′ remove L′′ from Links^{N} and L′ compute the intersection of the links in L′′ and add this link in S S′ ← ← ← S updated so that it satisfies the best skeleton approximation

     return return return(S′, L′)
   return return return(S, L′)
  return return return(S, L)

Intersection of the Links

To compute the new link that is the intersection of the links of the two tree schemata, we use an extension of the intersection algorithm on relations (inter-Rel, for ω-deterministic relations), just as for inclusion. We use the information computed in Restrictions, and the relative paths of the links to harmonize the two sets of links of the two tree schemata. Then, the only difference with the basic algorithm is the use of vectors of relations for loop testing instead of mere relations. This new link is then added to the skeleton that was computed so far.

Example: We compute the intersection of T and U defined below:

T = [figure: f; ◯; x; y; r; ◯; g; a; b; h] , U = [figure: f; ◯; x; s; ◯; g; a; b; h]

r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar@{-->}[dr]^{1} \ar[ddr]_{0} &  & y \ar[dl]_{0} \ar[ddl]^{1} \\  & true \\  & false}  s = [figure: x; 0; 1; true]

The two tree schemata have the same skeleton, so the first approximation of the skeleton of their intersection gives the same skeleton. The intersection of r and (s, true) gives the relation t defined below:

T ∩ U = [figure: f; ◯; x; y; t; ◯; g; a; b; h] t = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[ur]_{1} \ar[dr]_{0} & & y \ar[dl]_{1} \ar[dr]^{0} \\ & false & & true}

♢

Updating the Skeleton According to the New Link

The skeleton of the new tree schema must respect the rules defined section 5.4.1 (page 106) so that as much information as possible is put in the skeleton. To update correctly the skeleton, we must analyze the relation R of the link. To insure the fullness of the relation, we first compute the different R_{(x)} for all x entry name.

∀x entry name of R do do do

  if if if R_{(x)} = ∅ then then then

replace every node [figure: ◯; x; R; T_{0}; T_{n}] by ◯.

propagate the information until no ◯ appears in S or S = ◯

  else else else if if if R_{(x)} = {i} then then then

replace every node [figure: ◯; x; R; T_{0}; T_{n}] by T_{i}

  else else else if if if |R_{(x)}| ≤ n then then then

remove every T_{i} such that i ∉ R_{(x)} from [figure: ◯; x; R; T_{0}; T_{n}]

change the values of x such that x ranges from 0 to |R_{(x)}| − 1

The last step to enforce the rules is to remove the link from every node linked by an x such that x does not appear in the decision diagram of R.

All these operations give a new tree schema S′ valid with respect to the definition of section 5.4.1, except possibly for the last rule. This rule asks that if there is a best skeleton approximation, skel (S′) is this skeleton.

In order to compute the tree schema with best skeleton, we can follow the instructions described below:

while while while skel (S′) is not the best skeleton for Ens(S′) do do do

there is T ⋖ U ⋖ S′ such that:

T is labeled by (◯, x, l), U is labeled by (◯, y, l) and

there is a path p from U to T that does not allow every choice of T replace U_{[p]} by the new restrained choice node

If Ens(S′) admits a best skeleton approximation, then the process terminates. Sometimes, we can recognize whether the set admits a best skeleton approximation. It is the case if both the tree schemata of which S′ is the intersection admit best skeletons. We can also recognize cases of no best skeleton approximation as described in the second case page 104. But in some other cases, we don’t have any efficient algorithm to decide whether the process of best skeleton construction will terminate. In these cases, we can stop after an arbitrary number of iterations and let skel (S′) not be the best skeleton of Ens(S′). The only effect of this approximation is a reduction of the efficiency of further algorithms on S′.

6.4 Union

6.4.1 Union of Skeletons

Union is interesting in that it introduces new links, even when we start from mere skeletons with no links. Note that if we don’t add links, we get the best skeleton containing the union of T and U.

unionSkel(T, U):
  if if if T = ◯ then then then return return return(U)
  if if if U = ◯ then then then return return return(T)
  return return return(unionSkelRec(T, U, ∅))
unionSkelRec(T, U, A):
  if if if T = U then then then return return return(T)
  if if if {T, U} ∈ A then then then return return return(A({T, U})

X is a new label of arity 0 A′ ← ← ← A with {T, U}→X

  if if if T = [figure: ◯; t_{0}; t_{n}] then then then
   if if if U = [figure: ◯; u_{0}; u_{m}] then then then

i ← ← ← 0, j ← ← ← 0, k ← ← ← 0

     while while while j ≤ n and and and k ≤ m do do do

f is the label of T_{j} and g is the label of U_{k}

       if if if f <_{F} g then then then

S_{i} ← ← ← T_{j} j ← ← ← j + 1

       else else else if if if g <_{F} f then then then

S_{i} ← ← ← U_{k} k ← ← ← k + 1

       else else else (f = g)

S_{i} ← ← ← unionSkelRec(T_{j}, U_{k}, A)

j ← ← ← j + 1, k ← ← ← k + 1 i ← ← ← i + 1

     while while while j ≤ n do do do

S_{i} ← ← ← T_{j}

i ← ← ← i + 1, j ← ← ← j + 1

     while while while k ≤ m do do do

S_{i} ← ← ← U_{k}

i ← ← ← i + 1, k ← ← ← k + 1

     return return return^{(recCons ( [figure: ◯; S_{0}; S_{i−1}] , X))}

U is labeled by g

if if if ∃T_{i} labeled by g then then then

S_{i} ← ← ← unionSkelRec(T_{i}, U, A) ∀j ≤ n, j ≠ i do do do S_{j} ← ← ← T_{j}

return return return^{(recCons ( [figure: ◯; S_{0}; S_{n}] , X))}
else else else

i is the index of insertion of g in the sequence of labels of T_{j} ∀j < i do do do S_{j} ← ← ← T_{j} S_{i} ← ← ← U ∀j ∈ [i, n + 1[ do do do S_{j+1} ← ← ← T_{j}

return return return^{(recCons ( [figure: ◯; S_{0}; S_{n+1}] , X))}

else else else if if if U = [figure: ◯; U_{0}; U_{n}] then then then

T is labeled by f

if if if ∃U_{i} labeled by f then then then

S_{i} ← ← ← unionSkelRec(T, U_{i}, A) ∀j ≤ n, j ≠ i do do do S_{j} ← ← ← U_{j}

return return return^{(recCons ( [figure: ◯; S_{0}; S_{n}] , X))}
else else else

i is the index of insertion of f in the sequence of labels of U_{j} ∀j < i do do do S_{j} ← ← ← U_{j} S_{i} ← ← ← T ∀j ∈ [i, n + 1[ do do do S_{j+1} ← ← ← U_{j}

return return return^{(recCons ( [figure: ◯; S_{0}; S_{n+1}] , X))}

else else else T = [figure: f; T_{0}; T_{n−1}] and U = [figure: g; U_{0}; U_{n−1}]

if if if f < g then then then return return return(recCons ( [figure: ◯; T; U], X))
if if if f > g then then then return return return(recCons ( [figure: ◯; U; T], X))
for for for i ← ← ← 0 to to to n − 2 do do do

(S_{i}, L_{i}) ← ← ← unionWithLinks(T_{i}, U_{i}, A)

if if if all L_{i} are empty then then then

S_{n−1} ← ← ← unionSkelRec(T_{n−1}, U_{n−1}, A)

return return return(recCons ( [figure: f; S_{0}; S_{n−1}] , X))

S_{n−1} ← ← ← unionWithLinks(T_{n−1}, U_{n−1}, A)

S ← ← ← recCons ( [figure: f; S_{0}; S_{n−1}] , X)

if if if more than one L_{i} is not empty then then then

L ← ← ← S →⋃_{i<n} im(L_{i})

else else else L ← ← ← ⋃_{i<n} L_{i}
makeUnionLink(L, S)
return return return(S)
unionWithLinks(T, U, A):
if if if T = U then then then return return return(T)
if if if {T, U} ∈ A then then then return return return(A({T, U})

X is a new label of arity 0 A′ ← ← ← A with {T, U}→X

if if if T = [figure: ◯; t_{0}; t_{n}] then then then
if if if U = [figure: ◯; u_{0}; u_{m}] then then then

i ← ← ← 0, j ← ← ← 0, k ← ← ← 0 I ← ← ← ∅, J ← ← ← ∅ L ← ← ← ∅

while while while j ≤ n and and and k ≤ m do do do

f is the label of T_{j} and g is the label of U_{k}

if if if f <_{F} g then then then

S_{i} ← ← ← T_{j} I ← ← ← I ∪ {i} j ← ← ← j + 1

else else else if if if g <_{F} f then then then

S_{i} ← ← ← U_{k} J ← ← ← J ∪ {i} k ← ← ← k + 1

else else else (f = g)

(S_{i}, L′) ← ← ← unionWithLinks(T_{j}, U_{k}, A) L ← ← ← L ∪ L′ I ← ← ← I ∪ {i}, J ← ← ← J ∪ {i} j ← ← ← j + 1, k ← ← ← k + 1

i ← ← ← i + 1

while while while j ≤ n do do do

S_{i} ← ← ← T_{j} I ← ← ← I ∪ {i} i ← ← ← i + 1, j ← ← ← j + 1

while while while k ≤ m do do do

S_{i} ← ← ← U_{k}

J ← ← ← J ∪ {i}

i ← ← ← i + 1, k ← ← ← k + 1

S ← ← ← recCons ( [figure: ◯; S_{0}; S_{i−1}] , X)

if if if I ≠ J then then then L ← ← ← L ∪ ◯→(S, I, J)
return return return(S, L)

U is labeled by g

if if if ∃T_{i} labeled by g then then then

(S_{i}, L) ← ← ← unionWithLinks(T_{i}, U, A) ∀j ≤ n, j ≠ i do do do S_{j} ← ← ← T_{j} I ← ← ← [n + 1] J ← ← ← {i}

S ← ← ← recCons ( [figure: ◯; S_{0}; S_{n}] , X)

return return return(S, L ∪ ◯→(S, I, J))
else else else

i is the index of insertion of g in the sequence of labels of T_{j} ∀j < i do do do S_{j} ← ← ← T_{j} S_{i} ← ← ← U ∀j ∈ [i, n + 1[ do do do S_{j+1} ← ← ← T_{j} J ← ← ← {i} I ← ← ← [n + 2]\{i}

S ← ← ← recCons ( [figure: ◯; S_{0}; S_{n+1}] , X)

return return return(S, ◯→(S, I, J))

else else else if if if U = [figure: ◯; U_{0}; U_{n}] then then then

T is labeled by f

if if if ∃U_{i} labeled by f then then then

(S_{i}, L) ← ← ← unionWithLinks(T, U_{i}, A) ∀j ≤ n, j ≠ i do do do S_{j} ← ← ← U_{j} I ← ← ← {i} J ← ← ← [n + 1]

S ← ← ← recCons ( [figure: ◯; S_{0}; S_{n}] , X)

return return return(S, L ∪ ◯→(S, I, J))
else else else

i is the index of insertion of f in the sequence of labels of U_{j} ∀j < i do do do S_{j} ← ← ← U_{j} S_{i} ← ← ← T ∀j ∈ [i, n + 1[ do do do S_{j+1} ← ← ← U_{j} I ← ← ← {i} J ← ← ← [n + 2]\{i}

S ← ← ← recCons ( [figure: ◯; S_{0}; S_{n+1}] , X)

return return return(S, ◯→(S, I, J))

else else else T = [figure: f; T_{0}; T_{n−1}] and U = [figure: g; U_{0}; U_{n−1}]

if if if f < g then then then

S ← ← ← recCons ( [figure: ◯; T; U], X)

return return return(S, S →(S, {0}, {1}))

else else else if if if f > g then then then

S ← ← ← recCons ( [figure: ◯; U; T], X)

return return return(S, S →(S, {1}, {0}))

for for for i ← ← ← 0 to to to n − 1 do do do

(S_{i}, L_{i}) ← ← ← unionWithLinks(T_{i}, U_{i}, A)

S ← ← ← recCons ( [figure: f; S_{0}; S_{n−1}] , X)

if if if more than one L_{i} is not empty then then then

L ← ← ← S →⋃_{i<n} im(L_{i})

else else else L ← ← ← ⋃_{i<n} L_{i}
return return return(S, L)

makeUnionLink(L, T):

∀U ∈ dom(L)\{◯} do do do {(C_{0}, I_{0}, J_{0}), …, (C_{n}, I_{n}, J_{n})} is L(U) Let x_{0}, …, x_{n} be a set of entry names R ← ← ← ⨂_{i≤n} I_{i} ⋃ ⨂_{i≤n} J_{i}

if if if R ≠ ⨂_{i≤n} I_{i} ∪ J_{i} then then then

l ← ← ← the link defined by R, and x_{i} →C_{i} replace the label ◯ of C_{i} by [figure: ◯; x_{i}; l] register the scope of l to be U

A consequence of the algorithm is that if the labels in F are of arity 0 or 1 only, no link is created during the computation of the union. As union is the only basic algorithm introducing links, it means that as long as we manipulate sets of vectors with basic algorithms, we will not have any link in the tree schemata. This property justifies the use of tree schemata to represent relations (section 4.4.1).

6.4.2 Union of Tree Schemata

The extension of union to tree schemata is the same as the extension of intersection to tree schemata: while going through the two tree schemata, we build the union of their skeletons, and gather informations about the links. When we attain a least common scope, we compute the union of the links, in the same way as for intersection of links.

The only difference is the introduction of new links by the sharing of common prefixes. It means that we must also compute the intersection of the links with the additional links generated by the union of the skeletons. A consequence is that we don’t have to detect least common scope when we are in the phase unionWithLinks of the algorithms. We can wait until we reach the scope of the link generated by union, that is until we are in unionRec or makeUnionLink.

Remember also another difference with intersection if we use ω-deterministic relations: in that case, we might sometimes approximate the union of the links. In this case, the algorithm will just compute an approximation of the union.

6.5 Projection

Projection is an important algorithm because it is —with union— one of the constructive algorithm used in section 5.4.2 to describe the set of tree schemata.

6.5.1 Definition

Projection concerns only some paths in the tree schema. Suppose for example that g ∈ F of arity 3. One possible projection would be the set of trees that appear at first position. Then we don’t care about the second or third position. To describe this fact, we introduce a new label, Ω, which can stand for any subtree. Let t be a tree on F ∪ {Ω}. We say that t is a possible prefix in the set of trees E, and we write t ∈_{Ω} E if there is a function f from paths p such that t(p) = Ω to H(F) such that the tree u defined below is in E: v(q) = t(q) if t(q) ≠ Ω and v_{[p]} = f(p) if t(p) = Ω.

Let t be a tree on F ∪ {Ω, x} and T a tree schema. The projection of T on t according to x is defined as t_{x}^{−1} (T) =^{def} {u ∈ H(F) | t[x\u] ∈_{Ω} Set(T)}. Note that projection subsumes intersection: Let T and U be two tree schemata, and ∩ a

new label of arity two then: T ∩ U = [figure: ∩; x; x]_{x}^{−1} ( [figure: ∩; T; U])

We define tree projection with respect to one variable only, but it is possible to define it with respect to a finite vector of variables (the result is a set of vectors of trees). The algorithms below can easily be extended to that case, but for the simplicity of the presentation, we will only consider one variable.

6.5.2 Projection of Skeletons

We progressively refine the set t_{x}^{−1} (T) as we go through T and t. At the beginning, this set is H(F) (which is in Sk^{∴}(F), the set of sets of trees that can be represented by a skeleton, because F is finite). When we discover that t[x\Ω] ∉_{Ω} Ens(T), this set becomes empty and we return. When we come to a new path p such that t(p) = x, we intersect the set with the skeleton at this point. So we just need to visit the distinct T_{[p]} such that t(p) = x.

projSkel(t, x, T):

  Result ← ← ← 1_{F}

Mem ← ← ← ∅

  projSkelRec(t, x, T)
  return return return(Result)
projSkelRec(t, x, T):
  if if if t ≠ Ω and and and (t, T) ∉ Memthen then then

add (t, T) to Mem

   if if if t = x then then then
     Result ← ← ← interSkel(Result, T)
   else else else t is [figure: f; t_{0}; t_{n−1}]
     if if if T = [figure: ◯; T_{0}; T_{m}] then then then
       if if if ∃T_{i} labeled by f then then then projSkelRec(t, x, T_{i})
       else else else Result ← ← ← ◯
     else else else T is [figure: g; T_{0}; T_{m−1}]
       if if if f = g then then then
        for for for i ← ← ← 0 to to to n − 1 do do do projSkelRec(t_{i}, x, T_{i})
       else else else Result ← ← ← ◯

6.5.3 Projection of Tree Schemata

The computation of the projection of the skeleton corresponds to a kind of intersection algorithm between the skeleton and t[Ω\1_{F}][x\1_{F}], plus an intersection of all subtrees corresponding to x. We can use the same idea in the case of tree schemata, but this will give links linking nodes in the results to nodes outside of the result. It is a desirable feature during the computation, as it allows the different prefix requirements to affect the result, but at the end of the computation, we must forget these links.

As was the case for intersection, we can use a global information to deal with the finite part of the relations, taking advantage of the necessary traversal of the tree schema. But in order to simplify the presentation, we will collect the least common scope of every relation and use the algorithms on relations for every link.

projection(t, x, T):

  Result ← ← ← 1_{F}

Mem ← ← ← ∅

  Links ← ← ← ∅^{G}
  projRec(t, x, T)

forget in the links every entry which is linked outside of Result

  return return return(Result)

projRec(t, x, T):

L ← ← ← ∅

  if if if t ≠ Ω and and and (t, T) ∉ Memthen then then

add (t, T) to Mem

   if if if t = x then then then
     (Result, L) ← ← ← interRec(Result, T, ∅)
   else else else t is [figure: f; t_{0}; t_{n−1}]
     if if if T = [figure: ◯; x; l; T_{0}; T_{m}] then then then
       if if if ∃T_{i} labeled by f then then then L ← ← ← projRec(t, x, T_{i})
       else else else Result ← ← ← ◯
     else else else T is [figure: g; T_{0}; T_{m−1}]
       if if if f = g then then then
        for for for i ← ← ← 0 to to to n − 1 do do do L_{i} ← ← ← projRec(t_{i}, x, T_{i})

L ← ← ← ⋃_{i<n} L_{i}

       else else else Result ← ← ← ◯
  if if if T is the scope of a link then then then

L′ ← ← ← L plus those links if if if a subset of L′ is a connected part of Linksthen then then

L′′ ← ← ← the biggest such subset of L′ remove L′′ from Links^{N} and L′ compute the intersection of the links in L′′ and add this link in Result

   return return return(L′)
  return return return(L)

6.6 Meta Expressions

We overview how we can use the algorithms described above to compute the meta expressions of section 5.4.2 as language transformers. We suppose we have a finite set of set variables, V, and that each set variable X is associated with the tree schema T_{X}. We try to compute the value T_{e_{X}} which is the tree schema representing the semantics of the meta expression eX in the context of the current values of the set variables.

Meta expressions are finite and can be computed inductively. If the meta expression is a set variable X, then its new value is T_{X}. If it is a union e_{1} ∪ e_{2}, then its new value is the union of T_{e_{1}} and T_{e_{2}}.

The last case is e = {t′ : t_{1} ∈ e_{1} … t_{n} ∈ e_{n}}, with t′ a regular tree over F ∪v of finite groundness and each t_{i} a regular tree over F ∪v (v is a set of term variables). We start by computing the set of variable values, t_{1}_{v}^{−1} (T_{e_{1}}). It is performed with the projection algorithm. Then we modify slightly the projection algorithm, so that instead of starting from variables associated with the set of all possible trees, we start from the set of variable values that we just computed. And we keep going on until t_{n}_{v}^{−1} (T_{e_{n}}).

Then, starting from a set of variable values, we compute the set of trees represented by t′ in this context. t′ is of finite groundness, so each variable x appears finitely many times, say p times. If p = 1, then we just have to make a tree substitution. If p > 1, we first make a tree substitution, and we intersect the links of the tree schemata corresponding to each occurrence of x with the link which links every choice node of the p^{th} occurrence of x with the corresponding choice node of the other occurrence. The entry name of each occurrence must be different (e.g. p for the p^{th} occurrence) and the relation of the link is the equality relation.

Example:

e_{X} = \{ [figure: f; x; x]: \xymatrix{g \ar[d] \\ x}∈ Y\} ∪ \{a\} and T_{X} = 1_{F} and T_{Y} = \xymatrix{g \ar[d] \\ _{1_{F}}}

The result of the projection gives x → 1_{F}. As a result, we get the following tree schema:

T_{e_{X}} = [figure: ◯; a; f; _{1_{F}}; x; =; y; _{1_{F}}]

♢

6.7 Discussion

The algorithms described in this chapter are basic algorithms. They show how algorithms can be built to manipulate tree schemata. They depend highly on the algorithms described in chapters 3 and 4. As such, they may introduce approximations, for example in efficient union.

We saw in this chapter that the set of tree schemata is closed under finite basic operations such as union or projection. But still, in the domain of tree schemata, there are infinite increasing chains. Because of the regularity requirement for tree schemata, some of them don’t even have a limit in the set of tree schemata. So we might need some further approximations.

The main source of complexity in tree schemata is the links. The fewer the number of links, the more sharing we can achieve, and the more efficient the algorithms. So, a first approximation strategy can attack the links. By removing a link, or maybe just a part of it, we obtain an upper approximation (for inclusion) of the tree schema. Because the links that induce sets with no best skeletons are the most difficult to handle, they may be the first target of this kind of approximation.

The second possibility for approximation is the skeleton of the tree schema itself. The easiest one consists in replacing a subtree of the tree schema by 1_{F}. The choice of the subtree might be given by the observation of the growth of a part of the tree schemata during an iteration. A little more precise approximation, in the spirit of [Sch97], can force the equality of two subtrees by an approximation by their union.

All these approximation strategies can be computed by algorithms in the same spirit as those described in this chapter. The problem is their lack of precision in the choice of which part of the tree schema to approximate. In the next chapter, we introduce an extension to tree schemata that allow a more precise analysis.

Tree Schemata with Counters

Although already quite powerful, tree schemata may not be entirely satisfactory in abstract interpretation. In addition to the basic classical operations on sets of trees, abstract interpretation may use more complex operations in relation with the abstract values manipulated. In particular, during the computation of fixpoints, abstract interpretation may approximate the iteration through the use of widenings, which are based on abstraction of some iterates. In this case, we can use the approximations defined in chapter 6, but they are quite crude and may be inadequate. In fact we need to have a kind of direction of approximation in order to approximate more smartly.

One way of doing this is by counting the number of time a given pattern is repeated. If for example this number is increasing during many iterates, then it can be a good idea to directly replace the sequence of the pattern by an infinite (looping) pattern. To achieve this kind of analysis, we can add counters to the representation.

This chapter will develop on this extension. It will appear that this extension is easily integrated in tree schemata and comes with a wider acceptance of the notion of counters.

7.1 New Entries for the Links

When performing a decision process to decide the membership of a tree in a tree schema, we keep an environment, the partially evaluated relations, that can restrict the foregoing choices. In the same way, we can add entries to the links that are associated with other variables. There is no conceptual difference between entries associated with choice nodes outside of the current subtree of the tree schema and entries associated with some other variables outside of the choice nodes of the tree schema.

7.1.1 Tree Schemata on Labels and Variables

In order to enforce the strong determinism of tree schemata even in the presence of these new entries, we must still have full relations. To stay in the same frame, these variables must range over a finite domain which we can map to a natural number. We call Υ the set of such variables. We can now speak of tree schemata over set of labels F and set of variables Υ, members of T S(F, Υ). Such tree schemata T are augmented with a finite set var (T) ⊂ Υ. In a tree schema, each c ∈ var (T) is associated with an entry name and a link. Note that it means that a given variable cannot be associated with two different links, and thus cannot be the bond between two otherwise independent choice nodes. Variables of var (T) can now be members of the mapping of links.

Variables of tree schemata on labels and variables must still respect the rules of section 5.4.1: they must appear in the decision diagram of the link with which they are associated, and the relation of such links must be full. This last requirement means that, whatever the value of a variable, there is a vector in the relation corresponding to this variable. It means that if the variable is in var (T), then whatever the value of the variable, the tree schema is not empty. Although this allows a fast emptiness testing procedure, it may be more useful to allow some values to be associated with the empty set. For the use of the variable in the links, we need a mapping from the domain of the variable to a [n]. We can use this mapping to associate the empty tree schema with some value of the variable: the mapping is not defined on such variables. In this way, we still have a very fast emptiness testing mechanism (depending on the values of the variables), but a more flexible use of the variables.

7.1.2 Many Variables in a Link

Because the set of variables can contain any reference, it is very possible that some of them interfere with each other out of the links of a given tree schema. The situation is quite similar to the relation between parent nodes, as these nodes are indeed related by the structure of the skeleton —a relation which is added and not related to the link between them—. The problem in this case is to keep the strong determinism in the representation (and the fast emptiness testing). In the former case, we just had to care about the choices that could lead from one node to the other, and in this case require no real relation. But in general, if we don’t have any knowledge about two variables in a given link, the relation of the link must have a solution, whatever the combination of values of the variables. The same holds for more than two variables, of course. If in some cases, we know that some combinations of variables are not possible, we can add this information in the tree schema (and maybe have more precise skeletons) by replacing the two variables (or more) by a new one representing their combination, but whose domain excludes the impossible combinations.

7.1.3 Variables on Infinite Domains

The finitary condition for the variables domains is necessary to maintain some properties of the tree schemata, and in particular for an easy uniform representation of relations. But many useful properties may depend on variables ranging over an infinite domain. Suppose for example that a choice node depends on the number of loops in another tree schema. This number of loops can be as big as we want, but if this number is below a given limit, we take one choice, and another one if it is above. Although the domain of the variable is ℕ, what we need in fact is an abstraction of the variable, which is an element of the finite set {x ≤ l, x > l}.

So, by means of abstract interpretation, it is possible to depend on infinite domains while admitting variables on finite domains only. In fact, the only thing we need is a many to one function going from the domain of a variable (or the domains of many variables) to a finite domain associated with another variable. Although not necessary, a full Galois connection might be useful, when, for example, we use the set of possible values of the variables as a result after the run of a tree on the tree schema. The point is, that from the point of vue of the tree schema, as long as the variable is not closely related to the tree schema, we don’t care. As long as we have variables on finite domains, we cannot in general take their origin or computation into account.

7.2 Interaction between Counters and Skeletons

The reason why we extended relations to other variables was the possibility they offer to use the value of counters in the decision process. But it is not the only possibility of interaction between counters and tree schemata. Tree schemata themselves can modify the counters during their evaluation. We present three ways of interacting in addition to affecting the decision process. The first one can be useful in a wide variety of contexts, and it is presented in details.

7.2.1 Choice Node Counters

With counters, we could use an alternative representation for the tree with 42 g followed by a a. Instead of having indeed 42 nodes labeled by g, we could have:

[figure: g; ◯; x; r; a] with r = \xymatrix{ & & n \ar[dl]_{<42} \ar[dr]^{≥42} \\ & x \ar[dl]_{g} \ar[dr]^{a} & & x \ar[dl]_{g} \ar[dr]^{a} \\ true & & false & & true}

where n is a variable representing the number of times the loop have been completed. Not only does it save space, but it can give an idea of what is growing in a sequence ga, gga, ggga, …, g^{42}a, . . .. In the final version, r will as usual be labeled by natural numbers. The problem is how to relate n to a loop and how this will interact with operations on tree schemata.

Counter Names

What we want to count is the number of times the decision process of a given tree goes through a given loop. One way of doing so is to concentrate on a choice where we can leave the loop and count the number of times we take the choices that don’t leave the loop. The basic units to examine are described by a choice node and a choice number such that there is a path from this choice to the choice node.

Counter Identification in the Tree Schema

As with any variable that ranges over an infinite domain, we must use a function that maps the value of the variable to a finite domain. We must also note in the tree schema which choices of which choice nodes are used as counters, so that we can increase the counter each time we go through the associated choice. To do this, in addition to an entry name and a link, we associate with choice nodes a counter list: a choice node is now a tuple (◯, x, l, cl). The new element of the tuple, cl, is a partial map from the choices of the choice node to counter functions. If a given choice i is not used as a counter, cl(i) is not defined. A counter function is a kind of link between some counters and a given link of the tree schema.

Formally, a counter function is a many to one function of ℕ^{k} → [n], a link l, an entry name of range n of the link l, and a mapping f from each element of [k] to a choice node and the number of a choice of this choice node. We have cl(f(i)) is the counter function. For example, with k = 1, the function can be a discrimination: if n < 42 then 0 else 1. With k = 2, we can discriminate the sum of the counters, if both of them lead to the same loop, or compare the values of the two nodes, for example.

Because of this definition, a given counter can only be associated with one finite domain variable, the result of the counter function. It forces the link between two choice nodes that would be related through a given counter. When we want to use two different functions, we can always combine them to a function to a finer domain.

Legible Links for Counter Functions

When using counters in a tree schema, we don’t try anymore to use a best skeleton to support the tree schema. In the case of g^{42}a, it is not even a good idea. But with counters, we can have bigger problems: if we allow any link with counter, we can have tree schemata whose set of trees depend on the order of evaluation in the schemata. This is due to a fundamental difference between entries linked to choice nodes and entries linked to counter functions: every time we need to evaluate a relation, the counter function has a value, and this value may change during the evaluation of the tree schema, whereas the choice may be evaluated or not, and can take one value only.

Example: Consider the following tree schema with counters:

[figure: f; g; r; ◯; y; ◯; 0; α; x; b; c; a] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[ddr]_{0} \ar[dr]^{1} & & y \ar[dl]_{0} \ar[ddl]^{1} \\ & false \\ & true} and \{ \begin{matrix}α(0) & = & 1 \\ α(n + 1) & = & 0 \end{matrix}

This tree schema can be interpreted as any of the following tree schemata depending on whether we first explore the left child of f or its right child:

[figure: f; g; r; ◯; y; ◯; x; r; b; c; a; f; g; c; ◯; a]

If we first explore the left child, then, when we come to the right child, the choice we can make depend on whether we have been in the loop or not. But if we first explore the right child, when we evaluate the relation, necessarily, the number of loops is 0, so the value of x is 1, so the only choice is c. ♢

To avoid this kind of ambiguity, we require that the choice nodes in the link appear after the counters, and that in the evaluation, there is no opportunity of ambiguity. Formally, whatever the choice node N and choice i of N linked to l, whatever the choice node M labeled by (◯, x, l, cl), there is a p such that N.p = M and whatever q ≺ p, if N.q is not a choice node, then no extension of q can lead to N without going through M.

The second requirement just limits counters to choices of interest, which are the choices in a loop. Whatever the choice node N labeled by (◯, x, l, cl), whatever i ∈ dom(cl), there is a path p starting by i such that N.p = N.

Examples: We have an alternative to classical links with no best skeletons. We can use links based on counters instead. The following tree schema represents the set {a^{n}b^{n}c | n ∈ ℕ}.

[figure: ◯; a; c; ◯; 1; 0; 0; α; x; b; ◯; 0; 1; y; 0; r; c] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[ddr]_{0} \ar[dr]^{1} & & y \ar[dl]_{0} \ar[ddl]^{1} \\ & false \\ & true} and α(i, j) = 0 iff i > j

We also show an example of counter function with congruence:

[figure: g; α; x; ◯; y; 0,1; r; a] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[ddr]_{0} \ar[dr]^{1} & & y \ar[dl]_{0} \ar[ddl]^{1} \\ & false \\ & true} and α(i, j) = 1 iff (i + j) ≡ 41 mod 42

This tree schema represents the infinite tree (g^{42}a)^{ω}. ♢

7.2.2 Labels as Abstract Operators

In the last section, we saw that choice nodes could be used as operators on counters. In the same way, it is possible to use the different labels of F as abstract operators. In fact, each outgoing edge of the labels can be an operator. If we just have labels of arity 0 or 1, then tree schemata become abstract flowcharts, representing sets of traces.

In this case, tree schemata not only represent a set of trees, but can also be used to compute possible values of the counters. Such a use has some similarities with attribute grammars [Knu68, EF80].

7.2.3 Counters as Labels

A limitation of tree schemata, necessary to represent the set of all trees, H(F), is that the set of labels, F, must be finite. In some cases, though, we might want an infinite set of labels. An easy way of dealing with an infinite set of labels F is the use of a finite set of labels F′, each label in F′ representing a set of labels in F.

With the use of counters, we can have a more precise approximation of the set of labels represented by a given label in F′. This set of labels can be a function of the counters at the given point in the decision process.

Example: With this extension, we can represent the set of AVL trees. We use two counters, a and b, a starting with the minimum integer value, and b the maximum integer value. The set is represented by the following tree schema, with the correspondence of the labels {n, e} to the set ℕ ∪ {ε}, and the label operators, n_{0} and n_{1} (e_{0} does not change the values of the counters):

[figure: n; ◯; a] with \begin{aligned}n & → & [a, b[ \\ e & → & ε \end{aligned} and \begin{aligned}n_{0}(a, b) & = & (a, val(n)) \\ n_{1}(a, b) & = & (val(n), b) \end{aligned}

♢

7.3 Finding Cycles

By default, no counter is associated with a tree schema, except if it is expressly demanded by the user. But the user rarely knows which part of the tree schema will grow and can be best represented with counters. We present an algorithm to automatically discover such cycles during an iteration. It is then easy to approximate a tree schema by numerical analysis of the counters, in the way of [CH78] or [Mas92].

There are three problems with those new counted cycles: we must decide when and where to find those cycles, and we must fold those cycles as much as possible.

7.3.1 Deciding When to Look for a Cycle

To introduce counters in the tree schema, we look for parts of the tree schema where counters might be beneficial. Moreover, we must not spend the computation over tree schemata looking for such parts. So we propose a heuristic to decide to perform this computation.

The heuristic is based on the following remark: when we have a possibility to build a new cycle with counters, we have along a path a label which is repeated many times. So we can count the number of times each label appears in the tree schema, that is the number of distinct nodes of the tree schema with that label. If no label appears more than a given large number of times, then we know that there is no possibility for a beneficial cycle with counters.

Suppose now that there is a label which appears so many times that there might be a beneficial cycle with counters. Then we can start looking for such a cycle. If there is no such cycle, we can refine our information: when we have a possibility to build a new cycle with counters, we have along a path a label and its direct children repeated many times. So, for the label which appeared many times, we now divide the number of times the label appears between every possibility for the label of its children.

When this refining process becomes too expensive to compute, we can use some approximations (see next paragraph)

Example: Suppose F = {a, b, f} of arity 0,0,2. The number of distinct nodes labeled by a can be 1 at most. When the number of distinct nodes labeled by f is greater than k, we look for a beneficial cycle with counters. If there is no such

cycle, we count the number of [figure: f; a; f], [figure: f; b; f], [figure: f; f; a], [figure: f; f; b] and [figure: f; f; f]. If one such

label appears many times, then we can divide it furtherly. ♢

7.3.2 Finding or Building a New Cycle

When we decide that there might be a beneficial cycle with counters in the tree schema, we have a label (or sequence of labels) f that appears many times. We need only compare nodes labeled by f.

The first step is the refinement of the information on the label. This step is necessary if there is no interesting cycle, and it is useful as a first decision procedure: if there is no subdivision of the label that appears often enough, then we do not have to go further, and if there is such a subdivision, then we can restrict the nodes we consider to nodes labeled by this subdivision.

When we have our set of candidate nodes, we can compare them, in the way of chapter 3, but with a little more leniency, because we just look for a finite cycle, not an infinite one. So, when the number of pair of nodes labeled by f visited during the comparison is big enough, we allow a difference between one node labeled by f and another node. This node is the end of the cycle, the outgoing path. So, at this point, we add a choice node (or increase the existing one) and link the loop to the choice node, in the way described in the previous section.

During the comparison of the candidate nodes, we can use the information on the number of nodes labeled by a given label g. If, in the comparison, we come to such a label and the number of nodes labeled by g is too little, then we can stop the comparison.

When the size of the sequence of labels becomes too big, the computation of the number of nodes labeled by such labels might become too costly. Then, we can approximate the tree schema so that we force the apparition of a finite cycle. The advantage of this approximation compared to the approximation by an infinite cycle is that the approximation by finite cycle is more precise. Moreover, we can still have some information on the number of times we go through the cycle, whether it is increasing, to decide whether the approximation was appropriate.

7.3.3 Maximal Folding

When we have a cycle linked to a choice node counter, such as the ones that can be automatically discovered, we want to fold it as much as possible. Because of its finitery nature, we cannot use the same algorithm as for infinite cycles. We show an example where there is a folding which is not resolved by the algorithms of chapter 3:

Example:

[figure: g; g; α; x; ◯; y; 0; =; a] with α(n) = 0 iff n < 41

is the same as

[figure: g; α; x; ◯; y; 0; =; a] with α(n) = 0 iff n < 42

♢

This problem is easily solved by modifying slightly the keys associated with the cycle in the sharing algorithms. The normal key for the choice node that is linked to the counter is replaced by its father, and if we build such a node, we increase the value of the number of times the cycle is to be followed (in the counter function).

7.4 Modified Algorithms

In order to use tree schemata with counters, we need to modify the algorithms on tree schemata. Thanks to the separation between skeletons and relations, and to the locality of links, the modifications are very light. We will describe them referring to the algorithms of chapter 6. The only interactions we consider in detail in this section are the influence of the counters over the decision process (in the relations, through counter function), and the choice node counters.

7.4.1 Global Information and Forgetting

The only information we need to add to the global informations used when going through the tree schemata is the value of the counters. With this simple extension, and by taking into account the value of the counter functions each time we perform a G(l)_{(x)} or a G_{x=v}^{l}, we can keep the constructive definition of section 5.3.6 (page 99), and we have the new definition of the set represented by a tree schema with counters. The initial global information extends to counter values, as the current external values, if any, and for choice node counters, the initial value is 0. Choice node counters are incremented by one each time we go through the appropriate child of the appropriate choice node.

When we want to compute local informations, we need to forget the global information, after taking it into account in the links. It is the case for example at the end of the computation of the projection of tree schemata. It is also a necessary step before computing the inclusion or the intersection of the relations, so that the counter functions of the two tree schemata be in phase.

When we want to get rid of the global information (forget it), we just have to change the counter functions according to the current value of the choice node counters. Because each time we start a new evaluation the value of choice node counters is 0, we just replace every counter function α depending on the choice node counter n by α′(n) = α(n + k), where k is the value of the counter in the global information.

7.4.2 Inclusion and Loops

Tree schemata inclusion testing consists in skeletons and finite parts of the relation inclusion testing, then infinite relations testing. With counted loops, we can have very big finite loops, and it would be too costly to unfold entirely those loops. So, the inclusion will go as for the simple tree schemata, but we will also compute the inclusion of finite loops with the infinite relations. To isolate the finite loops, we do as for infinite relations, we stop the inclusion testing of the skeletons as soon as we loop. The scope of the choice node counter is the root of its cycle.

The idea is that instead of following the loops, we jump directly to the values of the counters that change the values of the counter functions. We keep the pairs of values in memory, and we iterate until no other change in the value of the counter functions is possible by increasing the counters, or the only possible pairs of value have already been encountered.

Each time we make a jump with a counter, we compute the new counter functions, as described above, and we compare the choice nodes that are linked to these counter functions with the appropriate node of the other tree schema.

Example: We compare the following tree schemata:

[figure: g; α; x; ◯; y; 0; =; a; g] with α(n) = 0 iff n < 41

[figure: g; β; x; ◯; y; 0,1; =; a] with β(i, j) = 1 iff (i + j) ≡ 41 mod 42

On the first comparison of the choice nodes, n = 0, i = 0, j = 0, so α = 0 and β = 0, so we just compare the left child. This comparison holds true. Then we jump to n = 41, i = 41. This time, we just go to the right child, and in the loop, we have i = 41, j = 1, so we compare again [figure: g] with the left child of the choice node of the second tree schema. This time again, the comparison holds true. Finally, we jump to i = 82, and we compare the right child. This time, we can conclude that the first tree schema is not included in the second one. ♢

Concerning the inclusion testing of the infinite behavior, it can be performed when we have tested the finite loops. It is not modified by the counters.

7.4.3 Intersection and Counter Functions Merging

The adaptation of the intersection algorithm on tree schemata with counters shows all the problems that are raised by any other fundamental algorithms on tree schemata (union, projection...). We show how to solve these problems for intersection, but the solutions are the same for the other algorithms.

To compute the intersection of two tree schemata with counters, we need to compute the new relations, between new counter functions, if any. Indeed, before computing the intersection of the relations, we need to merge the counter functions.

Adaptation to the New Skeleton

The first step is the adaptation of the counters and counter functions to the new skeleton (the intersection of the skeletons of the tree schemata). In this new skeleton, cycles may be unfolded, either by root unfolding or cycle growth. In case of root unfolding of a counted cycle, we count the number k of such unfoldings, and we replace α depending on the counter n by α′(n) = α(n + k) (as for global information forgetting). In case of cycle growth, we count the number of cycle growth and divide the counter between every inflated choice node. If the new counters are named n_{0}, …, n_{i}, α′(n_{0}, …, n_{i}) = α(n_{0} + … + n_{i}).

Counters Comparison

The second step consists in comparing the counters of the two tree schemata. As for regular relation entries, we need to recognize when two counters count the same loop. We can get rid of one counter name if and only if two choice nodes are in the same loop (there is a path from one to the other and back to the first one). Let N and M be two such choice nodes. We call i_{0}, …, i_{k} the counters of the choices of N that lead to M, and j_{0}, …, j_{n} the counters of the choices of M that lead to N. We have ∑_{a=0}^{k} i_{a} = ∑_{a=0}^{n} j_{a}. This is a necessary step to compare the counter functions.

Counter Functions Comparison

The third step is the comparison of the counter functions. Only counter functions which share some counter names need to be merged. In this case, we compute the new counter function as the cartesian product of the original ones. If α is the counter function of the first tree schema, and β the counter function of the second tree schema. We call p the common counters of α and β, n the other counters of α and m the other counters of β. The merging of α and β, γ is defined as γ(n, p, m) = <α(n, p), β(p, m)>. The extension of the relations to these new values is obvious, we just consider in the decision diagram the appropriate projection of the value: if R is the relation of the first schema, the new relation is defined as R′(<a, b>) = R(a).

Verifying the New Tree Schema

Then we can compute the intersection of the relations. At this stage, we have a tree schema representing the intersection, but we need to perform some verifications to transform the tree schema into a valid tree schema. This is performed for links (as was described in chapter 6), as well as for counter functions or external counters.

Concerning external counters, we just need to verify that the relation linked to the counter is full. If it is not the case, then we must propagate the information to the least choice node N such that every choice node in the link is a strict subtree of N. If there is no such choice node, it means that for the values on which the relation is false, the tree schema is empty. So we remove these values from the mapping function. If there is a least such choice node N, then we add N to the link, forbidding the choice of N leading to the original link for every value on which the relation is false.

Concerning counter functions, we can change the way the counters are computed. First, we simplify the counter functions by going through the new tree schema with global information in the way described in the previous subsection. Such a traversal might suppress some parts of the skeleton. This suppressions must be propagated, as for relations leading to an empty choice. If, after the counter functions simplification we still have some values of the counter functions on which the relation is false, then we add every choice node where this counters are computed in the relation, forbidding those values. If the entry of the counter function does not appear in the decision diagram, then we can get rid of the counter function (and all the associated counters).

7.5 Conclusion

The extensions presented in this chapter showed another interest of the separation between the skeleton part and the relational part of the set of trees. Thanks to this separation, the addition of external counters was easy. We also added choice node counters. Such counters can be automatically created during the computation of tree schemata. The use of the counters in the tree schemata increases the complexity of the algorithms on tree schemata. They are intended as a way to perform smart approximations by numerical analysis of the counters. They offer another tradeoff opportunity between precision and complexity.

148 CHAPTER 7. TREE SCHEMATA WITH COUNTERS

Tree Based Abstract Interpretations

In order to illustrate the possible usefulness of tree schemata, we briefly describe different examples of abstract interpretations using sets of trees in their domains. We compare the existing solutions to tree schemata and show the advantages of our solution.

8.1 Model of Logic Programs

Abstract interpretation have been widely applied to logic programs. A general presentation of the application of abstract interpretation of logic programs and a survey of the different applications can be found in [CC92a].

The analysis we study here is the computation of the Herbrand model of logic programs.

8.1.1 Syntax and Collecting Semantics

Let us first define the syntax of logic programs. We suppose that we have two finite ranked sets of labels, F and G, and a set of variables, V. A term is a tree labeled by F ∪ V. An atom is a tree labeled by F ∪ G ∪ V, where the only subtree

labeled by G is the root. We write an atom [figure: p; t_{0}; t_{n−1}], where p ∈ G, and each t_{i} is a

term. A clause is a couple (head, body), such that the head is an atom and the body is a finite sequence of atoms. We write a ← a_{0} … a_{n−1}. A logic program is a finite sequence of clauses.

A ground instance of a term t is a tree u such that there is a substitution κ : V → H(F) and u is the tree substitution of each variable X by κ(X) in t. A ground instance of a clause a ← a_{0} … a_{n−1} is a clause b ← b_{0} … b_{n−1} such that there is a substitution κ and b is the tree substitution defined by κ on a and each b_{i} is the tree substitution defined by the same κ on a_{i}. A logic program P defines a set of ground instances of its clauses. We denote this set ground(P).

The standard semantics we chose for logic programs is a small step operational semantics based on SLD resolution. The collecting semantics that we choose to study is the backward semantics based on the T_{P} operator of [vEK76]:

T_{P} (E) = {a | ∃a ← a_{0} … a_{n−1} ∈ ground(P) such that each a_{i} ∈ E}

A model of the program P is a fixpoint of T_{P}. Generally, one uses the least model of the program P. But the greatest model may be considered too: it is used for example to manipulate infinite trees, as in [Col82, Col84], or to specify infinite state systems in [CP98b].

8.1.2 Approximation of the Model

The semantic domain of the collecting semantics is P^{♭} = ℘(H(F ∪ G)). The abstract domain we use is the set P^{♯} = T S^{∴}(F ∪G). The approximation ordering is the inclusion ordering.

The T_{P} operator of a logic program P can be defined using a meta expression in the way of section 5.4.2. If P contains only one clause a ← a_{1} … a_{n}, then T_{P} (E) = { ; |{a : a_{1} ∈ X , … a_{n} ∈ X }| ; } ρ where ρ(X) = E. If P contains more than one clause, then the T_{P} operator corresponds to the union of the meta expressions associated with every clause. Thus, if E is represented by a tree schema, we can compute T_{P} (E) and represent it with a tree schema.

Example: Let P be the following logic program:

                        p(a,b) .
                        p(b,a) .
                        q(X,Y) ← p(X,Y)

The meta expression representing T_{P} is { [figure: p; a; b]}∪{ [figure: p; b; a]}∪{ [figure: q; X; Y] : [figure: p; X; Y] ∈ X }.

The iteration sequence computing the least fixpoint of the T_{P} operator will be:

X_{0} = ◯

X_{1} = [figure: p; ◯; x; r; y; ◯; a; b] with r = \xymatrix{ & x \ar[dl]_{0} \ar[dr]^{1} \\ y \ar[ddr]_{0} \ar@{-->}[dr]^{1} &  & y \ar[dl]_{0} \ar[ddl]^{1} \\  & true \\  & false}

X_{2} = [figure: ◯; p; q; ◯; x; r; y; ◯; a; b]

X_{3} = X_{2}

♢

As long as the iteration sequence is finite, the fixpoint is represented by a tree schema. When the iteration sequence is infinite, though, it is possible that the fixpoint cannot be represented by a tree schema. In this case, anyway, we need some way of acceleration of the iteration sequence, and the usual way in abstract interpretation is the use of an approximation through widening. We can use a widening using the choice node counters of section 7 which will fold the finite cycles as soon as the counters are above a given constant. If we stop the label numbering at a given depth, then the total size of the tree schema is bounded. With the bound on the counters, it gives a finite set of tree schemata, thus ensuring termination. Note also that if the meta expression have the limited form of section 5.4.2, we can compute directly the fixpoint without performing the iteration sequence.

Example: P is the following program:

                        p(f(X,X)) ← p(X)
                             p(a) .

The beginning of the iteration sequence for the least fixpoint is:

X_{0} = ◯
X_{1} = \xymatrix{p \ar[d] \\ a}

X_{2} = [figure: p; ◯; f; a]

X_{3} = [figure: p; ◯; f; ◯; x; =; y; ◯; f; a]

X_{4} = [figure: p; ◯; f; ◯; x; =; y; ◯; f; f; ◯; x; =; y; ◯; y; =; z; ◯; z; =; t; ◯; f; a]

It is obvious that a tree schema representing a fixpoint of T_{p} would require an infinite number of entry names. We have the following possible approximation for X_{4}:

X_{4}^{♯} = [figure: p; ◯; a; f]

T_{P} (X_{4}^{♯}) = [figure: p; ◯; a; f; ◯; x; =; y; ◯; f; a; f]

We have T_{P} (X_{4}^{♯}) is included in X_{4}^{♯}, so X_{4}^{♯} is a post fixpoint of T_{P}. Indeed, we can take T_{P} (X_{4}^{♯}), which is also a post fixpoint and is a more precise approximation of the least fixpoint of T_{P}. ♢

8.1.3 Comparison with Other Approaches

Earlier works concerning the approximation of the least Herbrand model of logic programs were known under the name of type inference of logic programs (see for example [Mis84, MR85, YS87]). These algorithms were not complete and the results were very approximate due to the use of the cartesian closure approximation.

In [HJ90], Nevin Heintze and Joxan Jaffar proposed an improvement on type inference using set based analysis: their analysis was more precise and the inferred approximation was recursive. But due to cartesian approximation and the rigid framework they used, they could not get the exact result on the first example. Moreover, their representation uses many variable names, and in particular introduces an exponential number of variable names during the computation of the intersection. Thus, the representation was very inefficient. In fact, their representation, and the use of cartesian approximation, could be as expressive as non deterministic tree automata. It means that by tuning carefully the analysis (for example using abstract interpretation techniques, as suggested in [CC95]), one could get the exact meaning of the first example with the same approximation.

Abstract interpretation have been used to compute an approximation of the least Herbrand model (see for example [HK87, BJ88, FS91]). These approaches have been limited by the available abstract domains. Thus their answer on the second example could not be as precise as with tree schemata.

8.2 Sets of Traces

The operational semantics of programs associates with a given program a set of states and a transition relation over this set of states. For a given set of inputs, the interpretation is a trace, starting from an initial state defined by the inputs and following the relation from state to state until no other transition is possible (or until we loop on a final state, if we require that the relation is total). Thus, an alternative representation for the operational semantics of the program is a set of traces. The exact shape of the traces depend on the particular semantics, but we will see that they can always be represented by (possibly infinite) trees. So, they are a good field of application for abstract interpretation based on trees.

Abstract interpretation of the execution traces was one of the initial applications of abstract interpretation. David Schmidt gave a recent presentation on the abstraction of a given trace by an abstract computation tree in [Sch98b]. Many examples in this section are taken from his article.

8.2.1 Flowchart Semantics

Presentation

Flowcharts are one of the oldest representations of the semantics of imperative languages. A flowchart is a graph labeled by program instructions. Each node in the graph corresponds to a program point. There are two special nodes named entry and exit. The nodes have one outgoing edge, except for the exit node which has none and test nodes which have two outgoing nodes, one labeled by true, and the other one labeled by false.

A state of the program is a couple <pp, ρ>, where pp is a program point and ρ is an environment binding the different variables of the program to their current values. The flowchart is a representation of the transition relation of the program: each states <pp, ρ> → <pp′, ρ′ > if there is an edge from pp to pp′ in the flowchart, and if pp is a test point, then the edge is labeled by the evaluation of the test in the environment ρ. The new environment ρ′ is computed by the instruction in the node of pp.

Flowchart Semantics as Sets of Trees

It is obvious from the semantics that any state can be followed by at most one state. It means that the execution trace of a program based on a flowchart semantics is a (possibly infinite) word of states. Thus, the semantics of the program can be equivalently represented by a set of words, or trees with labels of arity at most one. This representation can be understood as a first computation on the flowchart that loses no information, and that is convenient to express properties of the program, such as dataflow properties or path properties.

The problem is that the set of states of a program is generally infinite, and the set of traces is very difficult to represent in an explicit way (as opposed to the flowchart, which is an implicit representation). One way of representing sets of trees labeled by an infinite set of labels F with tree schemata is the use of a finite set of labels F^{♯}, each new label abstracting elements of ℘(F), such that F^{♯} represents a partition of F.

In this way it is possible to have a tree schema representing a supset of the set of traces. When the properties collected from the representation of the standard semantics are dataflow properties, this approach corresponds to direct abstract interpretation with finite abstract domain.

Example: Consider the following (labeled) imperative program and its flowchart semantics:

P_{start} : P(x) :
P_{?} :  if x is even then
P_{div} :  x ← ← ← x div 2
P_{+} :  x ← ← ← x + 1
P_{rec} :  P(x)
P_{end} :

[figure: entry; x is even?; false; true; exit; x ← ← ← x div 2; x ← ← ← x + 1]

We show a possible trace with entry x = 4 and a supset of the set of traces represented by a tree schema using the abstract domain {o, e}, where o represents the set of odd natural numbers and e the set of even natural number.

\xymatrix{4, P_{?} \ar[d] &  &  & ◯ \ar[dl] \ar[dr] \\ 4, P_{div} \ar[d] &  & e, P_{?} \ar[d] &  & o, P_{?} \ar[d] \\ 2, P_{+} \ar[d] &  & e, P_{div} \ar[d] &  & o, P_{end} \\ 3, P_{?} \ar[d] &  & ◯ \ar[dl] \ar[dr] \\ 3, P_{end} & o, P_{+} \ar[uuur] &  & e, P_{+} \ar[uuur]}

♢

In [Sch98b], a given trace is approximated by a tree, which represents a set of traces. The advantage of our point of vue is that there is no need for a complex safety relation: the tree schema is a safe approximation if and only if it represents a supset of the set of traces. The use of choice nodes allows the possibility of specifying the infinite behavior of the program in the tree schema: if the program were known to terminate, then we can add a relation on the second choice node that excludes infinite loops.

Although the approximation by tree schemata allows better flexibility than the classical behavior tree, the traces of flowchart semantics are mere words. It means that the full complexity of tree schemata is not exploited and that we could use a more efficient more specialized representation. So we present also a semantics where the traces themselves are trees.

8.2.2 Big-Step Semantics

Big-step semantics represent the transition relation of programs in terms of inference rule schemes. Big-step semantics are used to describe the semantics of higher order languages, or imperative languages with recursive interprocedural calls. As above, a state of the program is a couple <pp, ρ> of program points and environments. The inference rule schemes represent possible transitions and compute return values. An inference rule is composed of an inferred sequent s and a finite sequence of required sequents s_{1}, …, s_{n}. We write \frac{s_{1},...,s_{n}}{s}. A sequent is a couple state-value. The transition relation derived from the set of inference rule schemes is: a state S is derived to S′ if there is a rule \frac{s_{1},...,s_{n}}{S,v} and there is an i such that s_{i} = S′, v′, the transitions before i return a value compatible with the s_{j}, and S′ returns v′ and then the transition after i return a value compatible with the s_{j}. Then the value computed by S is v. The execution trace of a program with initial value is the tree corresponding to all the necessary steps used to compute the return value.

We can still approximate the set of traces by a tree schema representing a supset of the set of traces. Again, we use an approximation of the set of states.

Example: We present a small program written in a small functional language containing conditional, recursive definitions and primitive operators on expressions. The primitive operators will be denoted op, the expressions e and the identifiers x, y, f, g. Environments map identifiers to values, which can be closures. Program points are identified to subexpressions. The inference rules are:

\frac{e, ρ, v}{op(e), ρ, op(v)}  \frac{e_{1}, ρ, true e_{2}, ρ, v}{if e_{1}then e_{2}else e_{3}, ρ, v} \frac{e_{1}, ρ, false e_{3}, ρ, v}{if e_{1}then e_{2}else e_{3}, ρ, v}
recf(x).e, ρ, <ρ, f, x, e> x, ρ, ρ(x)

\frac{e_{1}, ρ, <ρ′, f′, x′, e′ > e_{2}, ρ, v′ e′, ρ′ ∪ \{f′ → <ρ′, f′, x′, e′ > , x′ →v′\} , v}{e_{1}e_{2}, ρ, v}

Here is the small program we analyze, with the labels corresponding to its subexpressions:

            p = recf(x). if even(x) then 1 else f(x div2)
           p_{if} = if p_{?} then 1 else p_{appl} and p_{appl} = f(p_{div})

The following tree is the trace of p5 (i.e. p applied to 5):

\xymatrix{ & p5, ∅, 1 \ar@{-->}[dl] \ar[d] \ar@{-->}[dr] \\ p, ∅, cl & 5, ∅, 5 & p_{if}, ρ_{5}, 1 \ar@{-->}[dl] \ar@{-->}[dr] \\  & p_{?}, ρ_{5}, false \ar[d] &  & p_{appl}, ρ_{5}, 2 \ar@{-->}[dl] \ar[d] \ar@{-->}[drr] \\  & x, ρ_{5}, 5 & f, ρ_{5}, cl & p_{div}, ρ_{5}, 2 \ar[d] &  & p_{if}, ρ_{2}, 1 \ar@{-->}[dl] \ar@{-->}[dr] \\  &  &  & x, ρ_{5}, 5 & p_{?}, ρ_{2}, true \ar[d] &  & 1, ρ_{2}, 1 \\  &  &  &  & x, ρ_{2}, 2}

where \begin{aligned}cl & = & <∅, f, x, p_{if} > \\ ρ_{i} & = & \{f →cl, x→i\} \end{aligned}

The abstraction of the set of traces of p applied to an integer is:

[figure: ◯; po, ∅, o; pe, ∅, o; p, ∅, cl; o, ∅, o; p_{if}, ρ_{o}, o; e, ∅, e; p_{if}, ρ_{e}, o; p_{?}, ρ_{o}, false; p_{appl}, ρ_{o}, o; p_{?}, ρ_{e}, true; o, ρ_{e}, o; f, ρ_{o}, cl; ◯; i; _{=_{f}}; j; ◯; 0; 1; x, ρ_{e}, e; p_{div}, ρ_{o}, o; p_{div}, ρ_{o}, e; x, ρ_{o}, o]

Where the relation =_{f} allows only finite loops:

=_{f} = \xymatrix{ & i \ar[dl]_{0} \ar[dr]^{1} \\ j \ar[ur]_{0} \ar[dr]^{1} & & j \ar[dl]_{0} \ar[dr]^{1} \\ & false & & true}

♢

What is Gained with Tree Schemata

The approximation of the set of traces by tree schemata present many advantages, compared with the behavior tree: there is a clear distinction between necessary derivations and non-deterministic choices represented by ◯. This distinction allows better property extraction. The expressive power is better with tree schemata, even compared with the so-called set-based abstraction presented in [Sch98b]. The expressiveness is increased concerning the finite behavior when dealing with trees and not only words. Concerning the infinite behavior, the expressiveness is increased, even compared to the use of positive and negative inference rules [IS98] in the behavior tree.

8.2.3 Parallel Programs: Fairness

Parallel programs semantics can be expressed using any of the previous semantics, with the additional complexity that for a given program and a given initial state, we can derive many traces. Each trace corresponds to a possible order of execution of the different parallel parts of the program. Such a semantics is called the interleaving semantics [SNW94, vGG89] of the program.

We show a very simple example of parallel program and its interleaving semantics to illustrate the expressive power of tree schemata with ω-deterministic relations.

Example: The following program sets the variable x to true, then executes in parallel the loop while x do skip and sets the variable x to false.

               X = true; [|while X do skip∥X = false|]

The positions in the program are:

A_{1}[|A_{2}∥A_{3}|]

In order to take into account the possibility that a parallel part of the program can be terminated and the other parallel parts are stalled, we introduce the positions F_{2} and F_{3} and we allow F_{2} to be followed by F_{2}. In this way the traces of the program are necessarily infinite. The program is said to terminate if after some point, we just have the states F_{2} and F_{3}.

Under these assumptions, the set of traces of the program is:

T = \xymatrix{ & & A_{1} \ar[d] \\ & & ◯ \ar[dl] \ar[dr] \\ & A_{3} \ar[d] & & A_{2} \ar[d] \\ & ◯ \ar[dl] \ar[dr] & & ◯ \ar[ull] \ar[u] \\ F_{3} \ar[ur] & & A_{2} \ar[d] \\ & & ◯ \ar[dl] \ar[dr] \\ & F_{3} \ar[ur] & & F_{2} \ar[ul]}

We can express the termination property with a tree schema. The following tree schema contains all terminating traces of programs with positions A_{1}, A_{2}, A_{3}, F_{2} and F_{3}:

F = [figure: ◯; Term; A_{2}; F_{2}; A_{1}; F_{3}; A_{3}] where Term = [figure: x; 1,3; 0,2,4; true]

So, to prove termination, we have to prove T ⊂ F. We see that here, with no additional assumption, it is not the case^{1}. We will show that under a weak fairness assumption, the program does always terminate. The proof is very easy. The following tree schema expresses the weak fairness property:

C = [figure: A_{1}; ◯; Fair; A_{2}; F_{2}; F_{3}; A_{3}] where Fair = [figure: x; 0,1; 2,3; x; 0,1; 2,3; x; 0,1; 2,3; true]

Then the semantics of the program under the fairness assumption is:

C ∩ T = [figure: A_{1}; ◯; A_{3}; A_{2}; ◯; _{Fin_{1}}; ◯; _{Fin_{2}}; F_{3}; A_{2}; ◯; F_{3}; F_{2}] where [figure: Fin_{1}; =; x; 1; 0; true; Fin_{2}; =; x; 0; 1; true]

And we have C ∩ T ⊂ F. ♢

This example shows how easy it is to manipulate non-trivial infinite behaviors with tree schemata.

8.3 Other Applications

Many other abstract interpretations or analyzes may benefit from the use of tree schemata. We present some of them very briefly.

8.3.1 Model Checking

Model checking [CES83] is a technique used to verify properties over systems, such as hardware or software systems. When the system is finite, model checking uses compact symbolic representations, such as BDDs. When the system is too big or infinite, model checking may benefit from abstract interpretation to reduce the size of the systems to be explored. This seems to be a growing direction of investigation in model checking (see for example [Bru93, CGL94, Dam96, Lev97, Sch98a]).

1In general, T is a supset of the set of traces, so we cannot conclude that the program does not terminate. In order to do this, we can use subsets of the set of traces.

Properties of systems, especially temporal properties, tend to be expressed over sets of trees, using logics such as CTL^{∗} [Tho88] or the modal μ-calculus. Models of systems using such tree representation would greatly benefit from the symbolic representation using tree schemata. Because of their ability to express complex infinite behavior, such as fairness, they would be well suited for these logics. When analyzing programs, one could use the set of traces as defined in the previous section, instead of the computation tree. In [ES88], it is noted that the representation of the model as a set of traces instead of a set of states and a relation is more general. In the more recent [KMM^{+}97], the adequacy of the use of sets of trees to model parameterized systems is demonstrated.

8.3.2 Closure Analysis

In the set of states corresponding to a higher order functional program, we have closures representing higher order functions. Abstracting the set of states so that we can represent these closures during an analysis is a difficult problem. In a unified presentation of the problem, [JW95] presented a representation based on flow graphs. Their presentation defines a hierarchy of instantiations of their framework of growing accuracy and complexity (the simplest one, 0CFA is equivalent to set-based analysis). In this framework, the tree schemata can be used as an alternative representation for the flow graph, as in the set of traces case.

Conclusion

9.1 Main Results

The main results of this thesis are a new representation for sets of trees and a new representation for infinite relations.

The new representation for infinite relations is based on decision diagrams and is an extension of BDDs. It defines a new class of infinite relations, ωdeterministic relations, which can be used as efficient approximations of regular relations. Their expressiveness allows the representation of safety, liveness and fairness properties (and many more).

The new representation for sets of trees is based on the decomposition of this sets between a tree-shaped structural information and a relational information. The new class of sets of trees it defines encompasses infinite tree automata and tree automata with equality constraints between brothers. The representation enforces maximal sharing of prefixes and the sharing of isomorphic sets of subtrees.

It allows the emptiness decision in constant time. Inclusion testing is decidable. If the relations are closed under intersection, the intersection of two tree schemata is a tree schema. If the relations are moreover closed under union, then the union of two tree schemata is also a tree schema. If we have approximation strategies over relations, they carry over to tree schemata to compute approximations of intersection or union for example. With the same restriction, we can compute projections and tree constructions on tree schemata.

Because of the decomposition at the heart of tree schemata, useful extensions such as loop counting can easily be added. Thanks to their expressive power and to the way they can handle approximations, tree schemata seem very well suited for many tree based abstract interpretations.

9.2 Future Work

9.2.1 Practical Usefulness

The main goal of the tree schemata is to allow practical and precise abstract interpretations based on sets of trees. To this effect, we presented many algorithms. Some of them were tested on prototype implementations in Java, but they depend on many parameters that need to be tested with many experiments in realistic conditions. Among this parameters, we can choose the representation of relations, the best ways of approximating iteration sequences and the representation of choice nodes. Moreover, the algorithms presented in the thesis give a flavor of the way we can manage tree schemata, but some of them can certainly be improved.

9.2.2 Negation

In this thesis, we did not mention negation, although this operation might be very useful, in particular to be used in model checking. ω-regular relations are closed by negation, but ω-deterministic relations are not. It is possible to approximate the negation of ω-deterministic relations, but it means that we need to carry over a supset and a subset approximation.

Negation is a regular process, that is, if its input is regular, the process will compute only a finite number of states. So we believe that tree schemata based on ω-regular relations can be closed by negation. Again, with less expressive (and more practical) relations, we will need to carry over two approximations. It could be feasible, and it would be interesting to have an idea of the complexity of such an operation. It is possible that the addition of a specific negation node reduces the complexity, but we need to be very careful that such a node does not tamper too much with the sharing.

9.2.3 Extensions

In chapter 7, we presented some quite general extensions that increased considerably the expressive power of tree schemata. These extension need to be furtherly explored before we can state their usefulness.

Appendix A List of Symbols and Conventions

A.1 Widely Used Mathematical Symbols

ℕ

the set of natural numbers

℘(E)

the set of subsets of E

|E|

the cardinal of the set E

⇔  if and only if
⇒  implies

dom(f)

the domain of the partial function f

im(f)

the image of the function f

f : E →F

the domain of the function f is E and its codomain is in F

⨂_{i∈I} E_{i}

the cartesian product of the family of sets (E_{i})_{i∈I}

⋃_{i∈I} E_{i}

the union of the family of sets (E_{i})_{i∈I}

⋂_{i∈I} E_{i}

the intersection of the family of sets (E_{i})_{i∈I}

E\F

the set of elements of E without the elements of F

A.2 Conventions for Other Mathematical Sym-

bols

lub_{≤}(E)

the least upper bound of E for the partial ordering ≤

glb_{≤}(E)

the greatest lower bound of E for the partial ordering ≤

[n]

the set of natural numbers smaller than n

[n, m[

the set of natural numbers between n and m, m excluded

|u|

the size of the word u

ε the empty word ⨀_{i∈I}^{<_{I}} u_{i} the concatenation of the finite words u_{i} in the total ordering defined by <_{I} (page 6)

A^{∗}

the set of finite words over A

A^{ω}

the set of infinite words over A

A^{∞}

the set of finite and infinite words over A

≺

the prefix relation on words

≺_{A}^{∗}

the alphabetic ordering on A^{∗}

\overrightarrow{L} the closure in the set of infinite words of the set of finite words L, with respect to the prefix ordering (page 7)

L^{ω}(A) the set of infinite words recognized by the Büchi automaton A

L^{∗}(A)

the set of finite words recognized by the automaton A

pos(t)

the domain of the tree t

Ar_{L}

the arity function associated with a set of labels L

H(L)

the set of trees labeled by L and respecting its arity

t_{[p]}

the subtree of t in p, where p is a path of t

s ⋖ t

s is a subtree of t

t[u\v]

substitution of the subtree u of t by v

Subtrees(t)

the set of subtrees of t

G^{N}

the set of nodes of the graph G

G^{E}

the set of edges of the graph G

∅^{G}

the empty graph

<>

the element of ⨂_{i∈∅}

Support(R)

the support set of the relation R (page 13)

x_{(j)} the projection of x (an element or a set) according to j (an index, a set of indexes or an index name)

R_{:J=e}

the projection of R according to e (page 14)

A.3 Sets and Operators Defined in the Thesis

≡_{t} The equivalence between two graph nodes, when they represent the same tree.

A.3.1 Relations

R = R_{1} ⊼ R_{2} the decomposition of the relation R in two independent relations (page 14)

AllProj(R) the set of all possible projections of the relation R according to any set of values (page 14)

e_{i↔j}

the vector e with its i^{th} and its j^{th} components exchanged

Rel The set of all possible relations with entry names and sets of indexes subset of ℕ^{∗} (page 44)

word (e)

the word equivalent to the vector e

<u>

the vector equivalent to the word u

name_{R}(e)

the name associated with the entry e of the relation R

ename(R)

the set of entry names of the relation R

R_{1} ≃ R_{2}

the relations R_{1} and R_{2} are isomorphic (page 46)

Ω (R) the recursive relation defined by the open relation R. If R is not open, then the empty relation (page 48)

□(R, J, w) is the property stating whether the relation R projected according to w on the set of indexes J is “square”. That is, if R is a relation on ⨂_{i∈I} E_{i}, □(R, J, w) is true if R_{:J=w} = ⨂_{i∈I\J} E_{i}.

nameiter(R, k) is the property stating whether k is a period of the entry names

of R. It is true if ∀i ∈ ℕ, name_{R}(i + k) = name_{R}(i).

iter(R) the family of recursive relations associated with the regular relation R (page 48)

infbehave_{R}(p) the set of indexes in the family of recursive relations (R_{i})_{i∈C} associated with the regular relation R such that whatever i in this set of indexes, whatever <f > ∈ R_{i}, <pf > ∈ R (page 59)

R_{ω}(t) the ω-deterministic relation represented by the decision diagram t (page 62)

A.3.2 Tree Schemata

<_{F}

ordering on the set of labels F

◯

the choice node

H_{◯}(F)

the set of trees on F ⋃{◯}

Ens(S)

the set of trees represented by a skeleton S (page 89)

Sk(F)

the set of skeletons on F

Sk^{∴}(F) the set of sets of trees labeled by F that can be represented by a skeleton

1_{F}

the skeleton representing the set H(F) (page 92)

cps(S) the set of paths of S labeled by a choice choice(p) p can be a path or a choice node. In both cases, it is the number of possible choices at this point

CS(S)

the choice space of a skeleton S (page 93)

⟨S⟩ the function defined by the skeleton S on its choice space (page 93)

skel (T)

the skeleton of the tree schema T

link (C)

the link associated with the choice node C

entry (C)

the entry associated with the choice node C

rel (T)

the relation on the tree schema T (page 99)

Set(T)

the set of trees represented by the tree schema T

T_{∅} the function that associates with every link of a tree schema T the empty list (page 99)

G(l)_{(x)} the set of possible choices for l on entry name x, according to the global information G (page 99)

G_{x=v}^{l} the new global information after taking the choice v for the entry x of the link l while the global information is G (page 100)

T S(F)

the set of tree schemata on F

T S^{∴}(F) the set of sets of trees labeled by F that can be represented by a tree schema

t_{x}^{−1} (T) the projection of the tree schema T according to the node x of the tree t (page 130)

var (T) the set of variables of the tree schema T

Appendix B

Algorithms

B.1 Notations

Algorithms are always presented in a pseudo language for more generality. This pseudo language is based on imperative languages. It uses mathematical notations and English sentences, but also some key words and an indentation to outline the control flow of the algorithms.

Each algorithm description starts with the name of the algorithm with a list of arguments in brackets separated by a coma. The description of the algorithm is then indented to show the extend of this description. This description consists in a sequence of expressions to be executed in order.

← is used to affect values to variables. The left hand side of the arrow is the variable to be affected, and the right hand side is the new value for the variable.

= is used for comparison in tests. Its value, then, is either true or false. It can be used as a statement, to remind the reader of some equalities.

∀ followed by a membership expression (of the form x ∈ E) and a do. It loops on the following expression(s) for each elements of E. If there is more than one expression, they are indented to show the extend of the loop.

do is used to start a sequence of expressions in a loop (such as ∀, for, while). It can start a loop by itself. The sequence of expressions in the loop can then be followed by a while followed by a test. The while is on the same indentation as the do. The loop is performed until the test is false.

else see if.

for followed by an affectation, to, a value, then do and one or more expressions. The affectation is on a variable x containing an integer. It loops on the expression, increasing the value of x by one at the end of each loop until it is greater than the value following to. If there is more than one expression, they are indented to show the extend of the loop.

if followed by a test which is delimited by a then, followed by one or more expressions to be executed if the test is true, and an optional else followed by one or more expressions to be executed if the test is false. The range of then or else is expressed by an indentation. The else of a given if is always on the same indentation as the if.

return with an argument, is the end of the current execution of the algorithm. The argument, if any, is the value computed by the algorithm. Note, that any loop or any test in the current algorithm is ended.

then see if.
to  see for.

while followed by a test which is delimited by a do. If the test is true, it loops on the following expression(s) while the test is true. The expressions that are in this loop are indented. An alternative syntax describes the same loop with at least one execution of the expressions. See do.

B.2 List of Algorithms

addKeys(dt) adds the keys corresponding to the recursive relation represented by dt in the dictionary. (page 71)

bestOpen(R) returns the decision tree of the greatest open relation representing the recursive relation R. (page 66)

compareRel(t_{1}, t_{2}, S, dt) is called with an initial function S empty. Then returns true if and only if t_{1} and t_{2}, subtrees of dt, represent the same subrelation of Ω (dt). (page 69)

dt_{ω}(R) returns the decision tree representing the ω-deterministic relation R. (semi-algorithm)

dt_{op}(R) returns a decision tree representing R, where R is an open relation. This decision tree is used to represent Ω (R) if R is the greatest open relation representing Ω (R). In the final representation, we use dt_{reg}(R) to represent the open relation. (semi-algorithm) dt_{reg}(R) returns the decision tree representing the regular relation R (before

elimination of redundant nodes). (semi-algorithm)

dt_{set}(R) returns the decision tree representing R, where R is a finite union of recursive relations. (semi-algorithm)

eqTree(M, N) returns true if and only if the two nodes M and N of a graph represent the same tree (page 19)

inclusion(T, U) returns true if Set(T) ⊂ Set(U) (page 116)

inclusionChildren(T, U, Γ_{0}, A) computes the inclusion of the tree schemata T and U labeled by the same label in F.

instGlobRels(Γ, l, x, v, i) instantiates the global informations in Γ with the entry x of the link l taking the value v. The link l is a link of the i^{th} tree schema.

inclusionRel(dt_{1}, dt_{2}) returns true if every vector in the ω-deterministic relation represented by decision tree dt_{1} is in the ω-deterministic relation represented by the decision tree dt_{2}. (page 75)

inclusionSkel(T, U) returns true if Ens(T) ⊂ Ens(U) (page 115)

instantiate(dt, nt_{R}, x, v) returns the decision tree and the name tree of the relation R_{ω}(dt)_{:x=v} (page 76)

instNameTree(nt_{R}, x) returns the name tree nt_{R} where the first occurrence of x have been removed.

interRel(dt_{1}, dt_{2}) returns the decision tree representing the ω-deterministic relation R_{ω}(dt_{1}) ∧ R_{ω}(dt_{2}) (page 77)

intersection(T, U) returns the tree schema representing the intersection Set(T) and Set(U) (page 121)

interSkel(T, U) returns the skeleton representing the intersection of Ens(T) and Ens(U) (page 120)

leastDeterministic(R) returns the MDD of the least ω-deterministic relation containing the regular relation R (page 80)

mdd(R) returns the MDD of the finite relation R (page 53)

mergeEntries(t, s, n, S) is first called with n = 0 and S empty. t and s are the trees representing the entry names of the regular relations R and S. It returns a tree representing a set of entry names which is compatible with both R and S. (page 74) projection(t, x, T) returns the projection of the tree schema T on the tree t

according to the variable x (page 132)

projSkel(t, x, T) returns the projection of the skeleton T on the tree t according to the variable x (page 131)

recCons(t, x) returns the tree t where every subtree labeled by x have been replaced recursively by t. (page 39)

representation(t) returns a node (in a graph) representing the tree t. This representation of t is unique, as long as we always use the two dictionaries D and D_{G}. (page 25)

represent(t, T) is the recursive algorithm for representation. It finds out the cycles with the help of the set of trees above the current tree, T. When a cycle is found, calls

          for representCycle.

representCycle(N) returns the uniquely determined node representing the same tree as N which is in a cycle.

share(G) modifies the graph G (by merging some of its nodes) so that any couple of different nodes of G represent different trees (page 20)

initiateBlocks(N) creates the partition Blocks of the graph according to the labels of the graphs

shareWithDone(N) N is a node of a graph labeled by partial keys. If this node represent the same tree as one of the nodes that can be reached through the partial keys, returns true. Must be called with empty dictionaries D_{D} and D_{S}. If the algorithm returns true, then the node equivalent to N is stored in D_{S}(N). (page 26)

tryShare(M, N, i, O) is used to determine whether the node M is equivalent to the already treated node N or any node reachable from N. We have M.i = O which is already treated and is used to restrain the number of calls to

          compareWithDone.

compareWithDone(M, N) determines whether the node M represents the same tree as the node N which is already in D (and so a representation with maximal sharing).

treeKey(N) returns the tree that is the key of the node N of a strongly connected graph (page 22) treeMap(N, F) recursively applies the function F to the tree represented by the

node N, and returns the result of this operation. We suppose that a fixpoint strategy is available for F. (page 36)

treeSubst(t_{1}, x, t_{2}) The substitution of the label x by the tree t_{2} in the tree t_{1} (page 38)

unavoidableSet(dt) returns the set of unavoidable relations defined by the decision tree dt. (page 71)

unfoldTrue(t, r) returns the decision tree t where every true node reachable without going through a iter is replaced by r. (page 77)

unionRel(dt_{1}, dt_{2}) returns the decision tree of the least ω-deterministic relations containing the union of the two ω-deterministic relations represented by the decision trees dt_{1} and dt_{2}. (page 81)

unionSkel(T, U) returns the tree schema representing the union of the two skeletons T and U (page 125)

unionWithLinks(T, U, A) returns the skeleton of the union of T and U and the set of union links informations collected in the process.

makeUnionLink(L, T) adds to T the links described in the union link information L.

172 APPENDIX B. ALGORITHMS

Bibliography

[AH84] Dana Angluin and Douglas N. Hoover. Regular prefix relations. Mathematical Systems Theory, 17:167–191, 1984.

[AHU74] Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman. The Design and Analysis of Computer Algorithms. Addison-Wesley, 1974.

[AHU83] Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman. Data Structures and Algorithms. Addison-Wesley, 1983.

[Aik94] Alexander Aiken. Set constraints: Results, applications and future directions. In Alan Borning, editor, Principles and Practice of Constraint Programming, volume 874 of Lecture Notes in Computer Science, pages 326–335. Springer-Verlag, May 1994.

[AM91] Alexander Aiken and Brian R. Murphy. Implementing regular tree expressions. In J. Hughes, editor, Functional Programming Languages and Computer Architecture, volume 523 of Lecture Notes in Computer Science, pages 427–446. Springer-Verlag, 1991.

[AN80] André Arnold and Maurice Nivat. Formal computations of non deterministic recursive program schemes. Mathematical Systems Theory, 13:219–236, 1980.

[AN92] André Arnold and Damian Niwiński. Fixed point characterization of weak monadic logic definable sets of trees. In M. Nivat and A. Podelski, editors, Tree Automata and Languages, volume 10 of Studies in Computer Science and Artificial Intelligence, pages 159– 188. Elsevier Science Publishers, 1992.

[And86] Nils Andersen. Approximating term rewriting systems with tree grammars. Technical Report 86/16, Institute of Datalogy, University of Copenhagen, 1986.

[AW92] Alexander Aiken and Edward L. Wimmers. Solving systems of set constraints. In IEEE - LICS ’92, pages 329–340, 1992.

[BCL91] Jerry R. Burch, Edmund M. Clarke, and David E. Long. Symbolic model checking with partitioned transition relations. In International Conference on Very Large Scale Integration, Edinbourg, Scotland, August 1991.

[BCM^{+}90] Jerry R. Burch, Edmund M. Clarke, K. L. McMillan, David L. Dill, and J. Hwang. Symbolic modek checking: 10^{20} states and beyond. In Fifth Annual Symposium on Logic in Computer Science, June 1990.

[BHMSV84] R. K. Brayton, G. D. Hachtel, C. T. Mc Mullen, and A. L. Sangiovanni-Vincentelli. Logic Minimization Algorithms for VLSI Synthesis. Kluwer Academic Publishers, 1984.

[BJ88] M. Bruynooghe and G. Janssens. An instance of abstract interpertation integrating type and mode inferencing. In R. Kowalski and K. Bowen, editors, Fifth International Conference and Symposium on Logic Programming, volume 1, pages 669–683. MIT Press, 1988.

[BKR97] Morten Biehl, Nils Klarlund, and Theis Rauhe. Algorithms for guided tree automata. In First International Workshop on Implementing Automata, volume 1260 of Lecture Notes in Computer Science, 1997.

[BMW91] Jürger Börstler, Ulrich Möncke, and Reinhard Wilhelm. Table compression for tree automata. ACM Transactions on Programming Languages and Systems, 13(3):295–314, July 1991.

[BN80] Luc Boasson and Maurice Nivat. Adherences of languages. Journal of Computer and System Sciences, 20(3):285–309, 1980.

[BRB90] Karl S. Brace, Richard L. Rudell, and Randal E. Bryant. Efficient implementation of a BDD package. In 27th ACM/IEEE Design Automation Conference, pages 40–45, June 1990.

[Bru93] G. Bruns. A practicle technique for process abstraction. In 4th International Conference on Concurrency Theory, volume 715 of Lecture Notes in Computer Science, pages 37–49. Springer-Verlag, 1993.

[Bry86] Randal E. Bryant. Graph based algorithms for boolean function manipulation. IEEE Transactions on Computers, C-35:677–691, August 1986.

[Bry92] Randal E. Bryant. Symbolic boolean manipulation with ordered binary-decision diagrams. ACM Computing Surveys, 24(3):293–318, September 1992.

[BT92] B. Bogaert and Sophie Tison. Equality and disequality constraints on direct subterms in tree automata. In A. Finkel and M. Jantzen, editors, 9th Annual Symposium on Theoretical Aspects of Computer Science (STACS 92), volume 577 of Lecture Notes in Computer Science, pages 161–171. Springer-Verlag, February 1992.

[Büc60] J. R. Büchi. On a decision method in restricted second order arithmetics. In E. Nagel et al., editors, International Congress on Logic, Methodology and Philosophy of Science. Stanford University Press, 1960.

[Büc73] J. R. Büchi. The monadic theory of ω_{1}. In Decidable Theories II, volume 328 of Lecture Notes in Mathematics. Springer, 1973.

[CC77] Patrick Cousot and Radhia Cousot. Abstract interpretation: a unified lattice model for static analysis of programs by construction of approximation of fixpoints. In 4th ACM Symposium on Principles of Programming Languages (POPL ’77), pages 238–252, 1977.

[CC79] Patrick Cousot and Radhia Cousot. Constructive version of Tarski’s fixed point theorems. Pacific Journal of Mathematics, 82(1):43–57, 1979.

[CC82] A. Cardon and M. Crochemore. Partitioning a graph in O(|A| log_{2} |V |). Theoretical Computer Science, 19:85–98, 1982.

[CC92a] Patrick Cousot and Radhia Cousot. Abstract interpretation and application to logic programs. Journal of Logic Programming, 13(2– 3):103–179, 1992.

[CC92b] Patrick Cousot and Radhia Cousot. Abstract interpretation framework. Journal of Logic and Computation, 2(4):511–547, August 1992.

[CC95] Patrick Cousot and Radhia Cousot. Formal languages, grammar and set-constraint-based program analysis by abstract interpretation. In Conference on Functional Programming and Computer Architecture (FPCA ’95), pages 170–181. ACM Press, June 1995.

[CES83] Edmund M. Clarke, E. Allen Emerson, and A. P. Sistla. Automatic verification of finite-state concurrent sytems using temporal logic specification. In 10th ACM Symposium on Principles of Programming Languages (POPL ’83), 1983.

[CGL94] Edmund M. Clarke, O. Grumberg, and D. E. Long. Model checking and abstraction. ACM Transactions on Programming Languages and Systems, 16(5):1512–1542, 1994.

[CH78] Patrick Cousot and Nicolas Halbwachs. Automatic discovery of linear constraints among variables of a program. In 5th ACM Symposium on Principles of Programming Languages (POPL ’78), pages 84–97, 1978.

[Cha94] Witold Charatonik. Set constraints in some equational theories. In Jean-Pierre Jouanaud, editor, Constraints in Computational Logics, volume 845 of Lecture Notes in Computer Science, pages 304–319. Springer-Verlag, September 1994.

[CMR92] M.-M. Corsini, K. Musumbi, and A. Rauzy. The μ-calculus over finite domains as an abstract semantics of Prolog. In M. Billaud, P. Castéran, M.-M. Corsini, K. Musumbu, and A. Rauzy, editors, Workshop on Static Analysis, number 81–82 in Bigre, September 1992.

[CNP93] Hugues Calbrix, Maurice Nivat, and Andreas Podelski. Ultimately periodic set words of rational ω-languages. In S. Brookes, M. Main, A. Melton, M. Mislove, and D. Schmidt, editors, 9th International Conference on Mathematical Foundations of Programming Semantics (MFPS ’93), volume 802 of Lecture Notes in Computer Science, pages 554–566. Springer-Verlag, April 1993.

[Col82] Alain Colmerauer. PROLOG and infinite trees. In K. L. Clark and S.-A. Tärnlund, editors, Logic Programming, volume 16 of APIC Studies in Data Processing, pages 231–251. Academic Press, 1982.

[Col84] Alain Colmerauer. Equations and inequations on finite and infinite trees. In International Conference on Fifth Generation Computer Systems (FGCS’84), pages 85–99. Elsevier Science Publishers, 1984.

[Cou78] Patrick Cousot. Méthodes itératives de construction et d’approximation de points fixes d’opérateurs monotones sur un treillis, analyse sémantique des programmes. PhD thesis, Université de Grenoble, March 1978.

[Cou96] Patrick Cousot. Abstract interpretation. ACM Computing Surveys, 28(2):324–328, June 1996.

[CP95] Jiazhen Cai and Robert Paige. Using multiset discrimination to solve language processing without hashing. Theoretical Computer Science, 145:189–228, 1995. URL “ftp://ftp.diku.dk/diku/- semantics/papers/D-209.ps.Z”.

[CP98a] Witold Charatonik and Andreas Podelski. Co-definite set constraints. In T. Nipkow, editor, 9th International Conference on Rewriting Techniques and Applications, volume 1379 of Lecture Notes in Computer Science, pages 211–225. Springer-Verlag, March-April 1998.

[CP98b] Witold Charatonik and Andreas Podelski. Set-based analysis of reactive infinite-state systems. In B. Steffen, editor, First International Conference on Tools and Algorithms for the Construction and Analysis of Systems, volume 1384, pages 358–375. Springer-Verlag, March-April 1998.

[CS91] R. Cleaveland and B. Steffen. A linear-time model-checking for alternation free modal μ-calculus. In Third workshop on Computer Aided Verification, Lecture Notes in Computer Science. Springer-Verlag, July 1991.

[Dam96] D. Dams. Abstract Interpretation and Partition Refinement for Model Checking. PhD thesis, Technishe Universiteit Eindhoven, 1996.

[Deu92] Alain Deutsch. A storeless model of aliasing and its abstractions using finite representations of right-regular equivalence relations. In IEEE’92 International Conference on Computer Languages. IEEE Press, 1992.

[DTT97] P. Devienne, JM. Talbot, and Sophie Tison. Solving classes of set constraints with tree automata. In G. Smolka, editor, 3th International Conference on Principles and Practice of Constraint Programming, volume 1330 of Lecture Notes in Computer Science, pages 62–76. Springer-Verlag, October 1997.

[EC80] E. A. Emerson and E. M. Clarke. Characterizing correctness properties of parallel programs using fixpoints. In J. W. de Bakker and J. van Leeuwen, editors, Automata, Languages and Programming, volume 85 of Lecture Notes in Computer Science, pages 169–181. Springer-Verlag, 1980.

[EF80] Joost Engelfriet and Gilberto Filè. Formal properties of one-visit and multi-pass attribute grammars. In J. W. de Bakker and J. van Leeuwen, editors, Automata, Languages and Programming, volume 85 of Lecture Notes in Computer Science, pages 182–194. Springer-Verlag, 1980.

[EJ91] E. A. Emerson and C. S. Jutla. Tree automata, mu-calculus and determinacy. In 32nd Annual Symposium on Foundations of Computer Science, pages 368–377. IEEE Computer Society, 1991.

[EJS93] E. A. Emerson, C. S. Jutla, and A. P. Sistla. On model-checking for fragments of μ-calculus. In Costas Courcoubetis, editor, Computer Aided Verification, volume 697 of Lecture Notes in Computer Science, pages 385–391, June/July 1993.

[Eng94] Joost Engelfriet. Graph grammars and tree transducers. In Sophie Tison, editor, Trees in Algebra and Programming — CAAP ’94, volume 787 of Lecture Notes in Computer Science, pages 15–36. Springer-Verlag, April 1994.

[ES88] E. Allen Emerson and Jai Srinivasan. Branching time temporal logic. In J. W. de Bakker, W. P. de Roever, and G. Rozenberg, editors, Linear Time, Branching Time, and Partial Order in Logics and Models for Concurrency, volume 354 of Lecture Notes in Computer Science, pages 123–172. Springer-Verlag, May/June 1988.

[EV94] Joost Engelfriet and Heiko Vogler. The translation power of topdown tree-to-graph transducers. Journal of Computer and System Sciences, 49:258–305, 1994.

[FS91] G. Filé and P. Sottero. Abstract interpretation for type checking. In J. Maluszyński and M. Wirsing, editors, Third International Symposium on Programming Language Implementation and Logic Programming (PLILP ’91), pages 311–322. Springer-Verlag, August 1991.

[GB94] Daniel Geist and Ilan Beer. Efficient model checking by automated ordering of transition relation partitions. In David L. Dill, editor, Sixth International Conference on Computer Aided Verification, volume 818 of Lecture Notes in Computer Science, pages 299–310. Springer-Verlag, 1994.

[GF93] Aarti Gupta and Allan L. Fisher. Parametric circuit representation using inductive boolean functions. In Costas Courcoubetis, editor, Computer Aided Verification, volume 697 of Lecture Notes in Computer Science, pages 15–28. Springer-Verlag, 1993.

[GN84] F. Gire and Maurice Nivat. Relations rationelles infinitaires. Calcolo, 21:91–125, 1984.

[Gra89] Philippe Granger. Static analysis of arithmetical congruences. International Journal of Computer Mathematics, 30:165–190, 1989.

[GS84] F. Gécseg and M. Steinby. Tree Automata. Akadémia Kiadó, 1984.

[HD93] Alan J. Hu and David L. Dill. Efficient verification with BDDs using implicitly conjoined invariants. In Costas Courcoubetis, editor, Computer Aided Verification, volume 697 of Lecture Notes in Computer Science, pages 4–14. Springer-Verlag, 1993.

[Hei92] Nevin Heintze. Set Based Program Analysis. PhD thesis, School of Computer Science, Carnegie Mellon University, October 1992.

[HJ90] Nevin Heintze and Joxan Jaffar. A finite presentation theorem for approximating logic programs. In ACM Symposium on Principles of Programming Languages (POPL’90), pages 197–209, 1990.

[HJJ^{+}96] Jesper G. Henriksen, Jakob Jensen, Michael Jørgensen, Nils Klarlund, Robert Paige, Theis Rauhe, and Anders Sandholm. Mona: Monadic second-order logic in practice. In Tools and Algorithms for the Construction and Analysis of Systems, volume 1019 of Lecture Notes in Computer Science, 1996.

[HK87] K. Horiuchi and T. Kanamori. Polymorphic type inference in Prolog by abstract interpretation. In K. Furukawa, H. Tanaka, and T. Fujisaka, editors, 6th Conference on Logic Programming, volume 315 of Lecture Notes in Computer Science, pages 195–214. Springer-Verlag, June 1987.

[Hop71] John Hopcroft. An n log n algorithm for minimizing states in a finite automaton. In Z. Kohavi and A. Paz, editors, Theory of machines and computations, pages 189–196. Academic Press, 1971.

[IS98] Husain Ibraheem and David A. Schmidt. Adaptating big-step semantics to small-step style: Coinductive interpretations and “higher-order” derivations. In C. Talcott, editor, 2nd Workshop on Higher-Order Techniques in Operational Semantics. Elsevier Science Publishers, 1998.

[JM79] N. D. Jones and S. S. Muchnick. Flow analysis and optimization of LISP-like structures. In 6th POPL, pages 244–256. ACM Press, January 1979.

[JW95] Suresh Jagannathan and Stephen Weeks. A unified treatment of flow analysis in higher-order languages. In 22nd ACM Symposium on Principles of Programming Languages (POPL ’95), pages 393– 407, 1995.

[KMM^{+}97] Y. Kesten, O. Maler, M. Marcus, A. Pnueli, and E. Shahar. Symbolic model checking with rich assertional languages. In Computer Aided Verification, volume 1254 of Lecture Notes in Computer Science, pages 424–435. Springer-Verlag, 1997.

[Knu68] Donald E. Knuth. Semantics of context-free languages. Mathematical Systems Theory, 2:127–145, 1968.

[Knu73] Donald E. Knuth. Sorting and Searching, volume 3 of The Art of Computer Programming. Addison-Wesley, 1973.

[Knu97] Donald E. Knuth. Fundamental Algorithms, volume 1 of The Art of Computer Programming. Addison-Wesley, third edition, 1997.

[Koz83] D. Kozen. Results on the propositional mu-calculus. Theoretical Computer Science, 27:333–354, December 1983.

[KR96] Nils Klarlund and Theis Rauhe. BDD algorithms and cache misses. Technical Report RS-96-5, BRICS, Department of Computer Science, University of Aarhus, 1996.

[Lam77] Leslie Lamport. Proving the correctness of multiprocess programs. IEEE Transactions on Software Engineering, SE-3(2):125– 143, March 1977.

[Lev97] F. Levi. Abstract model checking of value-passing processes. In A. Bossi, editor, International Workshop on Verification, Model Checking and Abstract Interpretation, 1997.

[Mas92] François Masdupuy. Array operations abstractions using semantic analysis of trapezoid congruences. In International Conference on Supercomputing, 1992.

[Mau98] Laurent Mauborgne. Abstract interpretation using typed decision graphs. Science of Computer Programming, 31(1):91–112, May 1998.

[Mau99] Laurent Mauborgne. Binary decision graphs. In A. Cortesi and G. Filé, editors, Static Analyis Symposium (SAS’99), volume 1694 of Lecture Notes in Computer Science, pages 101–116. Springer-Verlag, 1999.

[Mic68] D. Michie. “memo” functions and machine learning. Nature, 218:19– 22, April 1968.

[Mis84] P. Mishra. Towards a theory of types in Prolog. In International Symposium on Logic Programming, pages 289–298. IEEE Computer Society Press, 1984.

[MP88] Zohar Manna and Amir Pnueli. The anchored version of the temporal framework. In J. W. de Bakker, W. P. de Roever, and G. Rozenberg, editors, Linear Time, Branching Time, and Partial Order in Logics and Models for Concurrency, volume 354 of Lecture Notes in Computer Science, pages 201–284. Springer-Verlag, May/June 1988.

[MR85] P. Mishra and U. S. Reddy. Declaration-free type checking. In 12th ACM Symposium on Principles of Programming Languages (POPL ’85), pages 7–21, 1985.

[MS81] Jocelyne Mongy-Steen. Transformation de noyaux reconnaissables d’arbres. Forêts RATEG. PhD thesis, LIF de Lille, February 1981.

[Rab69] Michael O. Rabin. Decidability of second-order theories and automata on infinite trees. Transactions of the American Mathematical Society, 141:1–35, July 1969.

[Rey69] J. Reynolds. Automatic computation of data set definitions. In Information Processing ’68, pages 456–461. Elsevier Science Publisher, 1969.

[Saf88] S. Safra. On the complexity of omega-automata. In 29th Annual Symposium on Foundations of Computer Science, pages 319–327. IEEE Computer Society, October 1988.

[Sch90] Michael I. Schwartzbach. Infinite values in hierarchical imperative types. In A. Arnold, editor, 15th Colloquium on Trees in Algebra and Programming (CAAP ’90), volume 431 of Lecture Notes in Computer Science, pages 254–268. Springer-Verlag, May 1990.

[Sch97] David A. Schmidt. Abstract interpretation of small-step semantics. In 5th LOMAPS Workshop on Analysis and Verification of Multiple-Agent Languages, volume 1192 of Lecture Notes in Computer Science, pages 76–99. Springer-Verlag, 1997.

[Sch98a] David A. Schmidt. Data flow analysis is model checking of abstract interpretations. In 25th ACM Symposium on Principles of Programming Languages (POPL ’98), 1998.

[Sch98b] David A. Schmidt. Trace-based abstract interpretation of operational semantics. Journal of Lisp and Symbolic Computation, 10(3):237–271, 1998.

[Sei90] H. Seidl. Deciding equivalence of finite tree automata. SIAM Journal of Computing, 19(3):424–437, June 1990.

[SKMB90] Arvind Srinivasan, Timothy Kam, Sharad Malik, and Robert K. Brayton. Algorithms for discrete function manipulation. In IEEE International Conference on Computer-Aided Design, pages 92–95, 1990.

[SNW94] V. Sassone, M. Nielson, and G. Winskel. Relationship between models of concurrency. In Proceedings of the Rex ’93 School and Symposium, 1994.

[Sør94] Morten Heine Sørensen. A grammar-based data-flow analysis to stop deforestation. In Sophie Tison, editor, Trees in Algebra and Programming — CAAP ’94, volume 787 of Lecture Notes in Computer Science, pages 335–351. Springer-Verlag, April 1994.

[SVW85] A. P. Sistla, M. Y. Vardi, and P. Wolper. The complementation problem for büchi automata, with applications to temporal logic. In 12th International Colloquium on Automata, Languages and Programming, Lecture Notes in Computer Science. Springer-Verlag, 1985.

[Tar55] A. Tarski. A lattice theoretical fixpoint theorem and its applications. Pacific Journal of Mathematics, 5:285–310, 1955.

[Tar72] Robert Tarjan. Depth-first search and linear graph algorithms. SIAM Journal on Computing, 1(2):146–160, June 1972.

[Tho88] Wolfgang Thomas. Computation tree logic and regular ω-languages. In J. W. de Bakker, W. P. de Roever, and G. Rozenberg, editors, Linear Time, Branching Time, and Partial Order in Logics and Models for Concurrency, volume 354 of Lecture Notes in Computer Science, pages 690–713. Springer-Verlag, May/June 1988.

[Tho90] Wolfgang Thomas. Automata on infinite objects. In J. van Leeuwen, editor, Hanbook of Theoretical Computer Science, volume B, chapter 4, pages 135–191. Elsevier Science Publishers, 1990.

[TW68] J. W. Thatcher and J. B. Wright. Generalized finite automata with an application to a decision problem of second-order logic. Mathematical Systems Theory, 2:57–82, 1968.

[Var94] Moshe Y. Vardi. Nontraditional applications of automata theory. In Masami Hagiya and John C. Mitchell, editors, Theoretical Aspects of Computer Software, volume 789 of Lecture Notes in Computer Science, pages 575–597. Springer-Verlag, April 1994.

[vEK76] M. H. van Emden and R. A. Kowalski. The semantics of predicate logic as a programming language. Journal of the Association for Computer Machinery, 23(4):733–742, October 1976.

[Ven97] Arnaud Venet. Abstract interpretation of the π-calculus. In LOMAPS Workshop on Analysis and Verification of Multiple-Agent Languages, volume 1192 of Lecture Notes in Computer Science, pages 51–75. Springer-Verlag, 1997.

[vGG89] R. von Glabbeck and U. Goltz. Partial order semantics for refinement of actions. Bulletin of the EATCS, 34, 1989.

[YS87] E. Yardeni and E. Y. Shapiro. A type system of logic programs. In E. Y. Shapiro, editor, Concurrent Prolog: Collected Papers, volume 2, pages 211–244. MIT Press, 1987.

Index

ω-deterministic relation, 60 ω-regular relation, 48

automaton, 7, 49, 55, 85–86, 88, 109

BDD, 41, 50, 53, 92, 94, 160

child, 8 choice space, 63, 93–94 connected, 11

sharing, 19–23

entry, 12 equivalent, 45, 111 name, 44, 73–75, 96, 111, 113

equivalence, 6, 19, 23, 30

father, 8 fixpoint, 5, 10, 15–16, 36, 89, 100, 107

iterative relation, 47, 55

key, 18, 22

lattice, 6 link, 93–106, 113, 119, 123, 124, 135,

136, 138

maximal sharing, 18

open relation, 47, 55

greatest, 56–57, 66–69 ordering, 5–6, 30, 89, 100

alphabetic, 7

approximation, 15, 150

computation, 15 covering, 97, 114 labels, 90, 93 prefix, 7 subtree, 8 variables, 74

parent, 8

path, 7, 8, 11, 22, 43, 64, 112, 154 compression, 11, 50 to choice, 93, 97, 114

periodic entry names, 46, 50 word, 7

prefix, 7

prefix regular, 47

projection, 13, 14, 44, 130–132

ranked, 8

redundant node, 52

redundant nodes, 65, 72, 74

regular relation, 48, 59 tree, 9 relation, 12–14 return edges, 12 root

graph, 12 tree, 8

skeleton, 88–93, 102, 104, 114, 119,

124, 125, 131 square relation, 13, 55 subgraph, 12 subtree, 8

widening, 16, 135, 151