root/applications/robust/robustlib.h @ 1204

Revision 1204, 18.8 kB (checked in by sindj, 14 years ago)

Rozpracovani funkci na Bayes data update. JS

RevLine 
[976]1/*!
2  \file
3  \brief Robust Bayesian auto-regression model
4  \author Jan Sindelar.
5*/
6
7#ifndef ROBUST_H
8#define ROBUST_H
9
10#include <stat/exp_family.h>
[1171]11#include <limits>
[1172]12#include <vector>
13#include <algorithm>
[976]14       
15using namespace bdm;
16using namespace std;
[1204]17using namespace itpp;
[976]18
[1172]19const double max_range = numeric_limits<double>::max()/10e-5;
[1171]20
21class polyhedron;
22class vertex;
23
[1172]24/// A class describing a single polyhedron of the split complex. From a collection of such classes a Hasse diagram
25/// of the structure in the exponent of a Laplace-Inverse-Gamma density will be created.
[1171]26class polyhedron
[976]27{
[1172]28        /// A property having a value of 1 usually, with higher value only if the polyhedron arises as a coincidence of
29        /// more than just the necessary number of conditions. For example if a newly created line passes through an already
30        /// existing point, the points multiplicity will rise by 1.
31        int multiplicity;       
[976]32
[1204]33        int split_state;
34
35        int merge_state;
36
37       
38
[1172]39public:
40        /// A list of polyhedrons parents within the Hasse diagram.
41        vector<polyhedron*> parents;
[1171]42
[1172]43        /// A list of polyhedrons children withing the Hasse diagram.
44        vector<polyhedron*> children;
[1171]45
[1172]46        /// All the vertices of the given polyhedron
47        vector<vertex*> vertices;
[1171]48
[1172]49        /// A list used for storing children that lie in the positive region related to a certain condition
50        vector<polyhedron*> positivechildren;
[1171]51
[1172]52        /// A list used for storing children that lie in the negative region related to a certain condition
53        vector<polyhedron*> negativechildren;
[1171]54
[1172]55        /// Children intersecting the condition
56        vector<polyhedron*> neutralchildren;
[1171]57
[1204]58        vector<polyhedron*> mergechildren;
59
60        polyhedron* positiveparent;
61
62        polyhedron* negativeparent;
63
64        int message_counter;
65
[1172]66        /// List of triangulation polyhedrons of the polyhedron given by their relative vertices.
67        vector<vector<vertex*>> triangulations;
[1171]68
[1172]69        /// A list of relative addresses serving for Hasse diagram construction.
[1171]70        vector<int> kids_rel_addresses;
71
[1172]72        /// Default constructor
[1171]73        polyhedron()
74        {
[1204]75                multiplicity = 1;
76
77                message_counter = 0;
[1171]78        }
79       
[1172]80        /// Setter for raising multiplicity
[1204]81        void raise_multiplicity()
[1171]82        {
83                multiplicity++;
84        }
85
[1172]86        /// Setter for lowering multiplicity
[1204]87        void lower_multiplicity()
[1171]88        {
89                multiplicity--;
90        }
91       
[1172]92        /// An obligatory operator, when the class is used within a C++ STL structure like a vector
93        int operator==(polyhedron polyhedron2)
94        {
95                return true;
96        }
97
98        /// An obligatory operator, when the class is used within a C++ STL structure like a vector
99        int operator<(polyhedron polyhedron2)
100        {
101                return false;
102        }
[1204]103
104        void set_state(double state_indicator, actions action)
105        {
106                switch(action)
107                {
108                        case MERGE:
109                                merge_state = (int)sign(state_indicator);                       
110                        break;
111                        case SPLIT:
112                                split_state = (int)sign(state_indicator);
113                        break;
114                }
115        }
116
117        int get_state(actions action)
118        {
119                switch(action)
120                {
121                        case MERGE:
122                                return merge_state;                     
123                        break;
124                        case SPLIT:
125                                return split_state;
126                        break;
127                }
128        }
129
130        int number_of_children()
131        {
132                return children.size()+positivechildren.size()+negativechildren.size()+neutralchildren.size();
133        }
134
135        void send_state_message(bool shouldsplit, bool shouldmerge)
136        {
137                if(shouldsplit||shouldmerge)
138                {
139                        for(vector<polyhedron*>::iterator parent_iterator = parents.begin();parent_iterator<parents.end();parent_iterator++)
140                        {
141                                polyhedron* current_parent = *parent_iterator;
142
143                                current_parent->message_counter++;
144
145                                bool is_last = (current_parent->message_counter == current_parent->number_of_children());
146
147                                if(shouldmerge)
148                                {
149                                        int child_state  = get_state(MERGE);
150                                        int parent_state = current_parent->get_state(MERGE);
151
152                                        if(parent_state == NULL || parent_state == 0)
153                                        {
154                                                current_parent->set_state(child_state, MERGE);
155
156                                                if(child_state == 0)
157                                                {
158                                                        current_parent->mergechildren.push_back(this);
159                                                }
160                                        }
161                                        else
162                                        {
163                                                if(child_state == 0)
164                                                {
165                                                        if(parent_state > 0)
166                                                        {
167                                                                positiveparent = current_parent;
168                                                        }
169                                                        else
170                                                        {
171                                                                negativeparent = current_parent;
172                                                        }
173                                                }
174                                        }
175
176                                        if(is_last)
177                                        {
178                                                if(parent_state > 0)
179                                                {
180                                                        for(vector<polyhedron*>::iterator merge_child = current_parent->mergechildren.begin(); merge_child < current_parent->mergechildren.end();merge_child++)
181                                                        {
182                                                                (*merge_child)->positiveparent = current_parent;
183                                                        }
184                                                }
185
186                                                if(parent_state < 0)
187                                                {
188                                                        for(vector<polyhedron*>::iterator merge_child = current_parent->mergechildren.begin(); merge_child < current_parent->mergechildren.end();merge_child++)
189                                                        {
190                                                                (*merge_child)->negativeparent = current_parent;
191                                                        }
192                                                }
193
194                                                current_parent->mergechildren.clear();
195                                        }
196
197
198                                }
199                       
200                        }
201                }
202        }
[976]203};
204
[1186]205/// A class for representing 0-dimensional polyhedron - a vertex. It will be located in the bottom row of the Hasse
206/// diagram representing a complex of polyhedrons. It has its coordinates in the parameter space.
[1172]207class vertex : public polyhedron
[976]208{
[1186]209        /// A dynamic array representing coordinates of the vertex
[1204]210        vec coordinates;       
[976]211
[1204]212        enum actions {MERGE, SPLIT};
213
[976]214public:
[1171]215
[1204]216
217
[1186]218        /// Default constructor
[1171]219        vertex();
220
[1186]221        /// Constructor of a vertex from a set of coordinates
[1204]222        vertex(vec coordinates)
[1171]223        {
[1172]224                this->coordinates = coordinates;
[1171]225        }
226
[1186]227        /// A method that widens the set of coordinates of given vertex. It is used when a complex in a parameter
228        /// space of certain dimension is established, but the dimension is not known when the vertex is created.
[1171]229        void push_coordinate(double coordinate)
230        {
[1204]231                coordinates = concat(coordinates,coordinate);
[1171]232        }
233
[1186]234        /// A method obtaining the set of coordinates of a vertex. These coordinates are not obtained as a pointer
235        /// (not given by reference), but a new copy is created (they are given by value).
[1204]236        vec get_coordinates()
237        {               
238                return coordinates;
239        }
[1172]240
[1204]241               
[1172]242};
[976]243
[1186]244/// A class representing a polyhedron in a top row of the complex. Such polyhedron has a condition that differitiates
245/// it from polyhedrons in other rows.
[1172]246class toprow : public polyhedron
[1171]247{
[1204]248       
249public:
[1186]250        /// A condition used for determining the function of a Laplace-Inverse-Gamma density resulting from Bayesian estimation
[1204]251        vec condition;
[976]252
[1186]253        /// Default constructor
[1171]254        toprow();
[976]255
[1186]256        /// Constructor creating a toprow from the condition
[1204]257        toprow(vec condition)
[1171]258        {
[1172]259                this->condition = condition;
[1171]260        }
261
[1172]262};
[1171]263
[1204]264class condition
265{       
266public:
267        vec value;     
[1171]268
[1204]269        int multiplicity;
[1171]270
[1204]271        condition(vec value)
272        {
273                this->value = value;
274                multiplicity = 1;
275        }
276}
[1171]277
[1204]278
[976]279//! Conditional(e) Multicriteria-Laplace-Inverse-Gamma distribution density
[1186]280class emlig // : eEF
[1172]281{
[976]282
[1186]283        /// A statistic in a form of a Hasse diagram representing a complex of convex polyhedrons obtained as a result
284        /// of data update from Bayesian estimation or set by the user if this emlig is a prior density
[1172]285        vector<vector<polyhedron*>> statistic;
[1204]286
287        vector<condition*> conditions;
288
289        double normalization_factor;
290
291        void alter_toprow_conditions(vec condition, bool should_be_added)
292        {
293                for(vector<polyhedron*>::iterator horiz_ref = statistic[statistic.size()-1].begin();horiz_ref<statistic[statistic.size()-1].end();horiz_ref++)
294                {
295                        double product = 0;
296
297                        vector<vertex*>::iterator vertex_ref = (*horiz_ref)->vertices.begin();
298
299                        do
300                        {
301                                product = (*vertex_ref)->coordinates*condition;
302                        }
303                        while(product == 0)
304
305                        if((product>0 && should_be_added)||(product<0 && !should_be_added))
306                        {
307                                ((toprow*) (*horiz_ref))->condition += condition;
308                        }
309                        else
310                        {
311                                ((toprow*) (*horiz_ref))->condition -= condition;
312                        }                                                       
313                }
314        }
[1171]315       
316public: 
[976]317
[1186]318        /// A default constructor creates an emlig with predefined statistic representing only the range of the given
319        /// parametric space, where the number of parameters of the needed model is given as a parameter to the constructor.
[1171]320        emlig(int number_of_parameters)
321        {
[1172]322                create_statistic(number_of_parameters);
[1171]323        }
324
[1186]325        /// A constructor for creating an emlig when the user wants to create the statistic by himself. The creation of a
326        /// statistic is needed outside the constructor. Used for a user defined prior distribution on the parameters.
[1172]327        emlig(vector<vector<polyhedron*>> statistic)
[1171]328        {
[1172]329                this->statistic = statistic;
[1171]330        }
331
[1204]332        void add_and_remove_condition(vec toremove, vec toadd)
333        {
334                vector<condition*>::iterator toremove_ref = conditions.end();
335                bool condition_should_be_added = false;
336
337                for(vector<condition*>::iterator ref = conditions.begin();ref<conditions.end();ref++)
338                {
339                        if(toremove != NULL)
340                        {
341                                if((*ref)->value == toremove)
342                                {
343                                        if(multiplicity>1)
344                                        {
345                                                multiplicity--;
346
347                                                alter_toprow_conditions(toremove,false);
348
349                                                toremove = NULL;
350                                        }
351                                        else
352                                        {
353                                                toremove_ref = ref;                                                     
354                                        }
355                                }
356                        }
357
358                        if(toadd != NULL)
359                        {
360                                if((*iterator)->value == toadd)
361                                {
362                                        (*iterator)->multiplicity++;
363
364                                        alter_toprow_conditions(toadd,true);
365
366                                        toadd = NULL;
367                                }
368                                else
369                                {
370                                        condition_should_be_added = true;
371                                }
372                        }
373                }
374
375                if(toremove_ref!=conditions.end())
376                {
377                        conditions.erase(toremove_ref);
378                }
379
380                if(condition_should_be_added)
381                {
382                        conditions.push_back(new condition(toadd));
383                }
384
385                vector<vector<polyhedron*>> for_splitting;
386                vector<vector<polyhedron*>> for_merging;
387
388                for(vector<polyhedron*>::iterator horizontal_position = statistic[0].begin();horizontal_position<statistic[0].end();horizontal_position++)
389                {               
390                        vertex* current_vertex = (vertex*)horizontal_position;
391                       
392                        if(toadd != NULL)
393                        {
394                                current_vertex->set_state(toadd*current_vertex->coordinates,SPLIT);
395                        }
396                       
397                        if(toremove != NULL)
398                        {
399                                current_vertex->set_state(toremove*current_vertex->coordinates,MERGE);
400                        }
401
402                        current_vertex->send_state_message(toadd != NULL, toremove != NULL);
403                }
404        }
405
[1171]406protected:
407
[1186]408        /// A method for creating plain default statistic representing only the range of the parameter space.
[1172]409    void create_statistic(int number_of_parameters)
[1171]410        {
[1186]411                // An empty vector of coordinates.
[1204]412                vec origin_coord;       
[1171]413
[1186]414                // We create an origin - this point will have all the coordinates zero, but now it has an empty vector of coords.
[1172]415                vertex *origin = new vertex(origin_coord);
[1171]416
[1186]417                // It has itself as a vertex. There will be a nice use for this when the vertices of its parents are searched in
418                // the recursive creation procedure below.
[1172]419                origin->vertices.push_back(origin);
[1171]420
[1186]421                // As a statistic, we have to create a vector of vectors of polyhedron pointers. It will then represent the Hasse
422                // diagram. First we create a vector of polyhedrons..
[1172]423                vector<polyhedron*> origin_vec;
[1171]424
[1186]425                // ..we fill it with the origin..
[1172]426                origin_vec.push_back(origin);
427
[1186]428                // ..and we fill the statistic with the created vector.
[1171]429                statistic.push_back(origin_vec);
430
[1186]431                // Now we have a statistic for a zero dimensional space. Regarding to how many dimensional space we need to
432                // describe, we have to widen the descriptional default statistic. We use an iterative procedure as follows:
[1172]433                for(int i=0;i<number_of_parameters;i++)
[1171]434                {
[1186]435                        // We first will create two new vertices. These will be the borders of the parameter space in the dimension
436                        // of newly added parameter. Therefore they will have all coordinates except the last one zero. We get the
437                        // right amount of zero cooridnates by reading them from the origin
[1204]438                        vec origin_coord = origin->get_coordinates();                                           
[1171]439
[1186]440                        // And we incorporate the nonzero coordinates into the new cooordinate vectors
[1204]441                        vec origin_coord1 = concat(origin_coord,max_range);
442                        vec origin_coord2 = concat(origin_coord,-max_range);
[1172]443
[1186]444                        // Now we create the points
[1172]445                        vertex *new_point1 = new vertex(origin_coord1);
[1186]446                        vertex *new_point2 = new vertex(origin_coord2);
447                       
448                        //*********************************************************************************************************
449                        // The algorithm for recursive build of a new Hasse diagram representing the space structure from the old
450                        // diagram works so that you create two copies of the old Hasse diagram, you shift them up one level (points
451                        // will be segments, segments will be areas etc.) and you connect each one of the original copied polyhedrons
452                        // with its offspring by a parent-child relation. Also each of the segments in the first (second) copy is
453                        // connected to the first (second) newly created vertex by a parent-child relation.
454                        //*********************************************************************************************************
[1172]455
[1186]456
457                        // Create the vectors of vectors of pointers to polyhedrons to hold the copies of the old Hasse diagram
[1172]458                        vector<vector<polyhedron*>> new_statistic1;
459                        vector<vector<polyhedron*>> new_statistic2;
460
[1186]461                        // Copy the statistic by rows
[1172]462                        for(int j=0;j<statistic.size();j++)
[1171]463                        {
[1186]464                                // an element counter
[1171]465                                int element_number = 0;
466
[1186]467                                vector<polyhedron*> supportnew_1;
468                                vector<polyhedron*> supportnew_2;
469
470                                new_statistic1.push_back(supportnew_1);
471                                new_statistic2.push_back(supportnew_2);
472
473                                // for each polyhedron in the given row
[1172]474                                for(vector<polyhedron*>::iterator horiz_ref = statistic[j].begin();horiz_ref<statistic[j].end();horiz_ref++)
[1171]475                                {       
[1186]476                                        // Append an extra zero coordinate to each of the vertices for the new dimension
477                                        // If j==0 => we loop through vertices
478                                        if(j == 0)
479                                        {
480                                                // cast the polyhedron pointer to a vertex pointer and push a zero to its vector of coordinates
481                                                ((vertex*) (*horiz_ref))->push_coordinate(0);
482                                        }
483
484                                        // if it has parents
[1172]485                                        if(!(*horiz_ref)->parents.empty())
[1171]486                                        {
[1186]487                                                // save the relative address of this child in a vector kids_rel_addresses of all its parents.
488                                                // This information will later be used for copying the whole Hasse diagram with each of the
489                                                // relations contained within.
[1172]490                                                for(vector<polyhedron*>::iterator parent_ref = (*horiz_ref)->parents.begin();parent_ref < (*horiz_ref)->parents.end();parent_ref++)
[1171]491                                                {
[1172]492                                                        (*parent_ref)->kids_rel_addresses.push_back(element_number);                                                   
493                                                }                                               
[1171]494                                        }
495
[1186]496                                        // **************************************************************************************************
497                                        // Here we begin creating a new polyhedron, which will be a copy of the old one. Each such polyhedron
498                                        // will be created as a toprow, but this information will be later forgotten and only the polyhedrons
499                                        // in the top row of the Hasse diagram will be considered toprow for later use.
500                                        // **************************************************************************************************
501
502                                        // First we create vectors specifying a toprow condition. In the case of a preconstructed statistic
503                                        // this condition will be a vector of zeros. There are two vectors, because we need two copies of
504                                        // the original Hasse diagram.
[1204]505                                        vec vec1(i+2);
506                                        vec1.zeros();
[1171]507
[1204]508                                        vec vec2(i+2);
509                                        vec2.zeros();
510
[1186]511                                        // We create a new toprow with the previously specified condition.
[1172]512                                        toprow *current_copy1 = new toprow(vec1);
513                                        toprow *current_copy2 = new toprow(vec2);                                       
[1171]514
[1186]515                                        // The vertices of the copies will be inherited, because there will be a parent/child relation
516                                        // between each polyhedron and its offspring (comming from the copy) and a parent has all the
517                                        // vertices of its child plus more.
[1172]518                                        for(vector<vertex*>::iterator vert_ref = (*horiz_ref)->vertices.begin();vert_ref<(*horiz_ref)->vertices.end();vert_ref++)
[1171]519                                        {
[1172]520                                                current_copy1->vertices.push_back(*vert_ref);
521                                                current_copy2->vertices.push_back(*vert_ref);                                           
[1171]522                                        }
[1172]523                                       
[1186]524                                        // The only new vertex of the offspring should be the newly created point.
[1172]525                                        current_copy1->vertices.push_back(new_point1);
526                                        current_copy2->vertices.push_back(new_point2);
[1186]527                                       
528                                        // This method guarantees that each polyhedron is already triangulated, therefore its triangulation
529                                        // is only one set of vertices and it is the set of all its vertices.
[1172]530                                        current_copy1->triangulations.push_back(current_copy1->vertices);
531                                        current_copy2->triangulations.push_back(current_copy2->vertices);
532                                       
[1186]533                                        // Now we have copied the polyhedron and we have to copy all of its relations. Because we are copying
534                                        // in the Hasse diagram from bottom up, we always have to copy the parent/child relations to all the
535                                        // kids and when we do that and know the child, in the child we will remember the parent we came from.
536                                        // This way all the parents/children relations are saved in both the parent and the child.
[1172]537                                        if(!(*horiz_ref)->kids_rel_addresses.empty())
[1171]538                                        {
[1172]539                                                for(vector<int>::iterator kid_ref = (*horiz_ref)->kids_rel_addresses.begin();kid_ref<(*horiz_ref)->kids_rel_addresses.end();kid_ref++)
[1186]540                                                {       
541                                                        // find the child and save the relation to the parent
542                                                        current_copy1->children.push_back(new_statistic1[j-1][(*kid_ref)]);
543                                                        current_copy2->children.push_back(new_statistic2[j-1][(*kid_ref)]);
[1171]544
[1186]545                                                        // in the child save the parents' address
546                                                        new_statistic1[j-1][(*kid_ref)]->parents.push_back(current_copy1);
547                                                        new_statistic2[j-1][(*kid_ref)]->parents.push_back(current_copy2);
[1172]548                                                }                                               
[1171]549
[1186]550                                                // Here we clear the parents kids_rel_addresses vector for later use (when we need to widen the
551                                                // Hasse diagram again)
[1172]552                                                (*horiz_ref)->kids_rel_addresses.clear();
[1171]553                                        }
[1186]554                                        // If there were no children previously, we are copying a polyhedron that has been a vertex before.
555                                        // In this case it is a segment now and it will have a relation to its mother (copywise) and to the
556                                        // newly created point. Here we create the connection to the new point, again from both sides.
[1171]557                                        else
558                                        {
[1186]559                                                // Add the address of the new point in the former vertex
[1172]560                                                current_copy1->children.push_back(new_point1);
561                                                current_copy2->children.push_back(new_point2);
[1171]562
[1186]563                                                // Add the address of the former vertex in the new point
[1172]564                                                new_point1->parents.push_back(current_copy1);
565                                                new_point2->parents.push_back(current_copy2);
[1171]566                                        }
567
[1186]568                                        // Save the mother in its offspring
[1172]569                                        current_copy1->children.push_back(*horiz_ref);
570                                        current_copy2->children.push_back(*horiz_ref);
[1171]571
[1186]572                                        // Save the offspring in its mother
573                                        (*horiz_ref)->parents.push_back(current_copy1);
574                                        (*horiz_ref)->parents.push_back(current_copy2); 
575                                                               
[1171]576                                       
[1186]577                                        // Add the copies into the relevant statistic. The statistic will later be appended to the previous
578                                        // Hasse diagram
579                                        new_statistic1[j].push_back(current_copy1);
580                                        new_statistic2[j].push_back(current_copy2);
581                                       
582                                        // Raise the count in the vector of polyhedrons
[1171]583                                        element_number++;
[1186]584                                       
[1172]585                                }                               
[1186]586                        }
587
588                        statistic[0].push_back(new_point1);
589                        statistic[0].push_back(new_point2);
590
591                        // Merge the new statistics into the old one. This will either be the final statistic or we will
592                        // reenter the widening loop.
593                        for(int j=0;j<new_statistic1.size();j++)
594                        {
595                                if(j+1==statistic.size())
596                                {
597                                        vector<polyhedron*> support;
598                                        statistic.push_back(support);
599                                }
600                               
601                                statistic[j+1].insert(statistic[j+1].end(),new_statistic1[j].begin(),new_statistic1[j].end());
602                                statistic[j+1].insert(statistic[j+1].end(),new_statistic2[j].begin(),new_statistic2[j].end());
603                        }
[1171]604                }
605        }
606
607
[976]608       
[1171]609       
[976]610};
611
612//! Robust Bayesian AR model for Multicriteria-Laplace-Inverse-Gamma density
[1204]613class RARX : public BM
614{
615private:
616
617        emlig posterior;
618
619public:
620        RARX():BM()
621        {
622        };
623
624        void bayes(const itpp::vec &yt, const itpp::vec &cond = empty_vec)
625        {
626               
627        }
628
[976]629};
630
631
632#endif //TRAGE_H
Note: See TracBrowser for help on using the browser.