graph_generator.cpp

Go to the documentation of this file.
00001 // $Id: graph_generator.cpp,v 1.6 2008/02/28 14:57:33 gottschling Exp $
00002 
00003 #include "angel/include/graph_generator.hpp"
00004 
00005 #include <vector>
00006 #include <cstdlib>
00007 #include <numeric>
00008 
00009 #include "angel/include/angel_exceptions.hpp"
00010 #include "angel/include/angel_types.hpp"
00011 #include "angel/include/angel_tools.hpp"
00012 
00013 #ifndef NDEBUG
00014 #include "angel/include/angel_io.hpp"
00015 #endif
00016 
00017 namespace angel {
00018 
00019 using namespace std;
00020 using namespace boost;
00021 
00022 // -------------------------------------------------------------------------
00023 
00024 void random_statement (int inputs, int expr, const vector<double>& p,
00025                        c_graph_t& statement) {
00026 
00027   typedef c_graph_t::vertex_t    vertex_t;
00028 
00029   int maxar= int (p.size()); // maximal arity of expressions
00030 
00031   // assert (inputs + expr - 1 <= expr * maxar); // all inputs usable
00032   throw_debug_exception (inputs + expr - 1 > expr * maxar, consistency_exception,
00033                          "Un-usable inputs");
00034   
00035 
00036   // how many inputs each expression shall have
00037   // (statement inputs have zero)
00038   int V= inputs + expr; // number of vertices
00039   vector<int> expi (V);
00040   for (int i= inputs; i < V; i++)
00041     expi[i]= angel::random (p) + 1;
00042 
00043   // if expression inputs aren't enough then p will be ignored, 
00044   // i.e. expi increased randomly
00045   for (int m= inputs + expr - 1 - accumulate (expi.begin(), expi.end(), 0);
00046        m > 0; m--)
00047     for (;;) {
00048       int e= angel::random (inputs, V-1);
00049       if (expi[e] < maxar) {expi[e]++; break; }}
00050 
00051   // build graph with last vertex as dependent
00052   vector<vertex_t> deps (1);
00053   deps[0]= V - 1;
00054   c_graph_t gtmp (V, inputs, deps);
00055   
00056   // random successor for each input and intermediate expr.
00057   for (int i= V - 2; i >= 0; i--) {
00058     vertex_t v= vertex (i, gtmp);
00059     for (;;) {
00060       int s= angel::random (max (i+1, inputs), V-1);
00061       vertex_t vs= vertex (s, gtmp);
00062       if (int (in_degree (vs, gtmp)) < expi[s]) {
00063         add_edge (v, vs, gtmp); break;}
00064     }}
00065 
00066   // if some expression desires more inputs 
00067   // then reuse statement inputs
00068   for (int i= inputs; i < V; i++) {
00069     vertex_t v= vertex (i, gtmp);
00070     for (; int (in_degree (v, gtmp)) < expi[i];) {
00071       int pr= angel::random (0, inputs-1);
00072       vertex_t vpr= vertex (pr, gtmp);
00073       // c_graph_t::edge_t e;
00074       // bool found;
00075       // boost::tie (e, found)= edge (vpr, v, gtmp);
00076       // if (!found) add_edge (vpr, v, gtmp);
00077       add_edge (vpr, v, gtmp); // double arcs allowed e.g. x*x
00078     }
00079   }
00080 
00081   statement.swap (gtmp);
00082 }
00083 
00084 // -------------------------------------------------------------------------
00085 
00086 void random_statement_vector (int max_expr, double unary, 
00087                               std::vector<c_graph_t>& statement_vector) {
00088   // assert (unary >= 0.0 && unary <= 1.0);
00089   throw_debug_exception (unary < 0.0 || unary > 1.0, consistency_exception,
00090                          "unary must be between 0 and 1"); 
00091   std::vector<double> p (2); // probabilities of arities
00092   p[0]= unary; p[1]= 1.0;
00093 
00094   // assert (statement_vector.size() > 0);
00095   throw_debug_exception (statement_vector.size() == 0, consistency_exception,
00096                          "statement vector must be non-empty"); 
00097   for (size_t i= 0; i < statement_vector.size(); i++) {
00098     int expr= angel::random (1, max_expr); // number of expr.
00099     // #inputs in [1, expr+1], average most probable, good for unary=0.5
00100     int inputs= (angel::random (expr) + angel::random (expr)) / 2 + 1;
00101     random_statement (inputs, expr, p, statement_vector[i]);
00102 #ifndef NDEBUG
00103     write_graph ("random_statement", statement_vector[i]);
00104 #endif
00105   }
00106 }
00107 
00108 // -------------------------------------------------------------------------
00109 
00110 void stats2block (int inputs, int outputs, const std::vector<c_graph_t>& stats, 
00111                   c_graph_t& block) {
00112   typedef c_graph_t::vertex_t          vertex_t;
00113   typedef c_graph_t::oei_t             oei_t;
00114 
00115   int nstats= int (stats.size());
00116   // assert (nstats >= outputs); // not more outputs than statements
00117   throw_debug_exception (nstats < outputs, consistency_exception,
00118                          "More outputs than statements"); 
00119 
00120 #ifndef NDEBUG
00121   for (int i= 0; i < nstats; i++) { // really statements ?
00122     const c_graph_t& stat= stats[i];
00123     // assert (stat.dependents.size() == 1);
00124     throw_debug_exception (stat.dependents.size() != 1, consistency_exception,
00125                            "Statements must have 1 output"); 
00126     // assert (stat.dependents[0] == vertex (stat.v()-1, stat)); 
00127     throw_debug_exception (stat.dependents[0] != vertex (stat.v()-1, stat), consistency_exception,
00128                            "Statements output must be last vertex"); }
00129 #endif
00130 
00131   int V= inputs; // number of vertices (in block)
00132   // difference of vertex number between block and statement
00133   vector<int> soffset (nstats); 
00134   for (int i= 0; i < nstats; i++) {
00135     soffset[i]= V - stats[i].x();
00136     V+= stats[i].v() - stats[i].x(); }
00137 
00138   // build graph without dependents
00139   vector<vertex_t> deps;
00140   c_graph_t gtmp (V, inputs, deps);
00141 
00142   // copy statements into block (without edges from statement inputs)
00143   int en= 0;
00144   for (int i= 0; i < nstats; i++) {
00145     const c_graph_t& stat= stats[i];
00146     int so= soffset[i];
00147     for (int iv= stat.x(); iv < stat.v(); iv++)
00148       take_over_successors (vertex (iv, stat), vertex (iv+so, gtmp), 
00149                             so, stat, en, gtmp); }
00150 
00151   // each output can be set to some statement output
00152   // since vertex 0 is always input it can be used to mark output as unset
00153   deps.resize (outputs); 
00154 
00155   // list of potential successors (each used once)
00156   // initialized with block outputs
00157   typedef pair<int,int> succ_t;
00158   vector<succ_t> sl;
00159   for (int i= 0; i < outputs; i++)
00160     sl.push_back (make_pair (-1, i));
00161 
00162   // find successor for each statement output 
00163   for (int i= nstats-1; i >= 0; i--) {
00164     vertex_t vb= vertex (soffset[i] + stats[i].v() - 1, gtmp); // stat. output
00165     int si= angel::random (int (sl.size()));
00166     succ_t succ= sl[si];
00167     int succs= succ.first, succi= succ.second;
00168     if (succs == -1)           // block output
00169       deps[succi]= vb;
00170     else {                     // statement input
00171       const c_graph_t& sstat= stats[succs];     // succ. statement
00172       vertex_t ivs= vertex (succi, sstat);       // input vertex in sstat
00173       // connect vb with successors of ivs (their equivalents in block)
00174       take_over_successors (ivs, vb, soffset[succs], sstat, en, gtmp);
00175     }
00176     // remove succ from list, maybe more efficient with index
00177     remove (sl.begin(), sl.end(), succ); sl.resize (sl.size()-1);
00178     // add current statement's input to successor list
00179     for (int j= 0; j < stats[i].x(); j++) 
00180       sl.push_back (make_pair (i, j));
00181   }
00182 
00183   // remaining outputs are assigned to some statement (not yet used as output)
00184   while (sl.size() > 0 && sl[0].first == -1) {
00185     int output= sl[0].second;
00186     // remove this output from successor list
00187     remove (sl.begin(), sl.end(), sl[0]); sl.resize (sl.size()-1);
00188     vertex_t vb;
00189     do {                                // find non-output statement
00190       int ss= angel::random (nstats);
00191       vb= vertex (soffset[ss] + stats[ss].v() - 1, gtmp); // stat. output
00192     } while (find (deps.begin(), deps.end(), vb) != deps.end());
00193     deps[output]= vb;
00194   }
00195 
00196   // each block input is unified with some free statement input
00197   for (int i= 0; i < inputs; i++) {
00198     // assert (sl.size() > 0); // enough free statement inputs ?
00199     throw_exception (sl.size() == 0, consistency_exception, "Not enough inputs"); 
00200     vertex_t vi= vertex (i, gtmp);
00201     succ_t succ= sl[angel::random (int (sl.size()))];
00202     int succs= succ.first, succi= succ.second;
00203     const c_graph_t& sstat= stats[succs];     // statement
00204     vertex_t ivs= vertex (succi, sstat);       // substituted vertex
00205     // connect block input with successors of ivs (their equivalents in block)
00206     take_over_successors (ivs, vi, soffset[succs], sstat, en, gtmp);
00207     // remove succ from list, maybe more efficient with index
00208     remove (sl.begin(), sl.end(), succ); sl.resize (sl.size()-1);
00209   }
00210 
00211   // remaining free statement inputs are unified 
00212   // with some block input or statement output (smaller statement)
00213   // potential predecessors stored in pl
00214   vector<vertex_t> pl;
00215   for (int i= 0; i < inputs; i++) {
00216     vertex_t v= vertex (i, gtmp); pl.push_back (v); }
00217   for (int i= 0; i < nstats; i++) {
00218     vertex_t v= vertex (soffset[i] + stats[i].v() - 1, gtmp); // stat. output
00219     pl.push_back (v); }
00220   while (sl.size() > 0) {
00221     succ_t succ= sl[sl.size()-1];              // last one easier to delete 
00222     int succs= succ.first, succi= succ.second;
00223     const c_graph_t& sstat= stats[succs];     // statement
00224     vertex_t ivs= vertex (succi, sstat);       // substituted vertex
00225     vertex_t vp= pl[angel::random (inputs+succs)];
00226     take_over_successors (ivs, vp, soffset[succs], sstat, en, gtmp);
00227     sl.resize (sl.size()-1);
00228   }
00229 
00230   gtmp.dependents.swap (deps);
00231 
00232   block.swap (gtmp);
00233 }
00234 
00235 // -------------------------------------------------------------------------
00236 
00237 void random_block (int inputs, int outputs, int stats, int max_exp, double unary,
00238                    c_graph_t& block) {
00239 
00240   std::vector<c_graph_t> statement_vector (stats);
00241   random_statement_vector (max_exp, unary, statement_vector);
00242   stats2block (inputs, outputs, statement_vector, block);
00243 
00244 }
00245 
00246 // -------------------------------------------------------------------------
00247 
00248 // will be confused if some vertex in block is both dependent and independent
00249 void block2loop (const c_graph_t& block, int loops,
00250                  c_graph_t& loop) {
00251 
00252 
00253   typedef c_graph_t::vertex_t vertex_t;
00254   typedef c_graph_t::oei_t    oei_t;
00255 
00256   // some vertex sizes
00257   int binputs= block.x(), boutputs= block.y(), bv= block.v(),
00258       linputs= binputs <= boutputs ? binputs : binputs + (loops-1)*(binputs-boutputs),
00259       // loutputs= binputs >= boutputs ? boutputs : boutputs + (loops-1)*(boutputs-binputs),
00260       isize= min (binputs, boutputs), // size of interface between blocks
00261       lv= loops * block.v() - (loops-1) * isize;
00262   vector<vertex_t> dependents;
00263   c_graph_t gtmp (lv, linputs, dependents);
00264 
00265   // input vertices of loop, initialized with input of block
00266   vector<vertex_t> input (binputs);
00267   for (int c= 0; c < binputs; c++) input[c]= c;
00268 
00269   // first block is simply copied
00270   int en= 0; // counter for edge_number
00271   c_graph_t::ei_t      ei, e_end;
00272   for (tie (ei, e_end)= edges (block); ei != e_end; ++ei)
00273     add_edge (source (*ei, block), target (*ei, block), en++, gtmp);
00274 
00275   for (int l= 1; l < loops; l++) {
00276     // vertex_t goffset= l * (lv - min (binputs, boutputs)); // first vertex in new block
00277     vertex_t goffset= l * (bv - isize), // corresponds to first vertex of new block in loop
00278              lgoffset= goffset - bv + isize;  // first vertex of previous block
00279 
00280     // unify output of last block with input of current block (first isize vertices resp.)
00281     for (int i= 0; i < isize; i++) {
00282       vertex_t bv= vertex (i, block); // vertex in block
00283       // vertex_t lv= vertex (lgoffset + block.dependents[i], gtmp);
00284       vertex_t lv= lgoffset + block.dependents[i]; // corresponds to vertex in loop
00285       oei_t      oei, oe_end;
00286       for (tie (oei, oe_end)= out_edges (bv, block); oei != oe_end; ++oei) {
00287         add_edge (lv, goffset + target (*oei, block), en++, gtmp); }
00288     }
00289 
00290     // look for loop inputs and outputs
00291     for (int i= isize; i < binputs; i++)
00292       input.push_back (goffset + vertex_t (i));
00293     for (int i= isize; i < boutputs; i++)
00294       dependents.push_back (lgoffset + block.dependents[i]);
00295 
00296     // copy the remainder of the block
00297     for (int i= isize; i < bv; i++) {
00298       vertex_t bv= vertex (i, block), // vertex in block
00299                lv= goffset + vertex_t (i);
00300       oei_t    oei, oe_end;
00301       for (tie (oei, oe_end)= out_edges (bv, block); oei != oe_end; ++oei) 
00302         add_edge (lv, vertex_t (goffset + target (*oei, block)), en++, gtmp);     
00303     }
00304   } 
00305   
00306   // output of last block is always output of loop
00307   vertex_t goffset= (loops - 1) * (bv - isize);
00308   for (int i= 0; i < boutputs; i++)
00309     dependents.push_back (goffset + block.dependents[i]);
00310 
00311   gtmp.X= int (input.size()); // will be used in independent_vertices_to_front
00312   gtmp.dependents.swap (dependents); 
00313 
00314   independent_vertices_to_front (gtmp, input, loop);
00315 
00316   // remove all vertices that do not lie on a path from independent 
00317   // to dependent nodes
00318   loop.clear_graph (); 
00319   loop.next_edge_number= renumber_edges (loop);
00320 }
00321 
00322 // Initializes the random generator unless SAME_RANDOM_VALUES is defined
00323 random_init_t random_init_object;
00324 
00325 } // namespace angel

Generated on Fri Dec 19 02:20:25 2008 for angel by  doxygen 1.5.7.1