diff --git a/C/c_interface.c b/C/c_interface.c index 4139474f1..eced2b059 100755 --- a/C/c_interface.c +++ b/C/c_interface.c @@ -334,6 +334,7 @@ #include "clause.h" #include "yapio.h" #include "attvar.h" +#include "SWI-Stream.h" #if HAVE_STDARG_H #include #endif @@ -458,6 +459,7 @@ X_API int STD_PROTO(YAP_GoalHasException,(Term *)); X_API void STD_PROTO(YAP_ClearExceptions,(void)); X_API int STD_PROTO(YAP_ContinueGoal,(void)); X_API void STD_PROTO(YAP_PruneGoal,(void)); +X_API IOSTREAM *STD_PROTO(YAP_TermToStream,(Term)); X_API IOSTREAM *STD_PROTO(YAP_InitConsult,(int, char *)); X_API void STD_PROTO(YAP_EndConsult,(IOSTREAM *)); X_API Term STD_PROTO(YAP_Read, (IOSTREAM *)); @@ -2488,6 +2490,22 @@ YAP_InitConsult(int mode, char *filename) return st; } +X_API IOSTREAM * +YAP_TermToStream(Term t) +{ + CACHE_REGS + IOSTREAM *s; + int rc; + BACKUP_MACHINE_REGS(); + + if ( (rc=PL_get_stream_handle(Yap_InitSlot(t PASS_REGS), &s)) ) { + RECOVER_MACHINE_REGS(); + return s; + } + RECOVER_MACHINE_REGS(); + return NULL; +} + X_API void YAP_EndConsult(IOSTREAM *s) { diff --git a/C/scanner.c b/C/scanner.c index c8fff39d9..6bb00e9db 100755 --- a/C/scanner.c +++ b/C/scanner.c @@ -854,6 +854,15 @@ Yap_tokenizer(IOSTREAM *inp_stream, Term *tposp) while (chtype(ch) == BS) { ch = getchr(inp_stream); } + if (ASP-H < 1024) { + Yap_ErrorMessage = "Stack Overflow"; + Yap_Error_TYPE = OUT_OF_STACK_ERROR; + Yap_Error_Size = 0L; + if (p) + p->Tok = Ord(kind = eot_tok); + /* serious error now */ + return l; + } *tposp = Yap_StreamPosition(inp_stream); } goto restart; @@ -1161,6 +1170,15 @@ Yap_tokenizer(IOSTREAM *inp_stream, Term *tposp) while (chtype(ch) == BS) { ch = getchr(inp_stream); } + if (ASP-H < 1024) { + Yap_ErrorMessage = "Stack Overflow"; + Yap_Error_TYPE = OUT_OF_STACK_ERROR; + Yap_Error_Size = 0L; + if (p) + p->Tok = Ord(kind = eot_tok); + /* serious error now */ + return l; + } *tposp = Yap_StreamPosition(inp_stream); } goto restart; diff --git a/console/LGPL/pl-ntmain.c b/console/LGPL/pl-ntmain.c index 3bdf34ab5..4505c4882 100755 --- a/console/LGPL/pl-ntmain.c +++ b/console/LGPL/pl-ntmain.c @@ -1035,6 +1035,7 @@ win32main(rlc_console c, int argc, TCHAR **argv) if ( !PL_initialise(argc, av) ) PL_halt(1); + rlc_bind_terminal(c); PL_halt(PL_toplevel() ? 0 : 1); return 0; @@ -1050,7 +1051,6 @@ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { LPTSTR cmdline; - fprintf(stderr,"Hello\n"); InitializeCriticalSection(&mutex); diff --git a/include/YapInterface.h b/include/YapInterface.h index ca720aab5..8ede58f0f 100755 --- a/include/YapInterface.h +++ b/include/YapInterface.h @@ -325,6 +325,9 @@ extern X_API int PROTO(YAP_Init,(YAP_init_args *)); /* int YAP_FastInit(const char *) */ extern X_API int PROTO(YAP_FastInit,(CONST char *)); +/* void * YAP_TermToStream(YAP_Term) */ +extern X_API void * PROTO(YAP_TermToStream,(YAP_Term)); + /* void * YAP_InitConsult(int, const char *) */ extern X_API void * PROTO(YAP_InitConsult,(int, CONST char *)); diff --git a/packages/CLPBN/Makefile.in b/packages/CLPBN/Makefile.in index 6eae7152b..c3cc626e7 100644 --- a/packages/CLPBN/Makefile.in +++ b/packages/CLPBN/Makefile.in @@ -51,7 +51,7 @@ CLPBN_PROGRAMS= \ $(CLPBN_SRCDIR)/table.yap \ $(CLPBN_SRCDIR)/topsort.yap \ $(CLPBN_SRCDIR)/utils.yap \ - $(CLPBN_SRCDIR)/vel.yap \ + $(CLPBN_SRCDIR)/ve.yap \ $(CLPBN_SRCDIR)/viterbi.yap \ $(CLPBN_SRCDIR)/xbif.yap diff --git a/packages/CLPBN/clpbn.yap b/packages/CLPBN/clpbn.yap index c28814f92..11e57eb45 100644 --- a/packages/CLPBN/clpbn.yap +++ b/packages/CLPBN/clpbn.yap @@ -7,6 +7,7 @@ clpbn_key/2, clpbn_init_solver/4, clpbn_run_solver/3, + clpbn_finalize_solver/1, clpbn_init_solver/5, clpbn_run_solver/4, clpbn_init_graph/1, @@ -28,13 +29,22 @@ :- attribute key/1, dist/2, evidence/1, starter/0. -:- use_module('clpbn/vel', - [vel/3, - check_if_vel_done/1, - init_vel_solver/4, - run_vel_solver/3 +:- use_module('clpbn/ve', + [ve/3, + check_if_ve_done/1, + init_ve_solver/4, + run_ve_solver/3 ]). +:- use_module('clpbn/bp', + [bp/3, + check_if_bp_done/1, + init_bp_solver/4, + run_bp_solver/3, + finalize_bp_solver/1 + ]). + + :- use_module('clpbn/jt', [jt/3, init_jt_solver/4, @@ -53,6 +63,14 @@ run_gibbs_solver/3 ]). +:- use_module('clpbn/bp', + [bp/3, + check_if_bp_done/1, + init_bp_solver/4, + run_bp_solver/3, + finalize_bp_solver/1 + ]). + :- use_module('clpbn/pgrammar', [init_pcg_solver/4, run_pcg_solver/3, @@ -92,8 +110,8 @@ :- dynamic solver/1,output/1,use/1,suppress_attribute_display/1, parameter_softening/1, em_solver/1. -solver(vel). -em_solver(vel). +solver(ve). +em_solver(ve). %output(xbif(user_error)). %output(gviz(user_error)). @@ -142,6 +160,18 @@ clpbn_flag(parameter_softening,Before,After) :- % ,writeln({Var = Key with Dist}) . +% +% make sure a query variable is reachable by the garbage collector. +% +store_var(El) :- + catch(b_getval(clpbn_qvars,Q.Tail), _, init_clpbn_vars(El, Q, Tail)), + Tail = [El|NewTail], + b_setval(clpbn_qvars, [Q|NewTail]). + +init_clpbn_vars(El, Q, Tail) :- + Q = [El|Tail], + b_setval(clpbn_qvars, [Q|Tail]). + check_constraint(Constraint, _, _, Constraint) :- var(Constraint), !. check_constraint((A->D), _, _, (A->D)) :- var(A), !. check_constraint((([A|B].L)->D), Vars, NVars, (([A|B].NL)->D)) :- !, @@ -162,8 +192,10 @@ add_evidence(V,Key,Distinfo,NV) :- nonvar(V), !, get_evidence_position(V, Distinfo, Pos), check_stored_evidence(Key, Pos), + store_var(NV), clpbn:put_atts(NV,evidence(Pos)). add_evidence(V,K,_,V) :- + store_var(V), add_evidence(K,V). clpbn_marginalise(V, Dist) :- @@ -183,7 +215,7 @@ project_attributes(GVars, AVars) :- clpbn_vars(AVars, DiffVars, AllVars), get_clpbn_vars(GVars,CLPBNGVars0), simplify_query_vars(CLPBNGVars0, CLPBNGVars), - (output(xbif(XBifStream)) -> clpbn2xbif(XBifStream,vel,AllVars) ; true), + (output(xbif(XBifStream)) -> clpbn2xbif(XBifStream,ve,AllVars) ; true), (output(gviz(XBifStream)) -> clpbn2gviz(XBifStream,sort,AllVars,GVars) ; true), ( Solver = graphs @@ -225,10 +257,12 @@ get_rid_of_ev_vars([V|LVs0],[V|LVs]) :- % do nothing if we don't have query variables to compute. write_out(graphs, _, AVars, _) :- clpbn2graph(AVars). -write_out(vel, GVars, AVars, DiffVars) :- - vel(GVars, AVars, DiffVars). +write_out(ve, GVars, AVars, DiffVars) :- + ve(GVars, AVars, DiffVars). write_out(jt, GVars, AVars, DiffVars) :- jt(GVars, AVars, DiffVars). +write_out(bp, GVars, AVars, DiffVars) :- + bp(GVars, AVars, DiffVars). write_out(gibbs, GVars, AVars, DiffVars) :- gibbs(GVars, AVars, DiffVars). write_out(bnt, GVars, AVars, DiffVars) :- @@ -315,11 +349,14 @@ bind_clpbn(_, Var, _, _, _, _, []) :- use(bnt), check_if_bnt_done(Var), !. bind_clpbn(_, Var, _, _, _, _, []) :- - use(vel), - check_if_vel_done(Var), !. + use(ve), + check_if_ve_done(Var), !. +bind_clpbn(_, Var, _, _, _, _, []) :- + use(bp), + check_if_bp_done(Var), !. bind_clpbn(_, Var, _, _, _, _, []) :- use(jt), - check_if_vel_done(Var), !. + check_if_ve_done(Var), !. bind_clpbn(T, Var, Key0, _, _, _, []) :- get_atts(Var, [key(Key)]), !, ( @@ -379,18 +416,21 @@ clpbn_key(Var,Key) :- % values at the end of the day. % clpbn_init_solver(LVs, Vs0, VarsWithUnboundKeys, State) :- - solver(Solver), + solver(Solver), clpbn_init_solver(Solver, LVs, Vs0, VarsWithUnboundKeys, State). clpbn_init_solver(gibbs, LVs, Vs0, VarsWithUnboundKeys, State) :- init_gibbs_solver(LVs, Vs0, VarsWithUnboundKeys, State). -clpbn_init_solver(vel, LVs, Vs0, VarsWithUnboundKeys, State) :- - init_vel_solver(LVs, Vs0, VarsWithUnboundKeys, State). +clpbn_init_solver(ve, LVs, Vs0, VarsWithUnboundKeys, State) :- + init_ve_solver(LVs, Vs0, VarsWithUnboundKeys, State). +clpbn_init_solver(bp, LVs, Vs0, VarsWithUnboundKeys, State) :- + init_bp_solver(LVs, Vs0, VarsWithUnboundKeys, State). clpbn_init_solver(jt, LVs, Vs0, VarsWithUnboundKeys, State) :- init_jt_solver(LVs, Vs0, VarsWithUnboundKeys, State). clpbn_init_solver(pcg, LVs, Vs0, VarsWithUnboundKeys, State) :- init_pcg_solver(LVs, Vs0, VarsWithUnboundKeys, State). + % % LVs is the list of lists of variables to marginalise % Vs is the full graph @@ -398,15 +438,21 @@ clpbn_init_solver(pcg, LVs, Vs0, VarsWithUnboundKeys, State) :- % % clpbn_run_solver(LVs, LPs, State) :- - solver(Solver), + solver(Solver), clpbn_run_solver(Solver, LVs, LPs, State). clpbn_run_solver(gibbs, LVs, LPs, State) :- run_gibbs_solver(LVs, LPs, State). -clpbn_run_solver(vel, LVs, LPs, State) :- - run_vel_solver(LVs, LPs, State). + +clpbn_run_solver(ve, LVs, LPs, State) :- + run_ve_solver(LVs, LPs, State). + +clpbn_run_solver(bp, LVs, LPs, State) :- + run_bp_solver(LVs, LPs, State). + clpbn_run_solver(jt, LVs, LPs, State) :- run_jt_solver(LVs, LPs, State). + clpbn_run_solver(pcg, LVs, LPs, State) :- run_pcg_solver(LVs, LPs, State). @@ -415,3 +461,10 @@ add_keys(Key1+V1,_Key2,Key1+V1). clpbn_init_graph(pcg) :- !, pcg_init_graph. clpbn_init_graph(_). + +clpbn_finalize_solver(State) :- + solver(bp), !, + functor(State, _, Last), + arg(Last, State, Info), + finalize_bp_solver(Info). +clpbn_finalize_solver(_State). diff --git a/packages/CLPBN/clpbn/aggregates.yap b/packages/CLPBN/clpbn/aggregates.yap index ed83ebb95..3c189756d 100644 --- a/packages/CLPBN/clpbn/aggregates.yap +++ b/packages/CLPBN/clpbn/aggregates.yap @@ -52,7 +52,7 @@ cpt_average(AllVars, Key, Els0, Tab, Vs, NewVs) :- cpt_average(AllVars, Key, Els0, 1.0, Tab, Vs, NewVs). % support variables with evidence from domain. This should make everyone's life easier. -cpt_average([Ev|Vars], Key, Els0, Softness, p(Els0, CPT, NewParents), Vs, NewVs) :- +cpt_average([Ev|Vars], Key, Els0, Softness, pf(Els0, MAT, NewParents), Vs, NewVs) :- find_evidence(Vars, 0, TotEvidence, RVars), build_avg_table(RVars, Vars, Els0, Key, TotEvidence, Softness, MAT0, NewParents0, Vs, IVs), include_qevidence(Ev, MAT0, MAT, NewParents0, NewParents, Vs, IVs, NewVs). diff --git a/packages/CLPBN/clpbn/bp.yap b/packages/CLPBN/clpbn/bp.yap index da4043a4f..417958298 100644 --- a/packages/CLPBN/clpbn/bp.yap +++ b/packages/CLPBN/clpbn/bp.yap @@ -1,157 +1,152 @@ -/*********************************** +/************************************************ Belief Propagation in CLP(BN) - - This should connect to C-code. -*********************************/ +**************************************************/ -:- module(clpbn_bp, [ - bp/3, - check_if_bp_done/1, - init_bp_solver/4, - run_bp_solver/3]). - - -:- use_module(library('clpbn/aggregates'), - [check_for_agg_vars/2]). - -:- use_module(library('clpbn/connected'), - [init_influences/3, - influences/5 +:- module(clpbn_bp, + [bp/3, + check_if_bp_done/1, + init_bp_solver/4, + run_bp_solver/3, + finalize_bp_solver/1 ]). + :- use_module(library('clpbn/dists'), [dist/4, get_dist_domain/2, + get_dist_domain_size/2, get_dist_params/2 ]). -:- use_module(library('clpbn/display'), - [clpbn_bind_vals/3]). -:-use_module(library(lists), - [append/3, - memberchk/2 - ]). +:- use_module(library('clpbn/display'), + [clpbn_bind_vals/3]). + + +:- use_module(library(atts)). + +:- use_module(library(charsio)). :- load_foreign_files(['horus'], [], init_predicates). -:- attribute all_diffs/1. +:- attribute id/1. + +:- dynamic num_bayes_nets/1. check_if_bp_done(_Var). -% -% implementation of belief propagation -% -% A1 = +QueryVars -> sets of independent marginalization variables -% A2 = *AllVars -> list of all variables -% A3 = -Output -> output probabilities -% -% Other important variables: -% -% State0 initialized graph, is used to pass data from initialization -% to query solving (eg, State might be the JT and be used to run -% different queries). -% +num_bayes_nets(0). + + bp([[]],_,_) :- !. -bp([QueryVars],AllVars,Output) :- - writeln(queryVars:QueryVars), - writeln(allVars:AllVars), - % init_bp_solver([QueryVars], AllVars, Output, State), - run_bp_solver([QueryVars], [AllVars], _State), - % bind probs back to variables so that they can be output. - clpbn_bind_vals([QueryVars],[LPs],Output). - -% initialise necessary data for query solver -init_bp_solver(Qs, AllVars, _, graph(LVis)) :- - % replace average, max, min and friends by binary nodes. - check_for_agg_vars(AllVars, UnFoldedVars), - % replace the variables reachable from G - init_influences(UnfoldedVars, G, RG), - init_bp_solver_for_questions(Qs, G, RG, _, LVis). - -init_bp_solver_for_questions([], _, _, [], []). -init_bp_solver_for_questions([Vs|MVs], G, RG, [NVs|MNVs0], [NVs|LVis]) :- - % find variables connectd to Vs - influences(Vs, _, NVs0, G, RG), - sort(NVs0, NVs), - init_bp_solver_for_questions(MVs, G, RG, MNVs0, LVis). +bp([QueryVars], AllVars, Output) :- + init_bp_solver(_, AllVars, _, BayesNet), + run_bp_solver([QueryVars], LPs, BayesNet), + finalize_bp_solver(BayesNet), + clpbn_bind_vals([QueryVars], LPs, Output). -% use a findall to recover space without needing for GC -run_bp_solver(LVs, LPs, _) :- - findall(Ps, solve_bp(LVs, LPs, Ps), LPs). +init_bp_solver(_, AllVars, _, (BayesNet, DistIds)) :- + %inc_num_bayes_nets, + %(showprofres(50) -> true ; true), + process_ids(AllVars, 0, DistIds0), + get_vars_info(AllVars, VarsInfo), + sort(DistIds0, DistIds), + %(num_bayes_nets(0) -> writeln(vars:VarsInfo) ; true), + %(num_bayes_nets(0) -> writeln(dists:DistsInfo) ; true), + create_network(VarsInfo, BayesNet). + %get_extra_vars_info(AllVars, ExtraVarsInfo), + %set_extra_vars_info(BayesNet, ExtraVarsInfo). + - -solve_bp([LVs|_], [NVs0|_], Ps) :- - get_vars_info(NVs0, LVi), - get_dists_info(NVs0, Dists), - process(LVi, Dists, LVs, Ps). -solve_bp([_|MoreLVs], [_|MoreLVis], Ps) :- - solve_bp(MoreLVs, MoreLVis, Ps). +process_ids([], _, []). +process_ids([V|Vs], VarId0, [DistId|DistIds]) :- + clpbn:get_atts(V, [dist(DistId, _)]), !, + put_atts(V, [id(VarId0)]), + VarId is VarId0 + 1, + process_ids(Vs, VarId, DistIds). +process_ids([_|Vs], VarId, DistIds) :- + process_ids(Vs, VarId, DistIds). get_vars_info([], []). -get_vars_info([V|Vs], [var(V, Id, Parents, NParents, Ev)|LV]) :- - clpbn:get_atts(V, [dist(Id, Parents)]), !, - length(Parents, NParents), +get_vars_info([V|Vs], [var(VarId, DSize, Ev, ParentIds, DistId)|VarsInfo]) :- + clpbn:get_atts(V, [dist(DistId, Parents)]), !, + get_atts(V, [id(VarId)]), + get_dist_domain_size(DistId, DSize), get_evidence(V, Ev), - get_vars_info(Vs, LV). -get_vars_info([_|Vs], LV) :- - get_vars_info(Vs, LV). + vars2ids(Parents, ParentIds), + get_vars_info(Vs, VarsInfo). +get_vars_info([_|Vs], VarsInfo) :- + get_vars_info(Vs, VarsInfo). + + +vars2ids([], []). +vars2ids([V|QueryVars], [VarId|Ids]) :- + get_atts(V, [id(VarId)]), + vars2ids(QueryVars, Ids). get_evidence(V, Ev) :- clpbn:get_atts(V, [evidence(Ev)]), !. -get_evidence(V, -1). % no evidence !!! +get_evidence(_V, -1). % no evidence !!! -get_dists_info([],[]). -get_dists_info([V|Vs], [dist(Id, Domain, DSize, Params, NParams) | Dists]) :- - clpbn:get_atts(V, [dist(Id, _)]), !, - get_dist_domain(Id, Domain), - length(Domain, DSize), +get_extra_vars_info([], []). +get_extra_vars_info([V|Vs], [v(VarId, Label, Domain)|VarsInfo]) :- + get_atts(V, [id(VarId)]), !, + clpbn:get_atts(V, [key(Key),dist(DistId, _)]), + term_to_atom(Key, Label), + get_dist_domain(DistId, Domain0), + numbers2atoms(Domain0, Domain), + get_extra_vars_info(Vs, VarsInfo). +get_extra_vars_info([_|Vs], VarsInfo) :- + get_extra_vars_info(Vs, VarsInfo). + + +numbers2atoms([], []). +numbers2atoms([Atom|L0], [Atom|L]) :- + atom(Atom), !, + numbers2atoms(L0, L). +numbers2atoms([Number|L0], [Atom|L]) :- + number_atom(Number, Atom), + numbers2atoms(L0, L). + + +run_bp_solver(QVsL0, LPs, (BayesNet, DistIds)) :- + get_dists_parameters(DistIds, DistsParams), + set_parameters(BayesNet, DistsParams), + process_query_list(QVsL0, QVsL), + %writeln(' qvs':QVsL), + %(num_bayes_nets(1506) -> writeln(qvs:QVsL) ; true), + run_solver(BayesNet, QVsL, LPs). + + +process_query_list([], []). +process_query_list([[V]|QueryVars], [VarId|Ids]) :- !, + get_atts(V, [id(VarId)]), + process_query_list(QueryVars, Ids). +process_query_list([Vs|QueryVars], [VarIds|Ids]) :- + vars2ids(Vs, VarIds), + process_query_list(QueryVars, Ids). + + +get_dists_parameters([],[]). +get_dists_parameters([Id|Ids], [dist(Id, Params)|DistsInfo]) :- get_dist_params(Id, Params), - length(Params, NParams), - get_dists_info(Vs, Dists). -get_dists_info([_|Vs], Dists) :- - get_dists_info(Vs, Dists). + get_dists_parameters(Ids, DistsInfo). -% +Vars is a list containing info about every clpbn variables -% +Dists is a list containing info about distributions -% +QVs is a list containing the query variables -% -Out is some output term stating the probabilities -process(Vars, Dists, QVs, Out) :- - write('vars = '), writeln(Vars), - order_vars(Vars, [], OrderedVars), - write('ovars = '), writeln(OrderedVars), - write('dists = '), writeln(Dists), - write('qvs = '), writeln(QVs), - length(OrderedVars, NVars), - length(Dists, NDists), - %create_network(OrderedVars, NVars, Dists, NDists, BNet), - length(QVs, NQVs), - run_solver(BNet, QVs, NQVs, Out), - free_memory(BNet). +finalize_bp_solver((BayesNet, _)) :- + delete_bayes_net(BayesNet). -order_vars([V], _, [V]) :- !. -order_vars([var(V, Id, Parents, NParents, Ev)|Vs], ParsedVars, [var(V, Id, Parents, NParents, Ev)|OrderedVars]) :- - \+ memberchk(V, ParsedVars), - parents_defined(Parents, ParsedVars), !, - order_vars(Vs, [V|ParsedVars], OrderedVars). -order_vars([var(V, Id, Parents, NParents, Ev)|Vs], ParsedVars, OrderedVars) :- - append(Vs, [var(V, Id, Parents, NParents, Ev)], NVs), - order_vars(NVs, ParsedVars, OrderedVars). +inc_num_bayes_nets :- + retract(num_bayes_nets(Count0)), + Count is Count0 + 1, + assert(num_bayes_nets(Count)). - -parents_defined([], _) :- !. -parents_defined([Parent|Parents], ParsedVars) :- - memberchk(Parent, ParsedVars), - parents_defined(Parents, ParsedVars). - -% f(F), b(B). ----> FAIL diff --git a/packages/CLPBN/clpbn/bp/BPSolver.cpp b/packages/CLPBN/clpbn/bp/BPSolver.cpp new file mode 100755 index 000000000..1d3566aa8 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BPSolver.cpp @@ -0,0 +1,891 @@ +#include +#include +#include +#include +#include +#include + +#include "BPSolver.h" +#include "BpNode.h" + + +BPSolver* Edge::klass = 0; +StatisticMap Statistics::stats_; +unsigned Statistics::numCreatedNets = 0; +unsigned Statistics::numSolvedPolyTrees = 0; +unsigned Statistics::numSolvedLoopyNets = 0; +unsigned Statistics::numUnconvergedRuns = 0; +unsigned Statistics::maxIterations = 0; +unsigned Statistics::totalOfIterations = 0; + + +BPSolver::BPSolver (const BayesNet& bn) : Solver (&bn) +{ + bn_ = &bn; + forceGenericSolver_ = false; + //forceGenericSolver_ = true; + schedule_ = S_SEQ_FIXED; + //schedule_ = S_SEQ_RANDOM; + //schedule_ = S_PARALLEL; + //schedule_ = S_MAX_RESIDUAL; + maxIter_ = 205; + accuracy_ = 0.000001; +} + + + +BPSolver::~BPSolver (void) +{ + for (unsigned i = 0; i < msgs_.size(); i++) { + delete msgs_[i]; + } +} + + + +void +BPSolver::runSolver (void) +{ + if (DL >= 1) { + //bn_->printNetwork(); + } + + clock_t start_ = clock(); + if (bn_->isSingleConnected() && !forceGenericSolver_) { + runPolyTreeSolver(); + Statistics::numSolvedPolyTrees ++; + } else { + runGenericSolver(); + Statistics::numSolvedLoopyNets ++; + if (nIter_ >= maxIter_) { + Statistics::numUnconvergedRuns ++; + } else { + Statistics::updateIterations (nIter_); + } + if (DL >= 1) { + cout << endl; + if (nIter_ < maxIter_) { + cout << "Belief propagation converged in " ; + cout << nIter_ << " iterations" << endl; + } else { + cout << "The maximum number of iterations was hit, terminating..." ; + cout << endl; + } + } + } + double time = (double (clock() - start_)) / CLOCKS_PER_SEC; + unsigned size = bn_->getNumberOfNodes(); + Statistics::updateStats (size, time); + //if (size > 30) { + // stringstream ss; + // ss << size << "." << Statistics::getCounting (size) << ".dot" ; + // bn_->exportToDotFile (ss.str().c_str()); + //} +} + + + +ParamSet +BPSolver::getPosterioriOf (const Variable* var) const +{ + assert (var); + assert (var == bn_->getNode (var->getVarId())); + assert (var->getIndex() < msgs_.size()); + return msgs_[var->getIndex()]->getBeliefs(); +} + + + + +ParamSet +BPSolver::getJointDistribution (const NodeSet& jointVars) const +{ + if (DL >= 1) { + cout << "calculating joint distribuition on: " ; + for (unsigned i = 0; i < jointVars.size(); i++) { + cout << jointVars[i]->getLabel() << " " ; + } + cout << endl; + } + + //BayesNet* workingNet = bn_->pruneNetwork (bn_->getNodes()); + //FIXME see if this works: + BayesNet* workingNet = bn_->pruneNetwork (jointVars); + BayesNode* node = workingNet->getNode (jointVars[0]->getVarId()); + + BayesNet* tempNet = workingNet->pruneNetwork (node); + BPSolver solver (*tempNet); + solver.runSolver(); + + NodeSet observedVars = { jointVars[0] }; + + node = tempNet->getNode (jointVars[0]->getVarId()); + ParamSet prevBeliefs = solver.getPosterioriOf (node); + + delete tempNet; + + for (unsigned i = 1; i < jointVars.size(); i++) { + node = workingNet->getNode (observedVars[i - 1]->getVarId()); + if (!node->hasEvidence()) { + node->setEvidence (0); + } + node = workingNet->getNode (jointVars[i]->getVarId()); + tempNet = workingNet->pruneNetwork (node); + + ParamSet allBeliefs; + vector confs = + BayesNet::getDomainConfigurationsOf (observedVars); + for (unsigned j = 0; j < confs.size(); j++) { + for (unsigned k = 0; k < observedVars.size(); k++) { + node = tempNet->getNode (observedVars[k]->getVarId()); + if (!observedVars[k]->hasEvidence()) { + if (node) { + node->setEvidence (confs[j][k]); + } else { + // FIXME try optimize + //assert (false); + cout << observedVars[k]->getLabel(); + cout << " is not in temporary net!" ; + cout << endl; + } + } else { + cout << observedVars[k]->getLabel(); + cout << " already has evidence in original net!" ; + cout << endl; + } + } + BPSolver solver (*tempNet); + node = tempNet->getNode (jointVars[i]->getVarId()); + solver.runSolver(); + ParamSet beliefs = solver.getPosterioriOf (node); + for (unsigned k = 0; k < beliefs.size(); k++) { + allBeliefs.push_back (beliefs[k]); + } + } + + int count = -1; + for (unsigned j = 0; j < allBeliefs.size(); j++) { + if (j % jointVars[i]->getDomainSize() == 0) { + count ++; + } + allBeliefs[j] *= prevBeliefs[count]; + } + prevBeliefs = allBeliefs; + observedVars.push_back (jointVars[i]); + delete tempNet; + } + delete workingNet; + return prevBeliefs; +} + + + +void +BPSolver::initializeSolver (void) +{ + if (DL >= 1) { + cout << "Initializing solver" << endl; + cout << "-> schedule = "; + if (forceGenericSolver_) { + switch (schedule_) { + case S_SEQ_FIXED: cout << "sequential fixed" ; break; + case S_SEQ_RANDOM: cout << "sequential random" ; break; + case S_PARALLEL: cout << "parallel" ; break; + case S_MAX_RESIDUAL: cout << "max residual" ; break; + } + } else { + cout << "polytree solver" ; + } + cout << endl; + cout << "-> max iters = " << maxIter_ << endl; + cout << "-> accuracy = " << accuracy_ << endl; + cout << endl; + } + + const NodeSet& nodes = bn_->getNodes(); + for (unsigned i = 0; i < msgs_.size(); i++) { + delete msgs_[i]; + } + msgs_.clear(); + msgs_.reserve (nodes.size()); + updateOrder_.clear(); + sortedOrder_.clear(); + edgeMap_.clear(); + + for (unsigned i = 0; i < nodes.size(); i++) { + msgs_.push_back (new BpNode (nodes[i])); + } + + NodeSet roots = bn_->getRootNodes(); + for (unsigned i = 0; i < roots.size(); i++) { + const ParamSet& params = roots[i]->getParameters(); + ParamSet& piVals = M(roots[i])->getPiValues(); + for (int ri = 0; ri < roots[i]->getDomainSize(); ri++) { + piVals[ri] = params[ri]; + } + } +} + + + +void +BPSolver::incorporateEvidence (BayesNode* x) +{ + ParamSet& piVals = M(x)->getPiValues(); + ParamSet& ldVals = M(x)->getLambdaValues(); + for (int xi = 0; xi < x->getDomainSize(); xi++) { + piVals[xi] = 0.0; + ldVals[xi] = 0.0; + } + piVals[x->getEvidence()] = 1.0; + ldVals[x->getEvidence()] = 1.0; +} + + + +void +BPSolver::runPolyTreeSolver (void) +{ + initializeSolver(); + const NodeSet& nodes = bn_->getNodes(); + + // Hack: I need this else this can happen with bayes ball + // Variable: 174 + // Id: 174 + // Domain: -1, 0, 1 + // Evidence: 1 + // Parents: + // Childs: 176 + // cpt + // ---------------------------------------------------- + // -1 0 0 0 0 ... + // 0 0.857143 0.857143 0.857143 0.857143 ... + // 1 0.142857 0.142857 0.142857 0.142857 ... + // the cpt for this node would be 0,0,0 + + for (unsigned i = 0; i < nodes.size(); i++) { + if (nodes[i]->hasEvidence()) { + incorporateEvidence (nodes[i]); + } + } + + // first compute all node marginals ... + NodeSet roots = bn_->getRootNodes(); + for (unsigned i = 0; i < roots.size(); i++) { + const NodeSet& childs = roots[i]->getChilds(); + for (unsigned j = 0; j < childs.size(); j++) { + polyTreePiMessage (roots[i], childs[j]); + } + } + // then propagate the evidence + for (unsigned i = 0; i < nodes.size(); i++) { + if (nodes[i]->hasEvidence()) { + incorporateEvidence (nodes[i]); + const NodeSet& parents = nodes[i]->getParents(); + for (unsigned j = 0; j < parents.size(); j++) { + if (!parents[j]->hasEvidence()) { + polyTreeLambdaMessage (nodes[i], parents[j]); + } + } + const NodeSet& childs = nodes[i]->getChilds(); + for (unsigned j = 0; j < childs.size(); j++) { + polyTreePiMessage (nodes[i], childs[j]); + } + } + } +} + + + +void +BPSolver::polyTreePiMessage (BayesNode* z, BayesNode* x) +{ + if (DL >= 1) { + cout << PI << " (" << z->getLabel(); + cout << " --> " << x->getLabel(); + cout << ")" << endl; + } + calculateNextPiMessage (z, x); + updatePiMessage (z, x); + + if (!x->hasEvidence()) { + updatePiValues (x); + const NodeSet& xChilds = x->getChilds(); + for (unsigned i = 0; i < xChilds.size(); i++) { + polyTreePiMessage (x, xChilds[i]); + } + } + + if (M(x)->hasReceivedChildInfluence()) { + const NodeSet& xParents = x->getParents(); + for (unsigned i = 0; i < xParents.size(); i++) { + if (xParents[i] != z && !xParents[i]->hasEvidence()) { + polyTreeLambdaMessage (x, xParents[i]); + } + } + } +} + + + +void +BPSolver::polyTreeLambdaMessage (BayesNode* y, BayesNode* x) +{ + if (DL >= 1) { + cout << LD << " (" << y->getLabel(); + cout << " --> " << x->getLabel(); + cout << ")" << endl; + } + calculateNextLambdaMessage (y, x); + updateLambdaMessage (y, x); + updateLambdaValues (x); + + const NodeSet& xParents = x->getParents(); + for (unsigned i = 0; i < xParents.size(); i++) { + if (!xParents[i]->hasEvidence()) { + polyTreeLambdaMessage (x, xParents[i]); + } + } + + const NodeSet& xChilds = x->getChilds(); + for (unsigned i = 0; i < xChilds.size(); i++) { + if (xChilds[i] != y) { + polyTreePiMessage (x, xChilds[i]); + } + } +} + + + +void +BPSolver::runGenericSolver() +{ + initializeSolver(); + const NodeSet& nodes = bn_->getNodes(); + for (unsigned i = 0; i < nodes.size(); i++) { + if (nodes[i]->hasEvidence()) { + incorporateEvidence (nodes[i]); + } + } + + for (unsigned i = 0; i < nodes.size(); i++) { + // pi messages + const NodeSet& childs = nodes[i]->getChilds(); + for (unsigned j = 0; j < childs.size(); j++) { + updateOrder_.push_back (Edge (nodes[i], childs[j], PI_MSG)); + } + // lambda messages + const NodeSet& parents = nodes[i]->getParents(); + for (unsigned j = 0; j < parents.size(); j++) { + if (!parents[j]->hasEvidence()) { + updateOrder_.push_back (Edge (nodes[i], parents[j], LAMBDA_MSG)); + } + } + } + + nIter_ = 0; + while (!converged() && nIter_ < maxIter_) { + + nIter_++; + if (DL >= 1) { + cout << endl; + cout << "****************************************" ; + cout << "****************************************" ; + cout << endl; + cout << " Iteration " << nIter_ << endl; + cout << "****************************************" ; + cout << "****************************************" ; + cout << endl; + } + + switch (schedule_) { + + case S_SEQ_RANDOM: + random_shuffle (updateOrder_.begin(), updateOrder_.end()); + // no break + + case S_SEQ_FIXED: + for (unsigned i = 0; i < updateOrder_.size(); i++) { + calculateNextMessage (updateOrder_[i]); + updateMessage (updateOrder_[i]); + updateValues (updateOrder_[i]); + } + break; + + case S_PARALLEL: + for (unsigned i = 0; i < updateOrder_.size(); i++) { + calculateNextMessage (updateOrder_[i]); + } + for (unsigned i = 0; i < updateOrder_.size(); i++) { + updateMessage (updateOrder_[i]); + updateValues (updateOrder_[i]); + } + break; + + case S_MAX_RESIDUAL: + maxResidualSchedule(); + break; + + } + } +} + + + +void +BPSolver::maxResidualSchedule (void) +{ + if (nIter_ == 1) { + Edge::klass = this; + for (unsigned i = 0; i < updateOrder_.size(); i++) { + calculateNextMessage (updateOrder_[i]); + updateResidual (updateOrder_[i]); + SortedOrder::iterator it = sortedOrder_.insert (updateOrder_[i]); + edgeMap_.insert (make_pair (updateOrder_[i].getId(), it)); + } + return; + } + + for (unsigned c = 0; c < sortedOrder_.size(); c++) { + if (DL >= 1) { + for (set::iterator it = sortedOrder_.begin(); + it != sortedOrder_.end(); it ++) { + cout << it->toString() << " residual = " ; + cout << getResidual (*it) << endl; + } + } + + set::iterator it = sortedOrder_.begin(); + Edge e = *it; + if (getResidual (e) < accuracy_) { + return; + } + updateMessage (e); + updateValues (e); + clearResidual (e); + sortedOrder_.erase (it); + assert (edgeMap_.find (e.getId()) != edgeMap_.end()); + edgeMap_.find (e.getId())->second = sortedOrder_.insert (e); + + // update the messages that depend on message source --> destination + const NodeSet& childs = e.destination->getChilds(); + for (unsigned i = 0; i < childs.size(); i++) { + if (childs[i] != e.source) { + Edge neighbor (e.destination, childs[i], PI_MSG); + calculateNextMessage (neighbor); + updateResidual (neighbor); + assert (edgeMap_.find (neighbor.getId()) != edgeMap_.end()); + EdgeMap::iterator iter = edgeMap_.find (neighbor.getId()); + sortedOrder_.erase (iter->second); + iter->second = sortedOrder_.insert (neighbor); + } + } + const NodeSet& parents = e.destination->getParents(); + for (unsigned i = 0; i < parents.size(); i++) { + if (parents[i] != e.source && !parents[i]->hasEvidence()) { + Edge neighbor (e.destination, parents[i], LAMBDA_MSG); + calculateNextMessage (neighbor); + updateResidual (neighbor); + assert (edgeMap_.find (neighbor.getId()) != edgeMap_.end()); + EdgeMap::iterator iter = edgeMap_.find (neighbor.getId()); + sortedOrder_.erase (iter->second); + iter->second = sortedOrder_.insert (neighbor); + } + } + } +} + + + +bool +BPSolver::converged (void) const +{ + bool converged = true; + if (schedule_ == S_MAX_RESIDUAL) { + if (nIter_ <= 2) { + return false; + } + // this can happen if every node does not have neighbors + if (sortedOrder_.size() == 0) { + return true; + } + Param maxResidual = getResidual (*(sortedOrder_.begin())); + if (maxResidual > accuracy_) { + return false; + } + } else { + if (nIter_ == 0) { + return false; + } + const NodeSet& nodes = bn_->getNodes(); + for (unsigned i = 0; i < nodes.size(); i++) { + if (!nodes[i]->hasEvidence()) { + double change = M(nodes[i])->getBeliefChange(); + if (DL >= 1) { + cout << nodes[i]->getLabel() + " belief change = " ; + cout << change << endl; + } + if (change > accuracy_) { + converged = false; + if (DL == 0) break; + } + } + } + } + + return converged; +} + + + +void +BPSolver::updatePiValues (BayesNode* x) +{ + // π(Xi) + const NodeSet& parents = x->getParents(); + const vector& entries = x->getCptEntries(); + assert (parents.size() != 0); + stringstream* calcs1; + stringstream* calcs2; + + ParamSet messageProducts (entries.size()); + for (unsigned k = 0; k < entries.size(); k++) { + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + } + double messageProduct = 1.0; + const DomainConf& conf = entries[k].getParentConfigurations(); + for (unsigned i = 0; i < parents.size(); i++) { + messageProduct *= M(parents[i])->getPiMessageValue(x, conf[i]); + if (DL >= 5) { + if (i != 0) *calcs1 << "." ; + if (i != 0) *calcs2 << "*" ; + *calcs1 << PI << "(" << x->getLabel() << ")" ; + *calcs1 << "[" << parents[i]->getDomain()[conf[i]] << "]"; + *calcs2 << M(parents[i])->getPiMessageValue(x, conf[i]); + } + } + messageProducts[k] = messageProduct; + if (DL >= 5) { + cout << " mp" << k; + cout << " = " << (*calcs1).str(); + if (parents.size() == 1) { + cout << " = " << messageProduct << endl; + } else { + cout << " = " << (*calcs2).str(); + cout << " = " << messageProduct << endl; + } + delete calcs1; + delete calcs2; + } + } + + for (int xi = 0; xi < x->getDomainSize(); xi++) { + double sum = 0.0; + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + } + for (unsigned k = 0; k < entries.size(); k++) { + sum += x->getProbability (xi, entries[k]) * messageProducts[k]; + if (DL >= 5) { + if (k != 0) *calcs1 << " + " ; + if (k != 0) *calcs2 << " + " ; + *calcs1 << x->cptEntryToString (xi, entries[k]); + *calcs1 << ".mp" << k; + *calcs2 << x->getProbability (xi, entries[k]); + *calcs2 << "*" << messageProducts[k]; + } + } + M(x)->setPiValue (xi, sum); + if (DL >= 5) { + cout << " " << PI << "(" << x->getLabel() << ")" ; + cout << "[" << x->getDomain()[xi] << "]" ; + cout << " = " << (*calcs1).str(); + cout << " = " << (*calcs2).str(); + cout << " = " << sum << endl; + delete calcs1; + delete calcs2; + } + } +} + + + +void +BPSolver::updateLambdaValues (BayesNode* x) +{ + // λ(Xi) + const NodeSet& childs = x->getChilds(); + assert (childs.size() != 0); + stringstream* calcs1; + stringstream* calcs2; + + for (int xi = 0; xi < x->getDomainSize(); xi++) { + double product = 1.0; + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + } + for (unsigned i = 0; i < childs.size(); i++) { + product *= M(x)->getLambdaMessageValue(childs[i], xi); + if (DL >= 5) { + if (i != 0) *calcs1 << "." ; + if (i != 0) *calcs2 << "*" ; + *calcs1 << LD << "(" << childs[i]->getLabel(); + *calcs1 << "-->" << x->getLabel() << ")" ; + *calcs1 << "[" << x->getDomain()[xi] << "]" ; + *calcs2 << M(x)->getLambdaMessageValue(childs[i], xi); + } + } + M(x)->setLambdaValue (xi, product); + if (DL >= 5) { + cout << " " << LD << "(" << x->getLabel() << ")" ; + cout << "[" << x->getDomain()[xi] << "]" ; + cout << " = " << (*calcs1).str(); + if (childs.size() == 1) { + cout << " = " << product << endl; + } else { + cout << " = " << (*calcs2).str(); + cout << " = " << product << endl; + } + delete calcs1; + delete calcs2; + } + } +} + + + +void +BPSolver::calculateNextPiMessage (BayesNode* z, BayesNode* x) +{ + // πX(Zi) + ParamSet& zxPiNextMessage = M(z)->piNextMessageReference (x); + const NodeSet& zChilds = z->getChilds(); + stringstream* calcs1; + stringstream* calcs2; + + for (int zi = 0; zi < z->getDomainSize(); zi++) { + double product = M(z)->getPiValue (zi); + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + *calcs1 << PI << "(" << z->getLabel() << ")"; + *calcs1 << "[" << z->getDomain()[zi] << "]" ; + *calcs2 << product; + } + for (unsigned i = 0; i < zChilds.size(); i++) { + if (zChilds[i] != x) { + product *= M(z)->getLambdaMessageValue(zChilds[i], zi); + if (DL >= 5) { + *calcs1 << "." << LD << "(" << zChilds[i]->getLabel(); + *calcs1 << "-->" << z->getLabel() << ")"; + *calcs1 << "[" << z->getDomain()[zi] + "]" ; + *calcs2 << " * " << M(z)->getLambdaMessageValue(zChilds[i], zi); + } + } + } + zxPiNextMessage[zi] = product; + if (DL >= 5) { + cout << " " << PI << "(" << z->getLabel(); + cout << "-->" << x->getLabel() << ")" ; + cout << "[" << z->getDomain()[zi] << "]" ; + cout << " = " << (*calcs1).str(); + if (zChilds.size() == 1) { + cout << " = " << product << endl; + } else { + cout << " = " << (*calcs2).str(); + cout << " = " << product << endl; + } + delete calcs1; + delete calcs2; + } + } +} + + + +void +BPSolver::calculateNextLambdaMessage (BayesNode* y, BayesNode* x) +{ + // λY(Xi) + //if (!y->hasEvidence() && !M(y)->hasReceivedChildInfluence()) { + // if (DL >= 5) { + // cout << "unnecessary calculation" << endl; + // } + // return; + //} + ParamSet& yxLambdaNextMessage = M(x)->lambdaNextMessageReference (y); + const NodeSet& yParents = y->getParents(); + const vector& allEntries = y->getCptEntries(); + int parentIndex = y->getIndexOfParent (x); + stringstream* calcs1; + stringstream* calcs2; + + vector entries; + DomainConstr constr = make_pair (parentIndex, 0); + for (unsigned i = 0; i < allEntries.size(); i++) { + if (allEntries[i].matchConstraints(constr)) { + entries.push_back (allEntries[i]); + } + } + + ParamSet messageProducts (entries.size()); + for (unsigned k = 0; k < entries.size(); k++) { + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + } + double messageProduct = 1.0; + const DomainConf& conf = entries[k].getParentConfigurations(); + for (unsigned i = 0; i < yParents.size(); i++) { + if (yParents[i] != x) { + if (DL >= 5) { + if (messageProduct != 1.0) *calcs1 << "*" ; + if (messageProduct != 1.0) *calcs2 << "*" ; + *calcs1 << PI << "(" << yParents[i]->getLabel(); + *calcs1 << "-->" << y->getLabel() << ")" ; + *calcs1 << "[" << yParents[i]->getDomain()[conf[i]] << "]" ; + *calcs2 << M(yParents[i])->getPiMessageValue(y, conf[i]); + } + messageProduct *= M(yParents[i])->getPiMessageValue(y, conf[i]); + } + } + messageProducts[k] = messageProduct; + if (DL >= 5) { + cout << " mp" << k; + cout << " = " << (*calcs1).str(); + if (yParents.size() == 1) { + cout << 1 << endl; + } else if (yParents.size() == 2) { + cout << " = " << messageProduct << endl; + } else { + cout << " = " << (*calcs2).str(); + cout << " = " << messageProduct << endl; + } + delete calcs1; + delete calcs2; + } + } + + for (int xi = 0; xi < x->getDomainSize(); xi++) { + if (DL >= 5) { + calcs1 = new stringstream; + calcs2 = new stringstream; + } + vector entries; + DomainConstr constr = make_pair (parentIndex, xi); + for (unsigned i = 0; i < allEntries.size(); i++) { + if (allEntries[i].matchConstraints(constr)) { + entries.push_back (allEntries[i]); + } + } + double outerSum = 0.0; + for (int yi = 0; yi < y->getDomainSize(); yi++) { + if (DL >= 5) { + (yi != 0) ? *calcs1 << " + {" : *calcs1 << "{" ; + (yi != 0) ? *calcs2 << " + {" : *calcs2 << "{" ; + } + double innerSum = 0.0; + for (unsigned k = 0; k < entries.size(); k++) { + if (DL >= 5) { + if (k != 0) *calcs1 << " + " ; + if (k != 0) *calcs2 << " + " ; + *calcs1 << y->cptEntryToString (yi, entries[k]); + *calcs1 << ".mp" << k; + *calcs2 << y->getProbability (yi, entries[k]); + *calcs2 << "*" << messageProducts[k]; + } + innerSum += y->getProbability (yi, entries[k]) * messageProducts[k]; + } + outerSum += innerSum * M(y)->getLambdaValue (yi); + if (DL >= 5) { + *calcs1 << "}." << LD << "(" << y->getLabel() << ")" ; + *calcs1 << "[" << y->getDomain()[yi] << "]"; + *calcs2 << "}*" << M(y)->getLambdaValue (yi); + } + } + yxLambdaNextMessage[xi] = outerSum; + if (DL >= 5) { + cout << " " << LD << "(" << y->getLabel(); + cout << "-->" << x->getLabel() << ")" ; + cout << "[" << x->getDomain()[xi] << "]" ; + cout << " = " << (*calcs1).str(); + cout << " = " << (*calcs2).str(); + cout << " = " << outerSum << endl; + delete calcs1; + delete calcs2; + } + } +} + + + +void +BPSolver::printMessageStatusOf (const BayesNode* var) const +{ + cout << left; + cout << setw (10) << "domain" ; + cout << setw (20) << PI << "(" + var->getLabel() + ")" ; + cout << setw (20) << LD << "(" + var->getLabel() + ")" ; + cout << setw (16) << "belief" ; + cout << endl; + cout << "--------------------------------" ; + cout << "--------------------------------" ; + cout << endl; + + BpNode* x = M(var); + ParamSet& piVals = x->getPiValues(); + ParamSet& ldVals = x->getLambdaValues(); + ParamSet beliefs = x->getBeliefs(); + const Domain& domain = var->getDomain(); + const NodeSet& childs = var->getChilds(); + + for (int xi = 0; xi < var->getDomainSize(); xi++) { + cout << setw (10) << domain[xi]; + cout << setw (19) << piVals[xi]; + cout << setw (19) << ldVals[xi]; + cout.precision (PRECISION); + cout << setw (16) << beliefs[xi]; + cout << endl; + } + cout << endl; + if (childs.size() > 0) { + string s = "(" + var->getLabel() + ")" ; + for (unsigned j = 0; j < childs.size(); j++) { + cout << setw (10) << "domain" ; + cout << setw (28) << PI + childs[j]->getLabel() + s; + cout << setw (28) << LD + childs[j]->getLabel() + s; + cout << endl; + cout << "--------------------------------" ; + cout << "--------------------------------" ; + cout << endl; + const ParamSet& piMessage = x->getPiMessage (childs[j]); + const ParamSet& lambdaMessage = x->getLambdaMessage (childs[j]); + for (int xi = 0; xi < var->getDomainSize(); xi++) { + cout << setw (10) << domain[xi]; + cout.precision (PRECISION); + cout << setw (27) << piMessage[xi]; + cout.precision (PRECISION); + cout << setw (27) << lambdaMessage[xi]; + cout << endl; + } + cout << endl; + } + } +} + + + +void +BPSolver::printAllMessageStatus (void) const +{ + const NodeSet& nodes = bn_->getNodes(); + for (unsigned i = 0; i < nodes.size(); i++) { + printMessageStatusOf (nodes[i]); + } +} + + diff --git a/packages/CLPBN/clpbn/bp/BPSolver.h b/packages/CLPBN/clpbn/bp/BPSolver.h new file mode 100755 index 000000000..b752b92d2 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BPSolver.h @@ -0,0 +1,450 @@ +#ifndef BP_BPSOLVER_H +#define BP_BPSOLVER_H + +#include +#include +#include + +#include "Solver.h" +#include "BayesNet.h" +#include "BpNode.h" +#include "Shared.h" + +using namespace std; + +class BPSolver; + +static const string PI = "pi" ; +static const string LD = "ld" ; + +enum MessageType {PI_MSG, LAMBDA_MSG}; + +class BPSolver; +struct Edge +{ + Edge (BayesNode* s, BayesNode* d, MessageType t) + { + source = s; + destination = d; + type = t; + } + string getId (void) const + { + stringstream ss; + type == PI_MSG ? ss << PI : ss << LD; + ss << source->getVarId() << "." << destination->getVarId(); + return ss.str(); + } + string toString (void) const + { + stringstream ss; + type == PI_MSG ? ss << PI << "(" : ss << LD << "(" ; + ss << source->getLabel() << " --> " ; + ss << destination->getLabel(); + ss << ")" ; + return ss.str(); + } + BayesNode* source; + BayesNode* destination; + MessageType type; + static BPSolver* klass; +}; + + + +/* +class BPMessage +{ + BPMessage (BayesNode* parent, BayesNode* child) + { + parent_ = parent; + child_ = child; + currPiMsg_.resize (child->getDomainSize(), 1); + currLdMsg_.resize (parent->getDomainSize(), 1); + nextLdMsg_.resize (parent->getDomainSize(), 1); + nextPiMsg_.resize (child->getDomainSize(), 1); + piResidual_ = 1.0; + ldResidual_ = 1.0; + } + + Param getPiMessageValue (int idx) const + { + assert (idx >=0 && idx < child->getDomainSize()); + return currPiMsg_[idx]; + } + + Param getLambdaMessageValue (int idx) const + { + assert (idx >=0 && idx < parent->getDomainSize()); + return currLdMsg_[idx]; + } + + const ParamSet& getPiMessage (void) const + { + return currPiMsg_; + } + + const ParamSet& getLambdaMessage (void) const + { + return currLdMsg_; + } + + ParamSet& piNextMessageReference (void) + { + return nextPiMsg_; + } + + ParamSet& lambdaNextMessageReference (const BayesNode* source) + { + return nextLdMsg_; + } + + void updatePiMessage (void) + { + currPiMsg_ = nextPiMsg_; + Util::normalize (currPiMsg_); + } + + void updateLambdaMessage (void) + { + currLdMsg_ = nextLdMsg_; + Util::normalize (currLdMsg_); + } + + double getPiResidual (void) + { + return piResidual_; + } + + double getLambdaResidual (void) + { + return ldResidual_; + } + + void updatePiResidual (void) + { + piResidual_ = Util::getL1dist (currPiMsg_, nextPiMsg_); + } + + void updateLambdaResidual (void) + { + ldResidual_ = Util::getL1dist (currLdMsg_, nextLdMsg_); + } + + void clearPiResidual (void) + { + piResidual_ = 0.0; + } + + void clearLambdaResidual (void) + { + ldResidual_ = 0.0; + } + + BayesNode* parent_; + BayesNode* child_; + ParamSet currPiMsg_; // current pi messages + ParamSet currLdMsg_; // current lambda messages + ParamSet nextPiMsg_; + ParamSet nextLdMsg_; + Param piResidual_; + Param ldResidual_; +}; + + + +class NodeInfo +{ + NodeInfo (BayesNode* node) + { + node_ = node; + piVals_.resize (node->getDomainSize(), 1); + ldVals_.resize (node->getDomainSize(), 1); + } + + ParamSet getBeliefs (void) const + { + double sum = 0.0; + ParamSet beliefs (node_->getDomainSize()); + for (int xi = 0; xi < node_->getDomainSize(); xi++) { + double prod = piVals_[xi] * ldVals_[xi]; + beliefs[xi] = prod; + sum += prod; + } + assert (sum); + //normalize the beliefs + for (int xi = 0; xi < node_->getDomainSize(); xi++) { + beliefs[xi] /= sum; + } + return beliefs; + } + + double getPiValue (int idx) const + { + assert (idx >=0 && idx < node_->getDomainSize()); + return piVals_[idx]; + } + + void setPiValue (int idx, double value) + { + assert (idx >=0 && idx < node_->getDomainSize()); + piVals_[idx] = value; + } + + double getLambdaValue (int idx) const + { + assert (idx >=0 && idx < node_->getDomainSize()); + return ldVals_[idx]; + } + + void setLambdaValue (int idx, double value) + { + assert (idx >=0 && idx < node_->getDomainSize()); + ldVals_[idx] = value; + } + + ParamSet& getPiValues (void) + { + return piVals_; + } + + ParamSet& getLambdaValues (void) + { + return ldVals_; + } + + double getBeliefChange (void) + { + double change = 0.0; + if (oldBeliefs_.size() == 0) { + oldBeliefs_ = getBeliefs(); + change = MAX_CHANGE_; + } else { + ParamSet currentBeliefs = getBeliefs(); + for (int xi = 0; xi < node_->getDomainSize(); xi++) { + change += abs (currentBeliefs[xi] - oldBeliefs_[xi]); + } + oldBeliefs_ = currentBeliefs; + } + return change; + } + + bool hasReceivedChildInfluence (void) const + { + // if all lambda values are equal, then neither + // this node neither its descendents have evidence, + // we can use this to don't send lambda messages his parents + bool childInfluenced = false; + for (int xi = 1; xi < node_->getDomainSize(); xi++) { + if (ldVals_[xi] != ldVals_[0]) { + childInfluenced = true; + break; + } + } + return childInfluenced; + } + + BayesNode* node_; + ParamSet piVals_; // pi values + ParamSet ldVals_; // lambda values + ParamSet oldBeliefs_; +}; +*/ + + +bool compareResidual (const Edge&, const Edge&); + +class BPSolver : public Solver +{ + public: + BPSolver (const BayesNet&); + ~BPSolver (void); + + void runSolver (void); + ParamSet getPosterioriOf (const Variable* var) const; + ParamSet getJointDistribution (const NodeSet&) const; + + private: + DISALLOW_COPY_AND_ASSIGN (BPSolver); + + void initializeSolver (void); + void incorporateEvidence (BayesNode*); + void runPolyTreeSolver (void); + void polyTreePiMessage (BayesNode*, BayesNode*); + void polyTreeLambdaMessage (BayesNode*, BayesNode*); + void runGenericSolver (void); + void maxResidualSchedule (void); + bool converged (void) const; + void updatePiValues (BayesNode*); + void updateLambdaValues (BayesNode*); + void calculateNextPiMessage (BayesNode*, BayesNode*); + void calculateNextLambdaMessage (BayesNode*, BayesNode*); + void printMessageStatusOf (const BayesNode*) const; + void printAllMessageStatus (void) const; + // inlines + void updatePiMessage (BayesNode*, BayesNode*); + void updateLambdaMessage (BayesNode*, BayesNode*); + void calculateNextMessage (const Edge&); + void updateMessage (const Edge&); + void updateValues (const Edge&); + double getResidual (const Edge&) const; + void updateResidual (const Edge&); + void clearResidual (const Edge&); + BpNode* M (const BayesNode*) const; + friend bool compareResidual (const Edge&, const Edge&); + + const BayesNet* bn_; + vector msgs_; + Schedule schedule_; + int nIter_; + int maxIter_; + double accuracy_; + vector updateOrder_; + bool forceGenericSolver_; + + struct compare + { + inline bool operator() (const Edge& e1, const Edge& e2) + { + return compareResidual (e1, e2); + } + }; + + typedef multiset SortedOrder; + SortedOrder sortedOrder_; + + typedef unordered_map EdgeMap; + EdgeMap edgeMap_; + +}; + + + +inline void +BPSolver::updatePiMessage (BayesNode* source, BayesNode* destination) +{ + M(source)->updatePiMessage(destination); +} + + + +inline void +BPSolver::updateLambdaMessage (BayesNode* source, BayesNode* destination) +{ + M(destination)->updateLambdaMessage(source); +} + + + +inline void +BPSolver::calculateNextMessage (const Edge& e) +{ + if (DL >= 1) { + cout << "calculating " << e.toString() << endl; + } + if (e.type == PI_MSG) { + calculateNextPiMessage (e.source, e.destination); + } else { + calculateNextLambdaMessage (e.source, e.destination); + } +} + + + +inline void +BPSolver::updateMessage (const Edge& e) +{ + if (DL >= 1) { + cout << "updating " << e.toString() << endl; + } + if (e.type == PI_MSG) { + M(e.source)->updatePiMessage(e.destination); + } else { + M(e.destination)->updateLambdaMessage(e.source); + } +} + + + +inline void +BPSolver::updateValues (const Edge& e) +{ + if (!e.destination->hasEvidence()) { + if (e.type == PI_MSG) { + updatePiValues (e.destination); + } else { + updateLambdaValues (e.destination); + } + } +} + + + +inline double +BPSolver::getResidual (const Edge& e) const +{ + if (e.type == PI_MSG) { + return M(e.source)->getPiResidual(e.destination); + } else { + return M(e.destination)->getLambdaResidual(e.source); + } +} + + + +inline void +BPSolver::updateResidual (const Edge& e) +{ + if (e.type == PI_MSG) { + M(e.source)->updatePiResidual(e.destination); + } else { + M(e.destination)->updateLambdaResidual(e.source); + } +} + + + +inline void +BPSolver::clearResidual (const Edge& e) +{ + if (e.type == PI_MSG) { + M(e.source)->clearPiResidual(e.destination); + } else { + M(e.destination)->clearLambdaResidual(e.source); + } +} + + + +inline bool +compareResidual (const Edge& e1, const Edge& e2) +{ + double residual1; + double residual2; + if (e1.type == PI_MSG) { + residual1 = Edge::klass->M(e1.source)->getPiResidual(e1.destination); + } else { + residual1 = Edge::klass->M(e1.destination)->getLambdaResidual(e1.source); + } + if (e2.type == PI_MSG) { + residual2 = Edge::klass->M(e2.source)->getPiResidual(e2.destination); + } else { + residual2 = Edge::klass->M(e2.destination)->getLambdaResidual(e2.source); + } + return residual1 > residual2; +} + + + +inline BpNode* +BPSolver::M (const BayesNode* node) const +{ + assert (node); + assert (node == bn_->getNode (node->getVarId())); + assert (node->getIndex() < msgs_.size()); + return msgs_[node->getIndex()]; +} + + +#endif + diff --git a/packages/CLPBN/clpbn/bp/BayesNet.cpp b/packages/CLPBN/clpbn/bp/BayesNet.cpp new file mode 100755 index 000000000..291c0c8d3 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BayesNet.cpp @@ -0,0 +1,792 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "xmlParser/xmlParser.h" + +#include "BayesNet.h" + + +BayesNet::BayesNet (void) +{ +} + + + +BayesNet::BayesNet (const char* fileName) +{ + map domains; + XMLNode xMainNode = XMLNode::openFileHelper (fileName, "BIF"); + // only the first network is parsed, others are ignored + XMLNode xNode = xMainNode.getChildNode ("NETWORK"); + int nVars = xNode.nChildNode ("VARIABLE"); + for (int i = 0; i < nVars; i++) { + XMLNode var = xNode.getChildNode ("VARIABLE", i); + string type = var.getAttribute ("TYPE"); + if (type != "nature") { + cerr << "error: only \"nature\" variables are supported" << endl; + abort(); + } + Domain domain; + string label = var.getChildNode("NAME").getText(); + int domainSize = var.nChildNode ("OUTCOME"); + for (int j = 0; j < domainSize; j++) { + if (var.getChildNode("OUTCOME", j).getText() == 0) { + stringstream ss; + ss << j + 1; + domain.push_back (ss.str()); + } else { + domain.push_back (var.getChildNode("OUTCOME", j).getText()); + } + } + domains.insert (make_pair (label, domain)); + } + + int nDefs = xNode.nChildNode ("DEFINITION"); + if (nVars != nDefs) { + cerr << "error: different number of variables and definitions"; + cerr << endl; + } + + queue indexes; + for (int i = 0; i < nDefs; i++) { + indexes.push (i); + } + + while (!indexes.empty()) { + int index = indexes.front(); + indexes.pop(); + XMLNode def = xNode.getChildNode ("DEFINITION", index); + string label = def.getChildNode("FOR").getText(); + map::const_iterator iter; + iter = domains.find (label); + if (iter == domains.end()) { + cerr << "error: unknow variable `" << label << "'" << endl; + abort(); + } + bool processItLatter = false; + NodeSet parents; + int nParams = iter->second.size(); + for (int j = 0; j < def.nChildNode ("GIVEN"); j++) { + string parentLabel = def.getChildNode("GIVEN", j).getText(); + BayesNode* parentNode = getNode (parentLabel); + if (parentNode) { + nParams *= parentNode->getDomainSize(); + parents.push_back (parentNode); + } + else { + iter = domains.find (parentLabel); + if (iter == domains.end()) { + cerr << "error: unknow parent `" << parentLabel << "'" << endl; + abort(); + } else { + // this definition contains a parent that doesn't + // have a corresponding bayesian node instance yet, + // so process this definition latter + indexes.push (index); + processItLatter = true; + break; + } + } + } + + if (!processItLatter) { + int count = 0; + ParamSet params (nParams); + stringstream s (def.getChildNode("TABLE").getText()); + while (!s.eof() && count < nParams) { + s >> params[count]; + count ++; + } + if (count != nParams) { + cerr << "error: invalid number of parameters " ; + cerr << "for variable `" << label << "'" << endl; + abort(); + } + params = reorderParameters (params, iter->second.size()); + addNode (label, iter->second, parents, params); + } + } + setIndexes(); +} + + + +BayesNet::~BayesNet (void) +{ + Statistics::writeStats(); + for (unsigned i = 0; i < nodes_.size(); i++) { + delete nodes_[i]; + } +} + + + +BayesNode* +BayesNet::addNode (unsigned varId) +{ + indexMap_.insert (make_pair (varId, nodes_.size())); + nodes_.push_back (new BayesNode (varId)); + return nodes_.back(); +} + + + +BayesNode* +BayesNet::addNode (unsigned varId, + unsigned dsize, + int evidence, + NodeSet& parents, + Distribution* dist) +{ + indexMap_.insert (make_pair (varId, nodes_.size())); + nodes_.push_back (new BayesNode ( + varId, dsize, evidence, parents, dist)); + return nodes_.back(); +} + + + +BayesNode* +BayesNet::addNode (string label, + Domain domain, + NodeSet& parents, + ParamSet& params) +{ + indexMap_.insert (make_pair (nodes_.size(), nodes_.size())); + Distribution* dist = new Distribution (params); + BayesNode* node = new BayesNode ( + nodes_.size(), label, domain, parents, dist); + dists_.push_back (dist); + nodes_.push_back (node); + return node; +} + + + +BayesNode* +BayesNet::getNode (unsigned varId) const +{ + IndexMap::const_iterator it = indexMap_.find(varId); + if (it == indexMap_.end()) { + return 0; + } else { + return nodes_[it->second]; + } +} + + + +BayesNode* +BayesNet::getNode (string label) const +{ + BayesNode* node = 0; + for (unsigned i = 0; i < nodes_.size(); i++) { + if (nodes_[i]->getLabel() == label) { + node = nodes_[i]; + break; + } + } + return node; +} + + + +void +BayesNet::addDistribution (Distribution* dist) +{ + dists_.push_back (dist); +} + + + +Distribution* +BayesNet::getDistribution (unsigned distId) const +{ + Distribution* dist = 0; + for (unsigned i = 0; i < dists_.size(); i++) { + if (dists_[i]->id == distId) { + dist = dists_[i]; + break; + } + } + return dist; +} + + + +const NodeSet& +BayesNet::getNodes (void) const +{ + return nodes_; +} + + + +int +BayesNet::getNumberOfNodes (void) const +{ + return nodes_.size(); +} + + + +NodeSet +BayesNet::getRootNodes (void) const +{ + NodeSet roots; + for (unsigned i = 0; i < nodes_.size(); i++) { + if (nodes_[i]->isRoot()) { + roots.push_back (nodes_[i]); + } + } + return roots; +} + + + +NodeSet +BayesNet::getLeafNodes (void) const +{ + NodeSet leafs; + for (unsigned i = 0; i < nodes_.size(); i++) { + if (nodes_[i]->isLeaf()) { + leafs.push_back (nodes_[i]); + } + } + return leafs; +} + + + +VarSet +BayesNet::getVariables (void) const +{ + VarSet vars; + for (unsigned i = 0; i < nodes_.size(); i++) { + vars.push_back (nodes_[i]); + } + return vars; +} + + + +BayesNet* +BayesNet::pruneNetwork (BayesNode* queryNode) const +{ + NodeSet queryNodes; + queryNodes.push_back (queryNode); + return pruneNetwork (queryNodes); +} + + + +BayesNet* +BayesNet::pruneNetwork (const NodeSet& interestedVars) const +{ + /* + cout << "interested vars: " ; + for (unsigned i = 0; i < interestedVars.size(); i++) { + cout << interestedVars[i]->getLabel() << " " ; + } + cout << endl; + */ + vector states (nodes_.size(), 0); + + Scheduling scheduling; + for (NodeSet::const_iterator it = interestedVars.begin(); + it != interestedVars.end(); it++) { + scheduling.push (ScheduleInfo (*it, false, true)); + } + + while (!scheduling.empty()) { + ScheduleInfo& sch = scheduling.front(); + StateInfo* state = states[sch.node->getIndex()]; + if (!state) { + state = new StateInfo(); + states[sch.node->getIndex()] = state; + } else { + state->visited = true; + } + if (!sch.node->hasEvidence() && sch.visitedFromChild) { + if (!state->markedOnTop) { + state->markedOnTop = true; + scheduleParents (sch.node, scheduling); + } + if (!state->markedOnBottom) { + state->markedOnBottom = true; + scheduleChilds (sch.node, scheduling); + } + } + if (sch.visitedFromParent) { + if (sch.node->hasEvidence() && !state->markedOnTop) { + state->markedOnTop = true; + scheduleParents (sch.node, scheduling); + } + if (!sch.node->hasEvidence() && !state->markedOnBottom) { + state->markedOnBottom = true; + scheduleChilds (sch.node, scheduling); + } + } + scheduling.pop(); + } + /* + cout << "\t\ttop\tbottom" << endl; + cout << "variable\t\tmarked\tmarked\tvisited\tobserved" << endl; + cout << "----------------------------------------------------------" ; + cout << endl; + for (unsigned i = 0; i < states.size(); i++) { + cout << nodes_[i]->getLabel() << ":\t\t" ; + if (states[i]) { + states[i]->markedOnTop ? cout << "yes\t" : cout << "no\t" ; + states[i]->markedOnBottom ? cout << "yes\t" : cout << "no\t" ; + states[i]->visited ? cout << "yes\t" : cout << "no\t" ; + nodes_[i]->hasEvidence() ? cout << "yes" : cout << "no" ; + cout << endl; + } else { + cout << "no\tno\tno\t" ; + nodes_[i]->hasEvidence() ? cout << "yes" : cout << "no" ; + cout << endl; + } + } + cout << endl; + */ + BayesNet* bn = new BayesNet(); + constructGraph (bn, states); + + for (unsigned i = 0; i < nodes_.size(); i++) { + delete states[i]; + } + return bn; +} + + + +void +BayesNet::constructGraph (BayesNet* bn, + const vector& states) const +{ + for (unsigned i = 0; i < nodes_.size(); i++) { + bool isRequired = false; + if (states[i]) { + isRequired = (nodes_[i]->hasEvidence() && states[i]->visited) + || + states[i]->markedOnTop; + } + if (isRequired) { + NodeSet parents; + if (states[i]->markedOnTop) { + const NodeSet& ps = nodes_[i]->getParents(); + for (unsigned j = 0; j < ps.size(); j++) { + BayesNode* parent = bn->getNode (ps[j]->getVarId()); + if (!parent) { + parent = bn->addNode (ps[j]->getVarId()); + } + parents.push_back (parent); + } + } + BayesNode* node = bn->getNode (nodes_[i]->getVarId()); + if (node) { + node->setData (nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } else { + node = bn->addNode (nodes_[i]->getVarId(), + nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } + if (nodes_[i]->hasDomain()) { + node->setDomain (nodes_[i]->getDomain()); + } + if (nodes_[i]->hasLabel()) { + node->setLabel (nodes_[i]->getLabel()); + } + } + } + bn->setIndexes(); +} + +/* +void +BayesNet::constructGraph (BayesNet* bn, + const vector& states) const +{ + for (unsigned i = 0; i < nodes_.size(); i++) { + if (states[i]) { + if (nodes_[i]->hasEvidence() && states[i]->visited) { + NodeSet parents; + if (states[i]->markedOnTop) { + const NodeSet& ps = nodes_[i]->getParents(); + for (unsigned j = 0; j < ps.size(); j++) { + BayesNode* parent = bn->getNode (ps[j]->getVarId()); + if (parent == 0) { + parent = bn->addNode (ps[j]->getVarId()); + } + parents.push_back (parent); + } + } + + BayesNode* n = bn->getNode (nodes_[i]->getVarId()); + if (n) { + n->setData (nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } else { + bn->addNode (nodes_[i]->getVarId(), + nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } + + } else if (states[i]->markedOnTop) { + NodeSet parents; + const NodeSet& ps = nodes_[i]->getParents(); + for (unsigned j = 0; j < ps.size(); j++) { + BayesNode* parent = bn->getNode (ps[j]->getVarId()); + if (parent == 0) { + parent = bn->addNode (ps[j]->getVarId()); + } + parents.push_back (parent); + } + + BayesNode* n = bn->getNode (nodes_[i]->getVarId()); + if (n) { + n->setData (nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } else { + bn->addNode (nodes_[i]->getVarId(), + nodes_[i]->getDomainSize(), + nodes_[i]->getEvidence(), parents, + nodes_[i]->getDistribution()); + } + } + } + } +}*/ + + + +bool +BayesNet::isSingleConnected (void) const +{ + return !containsUndirectedCycle(); +} + + + +vector +BayesNet::getDomainConfigurationsOf (const NodeSet& nodes) +{ + int nConfs = 1; + for (unsigned i = 0; i < nodes.size(); i++) { + nConfs *= nodes[i]->getDomainSize(); + } + + vector confs (nConfs); + for (int i = 0; i < nConfs; i++) { + confs[i].resize (nodes.size()); + } + + int nReps = 1; + for (int i = nodes.size() - 1; i >= 0; i--) { + int index = 0; + while (index < nConfs) { + for (int j = 0; j < nodes[i]->getDomainSize(); j++) { + for (int r = 0; r < nReps; r++) { + confs[index][i] = j; + index++; + } + } + } + nReps *= nodes[i]->getDomainSize(); + } + + return confs; +} + + + +vector +BayesNet::getInstantiations (const NodeSet& parents_) +{ + int nParents = parents_.size(); + int rowSize = 1; + for (unsigned i = 0; i < parents_.size(); i++) { + rowSize *= parents_[i]->getDomainSize(); + } + int nReps = 1; + vector headers (rowSize); + for (int i = nParents - 1; i >= 0; i--) { + Domain domain = parents_[i]->getDomain(); + int index = 0; + while (index < rowSize) { + for (int j = 0; j < parents_[i]->getDomainSize(); j++) { + for (int r = 0; r < nReps; r++) { + if (headers[index] != "") { + headers[index] = domain[j] + "," + headers[index]; + } else { + headers[index] = domain[j]; + } + index++; + } + } + } + nReps *= parents_[i]->getDomainSize(); + } + return headers; +} + + + +void +BayesNet::setIndexes (void) +{ + for (unsigned i = 0; i < nodes_.size(); i++) { + nodes_[i]->setIndex (i); + } +} + + + +void +BayesNet::freeDistributions (void) +{ + for (unsigned i = 0; i < dists_.size(); i++) { + delete dists_[i]; + } +} + + + +void +BayesNet::printNetwork (void) const +{ + for (unsigned i = 0; i < nodes_.size(); i++) { + cout << *nodes_[i]; + } +} + + + +void +BayesNet::printNetworkToFile (const char* fileName) const +{ + string s = "../../" ; + s += fileName; + ofstream out (s.c_str()); + if (!out.is_open()) { + cerr << "error: cannot open file to write at " ; + cerr << "BayesNet::printToFile()" << endl; + abort(); + } + for (unsigned i = 0; i < nodes_.size(); i++) { + out << *nodes_[i]; + } + out.close(); +} + + + +void +BayesNet::exportToDotFile (const char* fileName, + bool showNeighborless, + const NodeSet& highlightNodes) const +{ + string s = "../../" ; + s+= fileName; + ofstream out (s.c_str()); + if (!out.is_open()) { + cerr << "error: cannot open file to write at " ; + cerr << "BayesNet::exportToDotFile()" << endl; + abort(); + } + + out << "digraph \"" << fileName << "\" {" << endl; + for (unsigned i = 0; i < nodes_.size(); i++) { + const NodeSet& childs = nodes_[i]->getChilds(); + for (unsigned j = 0; j < childs.size(); j++) { + out << '"' << nodes_[i]->getLabel() << '"' << " -> " ; + out << '"' << childs[j]->getLabel() << '"' << endl; + } + } + + for (unsigned i = 0; i < nodes_.size(); i++) { + if (showNeighborless || nodes_[i]->hasNeighbors()) { + out << '"' << nodes_[i]->getLabel() << '"' ; + if (nodes_[i]->hasEvidence()) { + out << " [style=filled, fillcolor=yellow]" << endl; + } else { + out << endl; + } + } + } + + for (unsigned i = 0; i < highlightNodes.size(); i++) { + out << '"' << highlightNodes[i]->getLabel() << '"' ; + out << " [shape=box]" << endl; + } + + out << "}" << endl; + out.close(); +} + + + +void +BayesNet::exportToBifFile (const char* fileName) const +{ + string s = "../../" ; + s += fileName; + ofstream out (s.c_str()); + if(!out.is_open()) { + cerr << "error: cannot open file to write at " ; + cerr << "BayesNet::exportToBifFile()" << endl; + abort(); + } + out << "" << endl; + out << "" << endl; + out << "" << endl; + out << "" << fileName << "" << endl << endl; + for (unsigned i = 0; i < nodes_.size(); i++) { + out << "" << endl; + out << "\t" << nodes_[i]->getLabel() << "" << endl; + const Domain& domain = nodes_[i]->getDomain(); + for (unsigned j = 0; j < domain.size(); j++) { + out << "\t" << domain[j] << "" << endl; + } + out << "" << endl << endl; + } + + for (unsigned i = 0; i < nodes_.size(); i++) { + out << "" << endl; + out << "\t" << nodes_[i]->getLabel() << "" << endl; + const NodeSet& parents = nodes_[i]->getParents(); + for (unsigned j = 0; j < parents.size(); j++) { + out << "\t" << parents[j]->getLabel(); + out << "" << endl; + } + ParamSet params = revertParameterReorder (nodes_[i]->getParameters(), + nodes_[i]->getDomainSize()); + out << "\t" ; + for (unsigned j = 0; j < params.size(); j++) { + out << " " << params[j]; + } + out << "
" << endl; + out << "
" << endl << endl; + } + out << "
" << endl; + out << "
" << endl << endl; + out.close(); +} + + + +bool +BayesNet::containsUndirectedCycle (void) const +{ + vector visited (nodes_.size(), false); + for (unsigned i = 0; i < nodes_.size(); i++) { + int v = nodes_[i]->getIndex(); + if (!visited[v]) { + if (containsUndirectedCycle (v, -1, visited)) { + return true; + } + } + } + return false; +} + + + +bool +BayesNet::containsUndirectedCycle (int v, + int p, + vector& visited) const +{ + visited[v] = true; + vector adjacencies = getAdjacentNodes (v); + for (unsigned i = 0; i < adjacencies.size(); i++) { + int w = adjacencies[i]; + if (!visited[w]) { + if (containsUndirectedCycle (w, v, visited)) { + return true; + } + } + else if (visited[w] && w != p) { + return true; + } + } + return false; // no cycle detected in this component +} + + + +vector +BayesNet::getAdjacentNodes (int v) const +{ + vector adjacencies; + const NodeSet& parents = nodes_[v]->getParents(); + const NodeSet& childs = nodes_[v]->getChilds(); + for (unsigned i = 0; i < parents.size(); i++) { + adjacencies.push_back (parents[i]->getIndex()); + } + for (unsigned i = 0; i < childs.size(); i++) { + adjacencies.push_back (childs[i]->getIndex()); + } + return adjacencies; +} + + + +ParamSet +BayesNet::reorderParameters (const ParamSet& params, + int domainSize) const +{ + // the interchange format for bayesian networks keeps the probabilities + // in the following order: + // p(a1|b1,c1) p(a2|b1,c1) p(a1|b1,c2) p(a2|b1,c2) p(a1|b2,c1) p(a2|b2,c1) + // p(a1|b2,c2) p(a2|b2,c2). + // + // however, in clpbn we keep the probabilities in this order: + // p(a1|b1,c1) p(a1|b1,c2) p(a1|b2,c1) p(a1|b2,c2) p(a2|b1,c1) p(a2|b1,c2) + // p(a2|b2,c1) p(a2|b2,c2). + unsigned count = 0; + unsigned rowSize = params.size() / domainSize; + ParamSet reordered; + while (reordered.size() < params.size()) { + unsigned idx = count; + for (unsigned i = 0; i < rowSize; i++) { + reordered.push_back (params[idx]); + idx += domainSize; + } + count++; + } + return reordered; +} + + + +ParamSet +BayesNet::revertParameterReorder (const ParamSet& params, + int domainSize) const +{ + unsigned count = 0; + unsigned rowSize = params.size() / domainSize; + ParamSet reordered; + while (reordered.size() < params.size()) { + unsigned idx = count; + for (int i = 0; i < domainSize; i++) { + reordered.push_back (params[idx]); + idx += rowSize; + } + count ++; + } + return reordered; +} + diff --git a/packages/CLPBN/clpbn/bp/BayesNet.h b/packages/CLPBN/clpbn/bp/BayesNet.h new file mode 100755 index 000000000..547671f31 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BayesNet.h @@ -0,0 +1,129 @@ +#ifndef BP_BAYES_NET_H +#define BP_BAYES_NET_H + +#include +#include +#include +#include +#include +#include + +#include "GraphicalModel.h" +#include "BayesNode.h" +#include "Shared.h" + + +using namespace std; + +class Distribution; + +struct ScheduleInfo +{ + ScheduleInfo (BayesNode* n, bool vfp, bool vfc) + { + node = n; + visitedFromParent = vfp; + visitedFromChild = vfc; + } + BayesNode* node; + bool visitedFromParent; + bool visitedFromChild; +}; + + +struct StateInfo +{ + StateInfo (void) + { + visited = true; + markedOnTop = false; + markedOnBottom = false; + } + bool visited; + bool markedOnTop; + bool markedOnBottom; +}; + +typedef vector DistSet; +typedef queue > Scheduling; +typedef unordered_map Histogram; +typedef unordered_map Times; + + +class BayesNet : public GraphicalModel +{ + public: + BayesNet (void); + BayesNet (const char*); + ~BayesNet (void); + + BayesNode* addNode (unsigned); + BayesNode* addNode (unsigned, unsigned, int, NodeSet&, Distribution*); + BayesNode* addNode (string, Domain, NodeSet&, ParamSet&); + BayesNode* getNode (unsigned) const; + BayesNode* getNode (string) const; + void addDistribution (Distribution*); + Distribution* getDistribution (unsigned) const; + const NodeSet& getNodes (void) const; + int getNumberOfNodes (void) const; + NodeSet getRootNodes (void) const; + NodeSet getLeafNodes (void) const; + VarSet getVariables (void) const; + BayesNet* pruneNetwork (BayesNode*) const; + BayesNet* pruneNetwork (const NodeSet& queryNodes) const; + void constructGraph (BayesNet*, const vector&) const; + bool isSingleConnected (void) const; + static vector getDomainConfigurationsOf (const NodeSet&); + static vector getInstantiations (const NodeSet& nodes); + void setIndexes (void); + void freeDistributions (void); + void printNetwork (void) const; + void printNetworkToFile (const char*) const; + void exportToDotFile (const char*, bool = true, + const NodeSet& = NodeSet()) const; + void exportToBifFile (const char*) const; + + static Histogram histogram_; + static Times times_; + + private: + DISALLOW_COPY_AND_ASSIGN (BayesNet); + + bool containsUndirectedCycle (void) const; + bool containsUndirectedCycle (int, int, + vector&)const; + vector getAdjacentNodes (int) const ; + ParamSet reorderParameters (const ParamSet&, int) const; + ParamSet revertParameterReorder (const ParamSet&, int) const; + void scheduleParents (const BayesNode*, Scheduling&) const; + void scheduleChilds (const BayesNode*, Scheduling&) const; + + NodeSet nodes_; + DistSet dists_; + IndexMap indexMap_; +}; + + + +inline void +BayesNet::scheduleParents (const BayesNode* n, Scheduling& sch) const +{ + const NodeSet& ps = n->getParents(); + for (NodeSet::const_iterator it = ps.begin(); it != ps.end(); it++) { + sch.push (ScheduleInfo (*it, false, true)); + } +} + + + +inline void +BayesNet::scheduleChilds (const BayesNode* n, Scheduling& sch) const +{ + const NodeSet& cs = n->getChilds(); + for (NodeSet::const_iterator it = cs.begin(); it != cs.end(); it++) { + sch.push (ScheduleInfo (*it, true, false)); + } +} + +#endif + diff --git a/packages/CLPBN/clpbn/bp/BayesNode.cpp b/packages/CLPBN/clpbn/bp/BayesNode.cpp new file mode 100755 index 000000000..72ed5febd --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BayesNode.cpp @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include + +#include "BayesNode.h" + + +BayesNode::BayesNode (unsigned varId) : Variable (varId) +{ +} + + + +BayesNode::BayesNode (unsigned varId, + unsigned dsize, + int evidence, + const NodeSet& parents, + Distribution* dist) : Variable(varId, dsize, evidence) +{ + parents_ = parents; + dist_ = dist; + for (unsigned int i = 0; i < parents.size(); i++) { + parents[i]->addChild (this); + } +} + + + +BayesNode::BayesNode (unsigned varId, + string label, + const Domain& domain, + const NodeSet& parents, + Distribution* dist) : Variable(varId, domain) +{ + label_ = new string (label); + parents_ = parents; + dist_ = dist; + for (unsigned int i = 0; i < parents.size(); i++) { + parents[i]->addChild (this); + } +} + + + +void +BayesNode::setData (unsigned dsize, + int evidence, + const NodeSet& parents, + Distribution* dist) +{ + setDomainSize (dsize); + evidence_ = evidence; + parents_ = parents; + dist_ = dist; + for (unsigned int i = 0; i < parents.size(); i++) { + parents[i]->addChild (this); + } +} + + + +void +BayesNode::addChild (BayesNode* node) +{ + childs_.push_back (node); +} + + + +Distribution* +BayesNode::getDistribution (void) +{ + return dist_; +} + + + +const ParamSet& +BayesNode::getParameters (void) +{ + return dist_->params; +} + + + +ParamSet +BayesNode::getRow (int rowIndex) const +{ + int rowSize = getRowSize(); + int offset = rowSize * rowIndex; + ParamSet row (rowSize); + for (int i = 0; i < rowSize; i++) { + row[i] = dist_->params[offset + i] ; + } + return row; +} + + + +bool +BayesNode::isRoot (void) +{ + return getParents().empty(); +} + + + +bool +BayesNode::isLeaf (void) +{ + return getChilds().empty(); +} + + + +bool +BayesNode::hasNeighbors (void) const +{ + return childs_.size() != 0 || parents_.size() != 0; +} + + +int +BayesNode::getCptSize (void) +{ + return dist_->params.size(); +} + + + +const vector& +BayesNode::getCptEntries (void) +{ + if (dist_->entries.size() == 0) { + unsigned rowSize = getRowSize(); + unsigned nParents = parents_.size(); + vector confs (rowSize); + + for (unsigned i = 0; i < rowSize; i++) { + confs[i].resize (nParents); + } + + int nReps = 1; + for (int i = nParents - 1; i >= 0; i--) { + unsigned index = 0; + while (index < rowSize) { + for (int j = 0; j < parents_[i]->getDomainSize(); j++) { + for (int r = 0; r < nReps; r++) { + confs[index][i] = j; + index++; + } + } + } + nReps *= parents_[i]->getDomainSize(); + } + + dist_->entries.reserve (rowSize); + for (unsigned i = 0; i < rowSize; i++) { + dist_->entries.push_back (CptEntry (i, confs[i])); + } + } + return dist_->entries; +} + + + +int +BayesNode::getIndexOfParent (const BayesNode* parent) const +{ + for (unsigned int i = 0; i < parents_.size(); i++) { + if (parents_[i] == parent) { + return i; + } + } + return -1; +} + + + +string +BayesNode::cptEntryToString (const CptEntry& entry) const +{ + stringstream ss; + ss << "p(" ; + const DomainConf& conf = entry.getParentConfigurations(); + int row = entry.getParameterIndex() / getRowSize(); + ss << getDomain()[row]; + if (parents_.size() > 0) { + ss << "|" ; + for (unsigned int i = 0; i < conf.size(); i++) { + if (i != 0) { + ss << ","; + } + ss << parents_[i]->getDomain()[conf[i]]; + } + } + ss << ")" ; + return ss.str(); +} + + + +string +BayesNode::cptEntryToString (int row, const CptEntry& entry) const +{ + stringstream ss; + ss << "p(" ; + const DomainConf& conf = entry.getParentConfigurations(); + ss << getDomain()[row]; + if (parents_.size() > 0) { + ss << "|" ; + for (unsigned int i = 0; i < conf.size(); i++) { + if (i != 0) { + ss << ","; + } + ss << parents_[i]->getDomain()[conf[i]]; + } + } + ss << ")" ; + return ss.str(); +} + + + +vector +BayesNode::getDomainHeaders (void) const +{ + int nParents = parents_.size(); + int rowSize = getRowSize(); + int nReps = 1; + vector headers (rowSize); + for (int i = nParents - 1; i >= 0; i--) { + Domain domain = parents_[i]->getDomain(); + int index = 0; + while (index < rowSize) { + for (int j = 0; j < parents_[i]->getDomainSize(); j++) { + for (int r = 0; r < nReps; r++) { + if (headers[index] != "") { + headers[index] = domain[j] + "," + headers[index]; + } else { + headers[index] = domain[j]; + } + index++; + } + } + } + nReps *= parents_[i]->getDomainSize(); + } + return headers; +} + + + +ostream& +operator << (ostream& o, const BayesNode& node) +{ + o << "variable " << node.getIndex() << endl; + o << "Var Id: " << node.getVarId() << endl; + o << "Label: " << node.getLabel() << endl; + + o << "Evidence: " ; + if (node.hasEvidence()) { + o << node.getEvidence(); + } + else { + o << "no" ; + } + o << endl; + + o << "Parents: " ; + const NodeSet& parents = node.getParents(); + if (parents.size() != 0) { + for (unsigned int i = 0; i < parents.size() - 1; i++) { + o << parents[i]->getLabel() << ", " ; + } + o << parents[parents.size() - 1]->getLabel(); + } + o << endl; + + o << "Childs: " ; + const NodeSet& childs = node.getChilds(); + if (childs.size() != 0) { + for (unsigned int i = 0; i < childs.size() - 1; i++) { + o << childs[i]->getLabel() << ", " ; + } + o << childs[childs.size() - 1]->getLabel(); + } + o << endl; + + o << "Domain: " ; + Domain domain = node.getDomain(); + for (unsigned int i = 0; i < domain.size() - 1; i++) { + o << domain[i] << ", " ; + } + if (domain.size() != 0) { + o << domain[domain.size() - 1]; + } + o << endl; + + // min width of first column + const unsigned int MIN_DOMAIN_WIDTH = 4; + // min width of following columns + const unsigned int MIN_COMBO_WIDTH = 12; + + unsigned int domainWidth = domain[0].length(); + for (unsigned int i = 1; i < domain.size(); i++) { + if (domain[i].length() > domainWidth) { + domainWidth = domain[i].length(); + } + } + domainWidth = (domainWidth < MIN_DOMAIN_WIDTH) + ? MIN_DOMAIN_WIDTH + : domainWidth; + + o << left << setw (domainWidth) << "cpt" << right; + + vector widths; + int lineWidth = domainWidth; + vector headers = node.getDomainHeaders(); + + if (!headers.empty()) { + for (unsigned int i = 0; i < headers.size(); i++) { + unsigned int len = headers[i].length(); + int w = (len < MIN_COMBO_WIDTH) ? MIN_COMBO_WIDTH : len; + widths.push_back (w); + o << setw (w) << headers[i]; + lineWidth += w; + } + o << endl; + } else { + cout << endl; + widths.push_back (domainWidth); + lineWidth += MIN_COMBO_WIDTH; + } + + for (int i = 0; i < lineWidth; i++) { + o << "-" ; + } + o << endl; + + for (unsigned int i = 0; i < domain.size(); i++) { + ParamSet row = node.getRow (i); + o << left << setw (domainWidth) << domain[i] << right; + for (unsigned j = 0; j < node.getRowSize(); j++) { + o << setw (widths[j]) << row[j]; + } + o << endl; + } + o << endl; + + return o; +} + diff --git a/packages/CLPBN/clpbn/bp/BayesNode.h b/packages/CLPBN/clpbn/bp/BayesNode.h new file mode 100755 index 000000000..923cca0f1 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/BayesNode.h @@ -0,0 +1,91 @@ +#ifndef BP_BAYESNODE_H +#define BP_BAYESNODE_H + +#include +#include +#include + +#include "Variable.h" +#include "CptEntry.h" +#include "Distribution.h" +#include "Shared.h" + +using namespace std; + + +class BayesNode : public Variable +{ + public: + BayesNode (unsigned); + BayesNode (unsigned, unsigned, int, const NodeSet&, Distribution*); + BayesNode (unsigned, string, const Domain&, const NodeSet&, Distribution*); + + void setData (unsigned, int, const NodeSet&, Distribution*); + void addChild (BayesNode*); + Distribution* getDistribution (void); + const ParamSet& getParameters (void); + ParamSet getRow (int) const; + void setProbability (int, const CptEntry&, double); + bool isRoot (void); + bool isLeaf (void); + bool hasNeighbors (void) const; + int getCptSize (void); + const vector& getCptEntries (void); + int getIndexOfParent (const BayesNode*) const; + string cptEntryToString (const CptEntry&) const; + string cptEntryToString (int, const CptEntry&) const; + // inlines + const NodeSet& getParents (void) const; + const NodeSet& getChilds (void) const; + double getProbability (int, const CptEntry& entry); + unsigned getRowSize (void) const; + + private: + DISALLOW_COPY_AND_ASSIGN (BayesNode); + + Domain getDomainHeaders (void) const; + friend ostream& operator << (ostream&, const BayesNode&); + + NodeSet parents_; + NodeSet childs_; + Distribution* dist_; +}; + +ostream& operator << (ostream&, const BayesNode&); + + + +inline const NodeSet& +BayesNode::getParents (void) const +{ + return parents_; +} + + + +inline const NodeSet& +BayesNode::getChilds (void) const +{ + return childs_; +} + + + +inline double +BayesNode::getProbability (int row, const CptEntry& entry) +{ + int col = entry.getParameterIndex(); + int idx = (row * getRowSize()) + col; + return dist_->params[idx]; +} + + + +inline unsigned +BayesNode::getRowSize (void) const +{ + return dist_->params.size() / getDomainSize(); +} + +#endif + diff --git a/packages/CLPBN/clpbn/bp/BpNode.cpp b/packages/CLPBN/clpbn/bp/BpNode.cpp index 8f784ab16..4fd52f95c 100644 --- a/packages/CLPBN/clpbn/bp/BpNode.cpp +++ b/packages/CLPBN/clpbn/bp/BpNode.cpp @@ -4,226 +4,44 @@ #include "BpNode.h" +bool BpNode::calculateMessageResidual_ = true; -bool BpNode::parallelSchedule_ = false; -BpNode::BpNode (string varName, - vector parents, - Distribution* dist, - int evidence) : BayesianNode (varName, parents, dist, evidence) +BpNode::BpNode (BayesNode* node) { - -} - - - -BpNode::~BpNode (void) -{ - delete [] piValues_; - delete [] lambdaValues_; - delete [] oldBeliefs_; - map::iterator iter; - for (iter = lambdaMessages_.begin(); iter != lambdaMessages_.end(); ++iter) { - delete [] iter->second; + ds_ = node->getDomainSize(); + const NodeSet& childs = node->getChilds(); + piVals_.resize (ds_, 1); + ldVals_.resize (ds_, 1); + if (calculateMessageResidual_) { + piResiduals_.resize (childs.size(), 0.0); + ldResiduals_.resize (childs.size(), 0.0); } - for (iter = piMessages_.begin(); iter != piMessages_.end(); ++iter) { - delete [] iter->second; - } - // FIXME delete new messages -} - - - -void -BpNode::enableParallelSchedule (void) -{ - parallelSchedule_ = true; -} - - - -void -BpNode::allocateMemory (void) -{ - // FIXME do i need this !? - int domainSize = getDomainSize(); - piValues_ = new double [domainSize]; - lambdaValues_ = new double [domainSize]; - if (parallelSchedule_) { - newPiMessages_ = new map; - newLambdaMessages_ = new map; - } - oldBeliefs_ = 0; - vector childs = getChilds(); - for (unsigned int i = 0; i < childs.size(); i++) { - BpNode* child = static_cast (childs[i]); - piMessages_.insert (make_pair (child, new double [domainSize])); - lambdaMessages_.insert (make_pair (child, new double [domainSize])); - if (parallelSchedule_) { - newPiMessages_->insert (make_pair (child, new double [domainSize])); - newLambdaMessages_->insert (make_pair (child, new double [domainSize])); - } + childs_ = &childs; + for (unsigned i = 0; i < childs.size(); i++) { + //indexMap_.insert (make_pair (childs[i]->getVarId(), i)); + currPiMsgs_.push_back (ParamSet (ds_, 1)); + currLdMsgs_.push_back (ParamSet (ds_, 1)); + nextPiMsgs_.push_back (ParamSet (ds_, 1)); + nextLdMsgs_.push_back (ParamSet (ds_, 1)); } } -double* -BpNode::getPiValues (void) const +ParamSet +BpNode::getBeliefs (void) const { - return piValues_; -} - - - -double -BpNode::getPiValue (int index) const -{ - const int c = getDomainSize(); - assert (index >=0 && index < c); - return piValues_[index]; -} - - - -void -BpNode::setPiValue (int index, double value) -{ - const int c = getDomainSize(); - assert (index >=0 && index < c); - piValues_[index] = value; -} - - - -double* -BpNode::getLambdaValues (void) const -{ - return lambdaValues_; -} - - - -double -BpNode::getLambdaValue (int index) const -{ - const int c = getDomainSize(); - assert (index >=0 && index < c); - return lambdaValues_[index]; -} - - - -void -BpNode::setLambdaValue (int index, double value) -{ - const int c = getDomainSize(); - assert (index >=0 && index < c); - lambdaValues_[index] = value; -} - - - -double* -BpNode::getPiMessages (BpNode* node) const -{ - assert (node); - map::const_iterator iter = piMessages_.find (node); - assert (iter != piMessages_.end()); - return iter->second; -} - - - -double -BpNode::getPiMessage (BpNode* node, int index) const -{ - assert (node); - const int c = getDomainSize(); - assert (index >=0 && index < c); - map::const_iterator iter = piMessages_.find (node); - assert (iter != piMessages_.end()); - return iter->second[index]; -} - - - -void -BpNode::setPiMessage (BpNode* node, int index, double probability) -{ - assert (node); - const int c = getDomainSize(); - assert (index >=0 && index < c); - map::const_iterator iter; - if (parallelSchedule_) { - // cerr << "set_pi_message" << endl; - iter = newPiMessages_->find (node); - assert (iter != newPiMessages_->end()); - } else { - iter = piMessages_.find (node); - assert (iter != piMessages_.end()); - } - iter->second[index] = probability; -} - - - -double* -BpNode::getLambdaMessages (BpNode* node) const -{ - assert (node); - map::const_iterator iter = lambdaMessages_.find (node); - assert (iter != piMessages_.end()); - return iter->second; -} - - - -double -BpNode::getLambdaMessage (BpNode* node, int index) const -{ - assert (node); - const int c = getDomainSize(); - assert (index >=0 && index < c); - map::const_iterator iter = lambdaMessages_.find (node); - assert (iter != piMessages_.end()); - return iter->second[index]; -} - - - -void -BpNode::setLambdaMessage (BpNode* node, int index, double probability) -{ - assert (node); - const int c = getDomainSize(); - assert (index >=0 && index < c); - map::const_iterator iter; - if (parallelSchedule_) { - //cerr << "set_lambda_message" << endl; - iter = newLambdaMessages_->find (node); - assert (iter != newLambdaMessages_->end()); - } else { - iter = lambdaMessages_.find (node); - assert (iter != lambdaMessages_.end()); - } - iter->second[index] = probability; -} - - - -double* -BpNode::getBeliefs (void) -{ - double sum = 0.0; - double* beliefs = new double [getDomainSize()]; - for (int xi = 0; xi < getDomainSize(); xi++) { - double prod = piValues_[xi] * lambdaValues_[xi]; + double sum = 0.0; + ParamSet beliefs (ds_); + for (int xi = 0; xi < ds_; xi++) { + double prod = piVals_[xi] * ldVals_[xi]; beliefs[xi] = prod; sum += prod; } - // normalize the beliefs - for (int xi = 0; xi < getDomainSize(); xi++) { + assert (sum); + //normalize the beliefs + for (int xi = 0; xi < ds_; xi++) { beliefs[xi] /= sum; } return beliefs; @@ -231,91 +49,202 @@ BpNode::getBeliefs (void) +double +BpNode::getPiValue (int idx) const +{ + assert (idx >=0 && idx < ds_); + return piVals_[idx]; +} + + + +void +BpNode::setPiValue (int idx, double value) +{ + assert (idx >=0 && idx < ds_); + piVals_[idx] = value; +} + + + +double +BpNode::getLambdaValue (int idx) const +{ + assert (idx >=0 && idx < ds_); + return ldVals_[idx]; +} + + + +void +BpNode::setLambdaValue (int idx, double value) +{ + assert (idx >=0 && idx < ds_); + ldVals_[idx] = value; +} + + + +ParamSet& +BpNode::getPiValues (void) +{ + return piVals_; +} + + + +ParamSet& +BpNode::getLambdaValues (void) +{ + return ldVals_; +} + + + +double +BpNode::getPiMessageValue (const BayesNode* destination, int idx) const +{ + assert (idx >=0 && idx < ds_); + return currPiMsgs_[getIndex(destination)][idx]; +} + + + +double +BpNode::getLambdaMessageValue (const BayesNode* source, int idx) const +{ + assert (idx >=0 && idx < ds_); + return currLdMsgs_[getIndex(source)][idx]; +} + + + +const ParamSet& +BpNode::getPiMessage (const BayesNode* destination) const +{ + return currPiMsgs_[getIndex(destination)]; +} + + + +const ParamSet& +BpNode::getLambdaMessage (const BayesNode* source) const +{ + return currLdMsgs_[getIndex(source)]; +} + + + +ParamSet& +BpNode::piNextMessageReference (const BayesNode* destination) +{ + return nextPiMsgs_[getIndex(destination)]; +} + + + +ParamSet& +BpNode::lambdaNextMessageReference (const BayesNode* source) +{ + return nextLdMsgs_[getIndex(source)]; +} + + + +void +BpNode::updatePiMessage (const BayesNode* destination) +{ + int idx = getIndex (destination); + currPiMsgs_[idx] = nextPiMsgs_[idx]; + Util::normalize (currPiMsgs_[idx]); +} + + + +void +BpNode::updateLambdaMessage (const BayesNode* source) +{ + int idx = getIndex (source); + currLdMsgs_[idx] = nextLdMsgs_[idx]; + Util::normalize (currLdMsgs_[idx]); +} + + + double BpNode::getBeliefChange (void) { double change = 0.0; - if (!oldBeliefs_) { + if (oldBeliefs_.size() == 0) { oldBeliefs_ = getBeliefs(); - change = MAX_CHANGE_; + change = 9999999999.0; } else { - double* currentBeliefs = getBeliefs(); - for (int xi = 0; xi < getDomainSize(); xi++) { + ParamSet currentBeliefs = getBeliefs(); + for (int xi = 0; xi < ds_; xi++) { change += abs (currentBeliefs[xi] - oldBeliefs_[xi]); } oldBeliefs_ = currentBeliefs; } - //FIXME memory leak return change; } void -BpNode::normalizeMessages (void) +BpNode::updatePiResidual (const BayesNode* destination) { - map::iterator iter; - - iter = lambdaMessages_.begin(); - while (iter != lambdaMessages_.end()) { - double* v = iter->second; - double sum = 0.0; - for (int xi = 0; xi < getDomainSize(); xi++) { - sum += v[xi]; - } - for (int xi = 0; xi < getDomainSize(); xi++) { - v[xi] /= sum; - } - iter ++; - } - - iter = piMessages_.begin(); - while (iter != piMessages_.end()) { - double* v = iter->second; - double sum = 0.0; - for (int xi = 0; xi < getDomainSize(); xi++) { - sum += v[xi]; - } - for (int xi = 0; xi < getDomainSize(); xi++) { - v[xi] /= sum; - } - iter ++; - } + int idx = getIndex (destination); + Util::normalize (nextPiMsgs_[idx]); + //piResiduals_[idx] = Util::getL1dist ( + // currPiMsgs_[idx], nextPiMsgs_[idx]); + piResiduals_[idx] = Util::getMaxNorm ( + currPiMsgs_[idx], nextPiMsgs_[idx]); } void -BpNode::swapMessages (void) +BpNode::updateLambdaResidual (const BayesNode* source) { - //FIXME fast way to do this - map::iterator iter1; - map::iterator iter2; - - iter1 = lambdaMessages_.begin(); - iter2 = newLambdaMessages_->begin(); - while (iter1 != lambdaMessages_.end()) { - double* v1 = iter1->second; - double* v2 = iter2->second; - for (int xi = 0; xi < getDomainSize(); xi++) { - //v1[xi] = v2[xi]; - v1[xi] = (v1[xi] + v2[xi]) / 2; - } - iter1 ++; - iter2 ++; - } - - iter1 = piMessages_.begin(); - iter2 = newPiMessages_->begin(); - while (iter1 != piMessages_.end()) { - double* v1 = iter1->second; - double* v2 = iter2->second; - for (int xi = 0; xi < getDomainSize(); xi++) { - //v1[xi] = v2[xi]; - v1[xi] = (v1[xi] + v2[xi]) / 2; - } - iter1 ++; - iter2 ++; - } + int idx = getIndex (source); + Util::normalize (nextLdMsgs_[idx]); + //ldResiduals_[idx] = Util::getL1dist ( + // currLdMsgs_[idx], nextLdMsgs_[idx]); + ldResiduals_[idx] = Util::getMaxNorm ( + currLdMsgs_[idx], nextLdMsgs_[idx]); +} + + + +void +BpNode::clearPiResidual (const BayesNode* destination) +{ + piResiduals_[getIndex(destination)] = 0; +} + + + +void +BpNode::clearLambdaResidual (const BayesNode* source) +{ + ldResiduals_[getIndex(source)] = 0; +} + + + +bool +BpNode::hasReceivedChildInfluence (void) const +{ + // if all lambda values are equal, then neither + // this node neither its descendents have evidence, + // we can use this to don't send lambda messages his parents + bool childInfluenced = false; + for (int xi = 1; xi < ds_; xi++) { + if (ldVals_[xi] != ldVals_[0]) { + childInfluenced = true; + break; + } + } + return childInfluenced; } diff --git a/packages/CLPBN/clpbn/bp/BpNode.h b/packages/CLPBN/clpbn/bp/BpNode.h index 2d796365e..2b84a298d 100644 --- a/packages/CLPBN/clpbn/bp/BpNode.h +++ b/packages/CLPBN/clpbn/bp/BpNode.h @@ -1,56 +1,99 @@ -#ifndef BP_BP_NODE_H -#define BP_BP_NODE_H +#ifndef BP_BPNODE_H +#define BP_BPNODE_H #include #include -#include #include +#include -#include "BayesianNode.h" +#include "BayesNode.h" +#include "Shared.h" using namespace std; -class BpNode : public BayesianNode +class BpNode { public: - // constructs - BpNode (string, vector, Distribution* dist, int = -1); - // destruct - ~BpNode (void); - // methods - static void enableParallelSchedule (void); - void allocateMemory (void); - double* getPiValues (void) const; - double getPiValue (int) const; - void setPiValue (int, double); - double* getLambdaValues (void) const; - double getLambdaValue (int) const; - void setLambdaValue (int, double); - double* getPiMessages (BpNode*) const; - double getPiMessage (BpNode*, int) const; - void setPiMessage (BpNode*, int, double); - double* getLambdaMessages (BpNode*) const; - double getLambdaMessage (BpNode*, int) const; - void setLambdaMessage (BpNode*, int, double); - double* getBeliefs (void); - double getBeliefChange (void); - void normalizeMessages (void); - void swapMessages (void); + BpNode (int); + BpNode (BayesNode*); + + ParamSet getBeliefs (void) const; + double getPiValue (int) const; + void setPiValue (int, double); + double getLambdaValue (int) const; + void setLambdaValue (int, double); + ParamSet& getPiValues (void); + ParamSet& getLambdaValues (void); + double getPiMessageValue (const BayesNode*, int) const; + double getLambdaMessageValue (const BayesNode*, int) const; + const ParamSet& getPiMessage (const BayesNode*) const; + const ParamSet& getLambdaMessage (const BayesNode*) const; + ParamSet& piNextMessageReference (const BayesNode*); + ParamSet& lambdaNextMessageReference (const BayesNode*); + void updatePiMessage (const BayesNode*); + void updateLambdaMessage (const BayesNode*); + double getBeliefChange (void); + void updatePiResidual (const BayesNode*); + void updateLambdaResidual (const BayesNode*); + void clearPiResidual (const BayesNode*); + void clearLambdaResidual (const BayesNode*); + bool hasReceivedChildInfluence (void) const; + // inlines + double getPiResidual (const BayesNode*); + double getLambdaResidual (const BayesNode*); + int getIndex (const BayesNode*) const; private: - BpNode (const BpNode&); // disallow copy - void operator= (const BpNode&); // disallow assign - // members - double* lambdaValues_; - double* piValues_; - map piMessages_; - map lambdaMessages_; - map* newPiMessages_; - map* newLambdaMessages_; - double* oldBeliefs_; - static bool parallelSchedule_; - static const double MAX_CHANGE_ = 1.0; + DISALLOW_COPY_AND_ASSIGN (BpNode); + + IndexMap indexMap_; + ParamSet piVals_; // pi values + ParamSet ldVals_; // lambda values + vector currPiMsgs_; // current pi messages + vector currLdMsgs_; // current lambda messages + vector nextPiMsgs_; + vector nextLdMsgs_; + ParamSet oldBeliefs_; + ParamSet piResiduals_; + ParamSet ldResiduals_; + int ds_; + const NodeSet* childs_; + static bool calculateMessageResidual_; +// static const double MAX_CHANGE_ = 10000000.0; }; -#endif // BP_BP_NODE_H + + +inline double +BpNode::getPiResidual (const BayesNode* destination) +{ + return piResiduals_[getIndex(destination)]; +} + + +inline double +BpNode::getLambdaResidual (const BayesNode* source) +{ + return ldResiduals_[getIndex(source)]; +} + + + +inline int +BpNode::getIndex (const BayesNode* node) const +{ + assert (node); + //assert (indexMap_.find(node->getVarId()) != indexMap_.end()); + //return indexMap_.find(node->getVarId())->second; + for (unsigned i = 0; childs_->size(); i++) { + if ((*childs_)[i]->getVarId() == node->getVarId()) { + return i; + } + } + assert (false); + return -1; +} + + +#endif diff --git a/packages/CLPBN/clpbn/bp/CptEntry.h b/packages/CLPBN/clpbn/bp/CptEntry.h index 7289212d7..9229b2564 100644 --- a/packages/CLPBN/clpbn/bp/CptEntry.h +++ b/packages/CLPBN/clpbn/bp/CptEntry.h @@ -1,23 +1,71 @@ -#ifndef CPT_ENTRY_H -#define CPT_ENTRY_H +#ifndef BP_CPTENTRY_H +#define BP_CPTENTRY_H #include +#include "Shared.h" + using namespace std; class CptEntry { public: - // constructs - CptEntry (int, vector); - // methods - int getCptIndex (void) const; - vector getDomainInstantiations (void) const; - bool matchConstraints (const vector >&) const; + CptEntry (unsigned, const vector&); + + unsigned getParameterIndex (void) const; + const vector& getParentConfigurations (void) const; + bool matchConstraints (const DomainConstr&) const; + bool matchConstraints (const vector&) const; + private: - // members - int cptIndex_; - vector instantiations_; + unsigned index_; + vector confs_; }; -#endif // CPT_ENTRY_H + + +inline +CptEntry::CptEntry (unsigned index, const vector& confs) +{ + index_ = index; + confs_ = confs; +} + + + +inline unsigned +CptEntry::getParameterIndex (void) const +{ + return index_; +} + + + +inline const vector& +CptEntry::getParentConfigurations (void) const +{ + return confs_; +} + + + +inline bool +CptEntry::matchConstraints (const DomainConstr& constr) const +{ + return confs_[constr.first] == constr.second; +} + + + +inline bool +CptEntry::matchConstraints (const vector& constrs) const +{ + for (unsigned j = 0; j < constrs.size(); j++) { + if (confs_[constrs[j].first] != constrs[j].second) { + return false; + } + } + return true; +} + +#endif diff --git a/packages/CLPBN/clpbn/bp/Distribution.h b/packages/CLPBN/clpbn/bp/Distribution.h index 51a540b4c..63b562be4 100644 --- a/packages/CLPBN/clpbn/bp/Distribution.h +++ b/packages/CLPBN/clpbn/bp/Distribution.h @@ -1,24 +1,40 @@ -#ifndef DISTRIBUTION_H -#define DISTRIBUTION_H +#ifndef BP_DISTRIBUTION_H +#define BP_DISTRIBUTION_H #include #include +#include "Shared.h" + using namespace std; -class CptEntry; - -class Distribution +struct Distribution { public: - Distribution (int, double*, int, vector); - Distribution (double*, int, vector); - int id; - double* params; - int nParams; - vector domain; - int* offsets; + Distribution (unsigned id) + { + this->id = id; + this->params = params; + } + + Distribution (const ParamSet& params) + { + this->id = -1; + this->params = params; + } + + void updateParameters (const ParamSet& params) + { + this->params = params; + } + + unsigned id; + ParamSet params; + vector entries; + + private: + DISALLOW_COPY_AND_ASSIGN (Distribution); }; -#endif // DISTRIBUTION +#endif diff --git a/packages/CLPBN/clpbn/bp/Factor.cpp b/packages/CLPBN/clpbn/bp/Factor.cpp new file mode 100755 index 000000000..66d2296e0 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/Factor.cpp @@ -0,0 +1,346 @@ +#include +#include +#include +#include + +#include "Factor.h" +#include "FgVarNode.h" + + +int Factor::indexCount_ = 0; + +Factor::Factor (FgVarNode* var) { + vs_.push_back (var); + int nParams = var->getDomainSize(); + // create a uniform distribution + double val = 1.0 / nParams; + ps_ = ParamSet (nParams, val); + id_ = indexCount_; + indexCount_ ++; +} + + + +Factor::Factor (const FgVarSet& vars) { + vs_ = vars; + int nParams = 1; + for (unsigned i = 0; i < vs_.size(); i++) { + nParams *= vs_[i]->getDomainSize(); + } + // create a uniform distribution + double val = 1.0 / nParams; + ps_ = ParamSet (nParams, val); + id_ = indexCount_; + indexCount_ ++; +} + + + +Factor::Factor (FgVarNode* var, + const ParamSet& params) +{ + vs_.push_back (var); + ps_ = params; + id_ = indexCount_; + indexCount_ ++; +} + + + +Factor::Factor (const FgVarSet& vars, + const ParamSet& params) +{ + vs_ = vars; + ps_ = params; + id_ = indexCount_; + indexCount_ ++; +} + + + +const FgVarSet& +Factor::getFgVarNodes (void) const +{ + return vs_; +} + + + +FgVarSet& +Factor::getFgVarNodes (void) +{ + return vs_; +} + + + +const ParamSet& +Factor::getParameters (void) const +{ + return ps_; +} + + + +ParamSet& +Factor::getParameters (void) +{ + return ps_; +} + + + +void +Factor::setParameters (const ParamSet& params) +{ + //cout << "ps size: " << ps_.size() << endl; + //cout << "params size: " << params.size() << endl; + assert (ps_.size() == params.size()); + ps_ = params; +} + + + +Factor& +Factor::operator= (const Factor& g) +{ + FgVarSet vars = g.getFgVarNodes(); + ParamSet params = g.getParameters(); + return *this; +} + + + +Factor& +Factor::operator*= (const Factor& g) +{ + FgVarSet gVs = g.getFgVarNodes(); + const ParamSet& gPs = g.getParameters(); + + bool hasCommonVars = false; + vector varIndexes; + for (unsigned i = 0; i < gVs.size(); i++) { + int idx = getIndexOf (gVs[i]); + if (idx == -1) { + insertVariable (gVs[i]); + varIndexes.push_back (vs_.size() - 1); + } else { + hasCommonVars = true; + varIndexes.push_back (idx); + } + } + + if (hasCommonVars) { + vector offsets (gVs.size()); + offsets[gVs.size() - 1] = 1; + for (int i = gVs.size() - 2; i >= 0; i--) { + offsets[i] = offsets[i + 1] * gVs[i + 1]->getDomainSize(); + } + vector entries = getCptEntries(); + for (unsigned i = 0; i < entries.size(); i++) { + int idx = 0; + const DomainConf conf = entries[i].getParentConfigurations(); + for (unsigned j = 0; j < varIndexes.size(); j++) { + idx += offsets[j] * conf[varIndexes[j]]; + } + //cout << "ps_[" << i << "] = " << ps_[i] << " * " ; + //cout << gPs[idx] << " , idx = " << idx << endl; + ps_[i] = ps_[i] * gPs[idx]; + } + } else { + // if the originally factors doesn't have common factors. + // we don't have to make domain comparations + unsigned idx = 0; + for (unsigned i = 0; i < ps_.size(); i++) { + //cout << "ps_[" << i << "] = " << ps_[i] << " * " ; + //cout << gPs[idx] << " , idx = " << idx << endl; + ps_[i] = ps_[i] * gPs[idx]; + idx ++; + if (idx >= gPs.size()) { + idx = 0; + } + } + } + return *this; +} + + + +void +Factor::insertVariable (FgVarNode* var) +{ + int c = 0; + ParamSet newPs (ps_.size() * var->getDomainSize()); + for (unsigned i = 0; i < ps_.size(); i++) { + for (int j = 0; j < var->getDomainSize(); j++) { + newPs[c] = ps_[i]; + c ++; + } + } + vs_.push_back (var); + ps_ = newPs; +} + + + +void +Factor::marginalizeVariable (const FgVarNode* var) { + int varIndex = getIndexOf (var); + marginalizeVariable (varIndex); +} + + + +void +Factor::marginalizeVariable (unsigned varIndex) +{ + assert (varIndex >= 0 && varIndex < vs_.size()); + int distOffset = 1; + int leftVarOffset = 1; + for (unsigned i = vs_.size() - 1; i > varIndex; i--) { + distOffset *= vs_[i]->getDomainSize(); + leftVarOffset *= vs_[i]->getDomainSize(); + } + leftVarOffset *= vs_[varIndex]->getDomainSize(); + + int ds = vs_[varIndex]->getDomainSize(); + int count = 0; + int offset = 0; + int startIndex = 0; + int currDomainIdx = 0; + unsigned newPsSize = ps_.size() / ds; + ParamSet newPs; + newPs.reserve (newPsSize); + + stringstream ss; + ss << "marginalizing " << vs_[varIndex]->getLabel(); + ss << " from factor " << getLabel() << endl; + while (newPs.size() < newPsSize) { + ss << " sum = "; + double sum = 0.0; + for (int j = 0; j < ds; j++) { + if (j != 0) ss << " + "; + ss << ps_[offset]; + sum = sum + ps_[offset]; + offset = offset + distOffset; + } + newPs.push_back (sum); + count ++; + if (varIndex == vs_.size() - 1) { + offset = count * ds; + } else { + offset = offset - distOffset + 1; + if ((offset % leftVarOffset) == 0) { + currDomainIdx ++; + startIndex = leftVarOffset * currDomainIdx; + offset = startIndex; + count = 0; + } else { + offset = startIndex + count; + } + } + ss << " = " << sum << endl; + } + //cout << ss.str() << endl; + ps_ = newPs; + vs_.erase (vs_.begin() + varIndex); +} + + + +string +Factor::getLabel (void) const +{ + stringstream ss; + ss << "f(" ; + // ss << "Φ(" ; + for (unsigned i = 0; i < vs_.size(); i++) { + if (i != 0) ss << ", " ; + ss << "v" << vs_[i]->getVarId(); + } + ss << ")" ; + return ss.str(); +} + + + +string +Factor::toString (void) const +{ + stringstream ss; + ss << "vars: " ; + for (unsigned i = 0; i < vs_.size(); i++) { + if (i != 0) ss << ", " ; + ss << "v" << vs_[i]->getVarId(); + } + ss << endl; + vector entries = getCptEntries(); + for (unsigned i = 0; i < entries.size(); i++) { + ss << "Φ(" ; + char s = 'a' ; + const DomainConf& conf = entries[i].getParentConfigurations(); + for (unsigned j = 0; j < conf.size(); j++) { + if (j != 0) ss << "," ; + ss << s << conf[j] + 1; + s++; + } + ss << ") = " << ps_[entries[i].getParameterIndex()] << endl; + } + return ss.str(); +} + + + +vector +Factor::getCptEntries (void) const +{ + vector confs (ps_.size()); + for (unsigned i = 0; i < ps_.size(); i++) { + confs[i].resize (vs_.size()); + } + + int nReps = 1; + for (int i = vs_.size() - 1; i >= 0; i--) { + unsigned index = 0; + while (index < ps_.size()) { + for (int j = 0; j < vs_[i]->getDomainSize(); j++) { + for (int r = 0; r < nReps; r++) { + confs[index][i] = j; + index++; + } + } + } + nReps *= vs_[i]->getDomainSize(); + } + + vector entries; + for (unsigned i = 0; i < ps_.size(); i++) { + for (unsigned j = 0; j < vs_.size(); j++) { + } + entries.push_back (CptEntry (i, confs[i])); + } + return entries; +} + + + +int +Factor::getIndexOf (const FgVarNode* var) const +{ + for (unsigned i = 0; i < vs_.size(); i++) { + if (vs_[i] == var) { + return i; + } + } + return -1; +} + + + +Factor operator* (const Factor& f, const Factor& g) +{ + Factor r = f; + r *= g; + return r; +} + diff --git a/packages/CLPBN/clpbn/bp/Factor.h b/packages/CLPBN/clpbn/bp/Factor.h new file mode 100755 index 000000000..71b14df07 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/Factor.h @@ -0,0 +1,45 @@ +#ifndef BP_FACTOR_H +#define BP_FACTOR_H + +#include + +#include "CptEntry.h" + +using namespace std; + +class FgVarNode; + +class Factor +{ + public: + Factor (FgVarNode*); + Factor (const FgVarSet&); + Factor (FgVarNode*, const ParamSet&); + Factor (const FgVarSet&, const ParamSet&); + + const FgVarSet& getFgVarNodes (void) const; + FgVarSet& getFgVarNodes (void); + const ParamSet& getParameters (void) const; + ParamSet& getParameters (void); + void setParameters (const ParamSet&); + Factor& operator= (const Factor& f); + Factor& operator*= (const Factor& f); + void insertVariable (FgVarNode* index); + void marginalizeVariable (const FgVarNode* var); + void marginalizeVariable (unsigned); + string getLabel (void) const; + string toString (void) const; + + private: + vector getCptEntries() const; + int getIndexOf (const FgVarNode*) const; + + FgVarSet vs_; + ParamSet ps_; + int id_; + static int indexCount_; +}; + +Factor operator* (const Factor&, const Factor&); + +#endif diff --git a/packages/CLPBN/clpbn/bp/FactorGraph.cpp b/packages/CLPBN/clpbn/bp/FactorGraph.cpp new file mode 100755 index 000000000..0a85d2b5b --- /dev/null +++ b/packages/CLPBN/clpbn/bp/FactorGraph.cpp @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include + +#include "FactorGraph.h" +#include "FgVarNode.h" +#include "Factor.h" + + +FactorGraph::FactorGraph (const char* fileName) +{ + string line; + ifstream is (fileName); + if (!is.is_open()) { + cerr << "error: cannot read from file " + std::string (fileName) << endl; + abort(); + } + + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + getline (is, line); + if (line != "MARKOV") { + cerr << "error: the network must be a MARKOV network " << endl; + abort(); + } + + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + int nVars; + is >> nVars; + + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + vector domainSizes (nVars); + for (int i = 0; i < nVars; i++) { + int ds; + is >> ds; + domainSizes[i] = ds; + } + + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + for (int i = 0; i < nVars; i++) { + varNodes_.push_back (new FgVarNode (i, domainSizes[i])); + } + + int nFactors; + is >> nFactors; + for (int i = 0; i < nFactors; i++) { + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + int nFactorVars; + is >> nFactorVars; + FgVarSet factorVars; + for (int j = 0; j < nFactorVars; j++) { + int varId; + is >> varId; + FgVarNode* var = getVariableById (varId); + if (var == 0) { + cerr << "error: invalid variable identifier (" << varId << ")" << endl; + abort(); + } + factorVars.push_back (var); + } + Factor* f = new Factor (factorVars); + factors_.push_back (f); + for (unsigned j = 0; j < factorVars.size(); j++) { + factorVars[j]->addFactor (f); + } + } + + for (int i = 0; i < nFactors; i++) { + while (is.peek() == '#' || is.peek() == '\n') getline (is, line); + int nParams; + is >> nParams; + ParamSet params (nParams); + for (int j = 0; j < nParams; j++) { + double param; + is >> param; + params[j] = param; + } + factors_[i]->setParameters (params); + } + is.close(); + + for (unsigned i = 0; i < varNodes_.size(); i++) { + varNodes_[i]->setIndex (i); + } +} + + + +FactorGraph::~FactorGraph (void) +{ + for (unsigned i = 0; i < varNodes_.size(); i++) { + delete varNodes_[i]; + } + for (unsigned i = 0; i < factors_.size(); i++) { + delete factors_[i]; + } +} + + + +FgVarSet +FactorGraph::getFgVarNodes (void) const +{ + return varNodes_; +} + + + +vector +FactorGraph::getFactors (void) const +{ + return factors_; +} + + + +VarSet +FactorGraph::getVariables (void) const +{ + VarSet vars; + for (unsigned i = 0; i < varNodes_.size(); i++) { + vars.push_back (varNodes_[i]); + } + return vars; +} + + + +FgVarNode* +FactorGraph::getVariableById (unsigned id) const +{ + for (unsigned i = 0; i < varNodes_.size(); i++) { + if (varNodes_[i]->getVarId() == id) { + return varNodes_[i]; + } + } + return 0; +} + + + +FgVarNode* +FactorGraph::getVariableByLabel (string label) const +{ + for (unsigned i = 0; i < varNodes_.size(); i++) { + stringstream ss; + ss << "v" << varNodes_[i]->getVarId(); + if (ss.str() == label) { + return varNodes_[i]; + } + } + return 0; +} + + + +void +FactorGraph::printFactorGraph (void) const +{ + for (unsigned i = 0; i < varNodes_.size(); i++) { + cout << "variable number " << varNodes_[i]->getIndex() << endl; + cout << "Id = " << varNodes_[i]->getVarId() << endl; + cout << "Domain size = " << varNodes_[i]->getDomainSize() << endl; + cout << "Evidence = " << varNodes_[i]->getEvidence() << endl; + cout << endl; + } + cout << endl; + for (unsigned i = 0; i < factors_.size(); i++) { + cout << factors_[i]->toString() << endl; + } +} + diff --git a/packages/CLPBN/clpbn/bp/FactorGraph.h b/packages/CLPBN/clpbn/bp/FactorGraph.h new file mode 100755 index 000000000..9809f25b8 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/FactorGraph.h @@ -0,0 +1,35 @@ +#ifndef BP_FACTORGRAPH_H +#define BP_FACTORGRAPH_H + +#include +#include + +#include "GraphicalModel.h" +#include "Shared.h" + +using namespace std; + +class FgVarNode; +class Factor; + +class FactorGraph : public GraphicalModel +{ + public: + FactorGraph (const char* fileName); + ~FactorGraph (void); + + FgVarSet getFgVarNodes (void) const; + vector getFactors (void) const; + VarSet getVariables (void) const; + FgVarNode* getVariableById (unsigned) const; + FgVarNode* getVariableByLabel (string) const; + void printFactorGraph (void) const; + + private: + DISALLOW_COPY_AND_ASSIGN (FactorGraph); + + FgVarSet varNodes_; + vector factors_; +}; + +#endif diff --git a/packages/CLPBN/clpbn/bp/FgVarNode.h b/packages/CLPBN/clpbn/bp/FgVarNode.h new file mode 100755 index 000000000..e82ab0c52 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/FgVarNode.h @@ -0,0 +1,28 @@ +#ifndef BP_VARIABLE_H +#define BP_VARIABLE_H + +#include +#include + +#include "Variable.h" +#include "Shared.h" + +using namespace std; + +class Factor; + +class FgVarNode : public Variable +{ + public: + FgVarNode (int varId, int dsize) : Variable (varId, dsize) { } + + void addFactor (Factor* f) { factors_.push_back (f); } + vector getFactors (void) const { return factors_; } + + private: + DISALLOW_COPY_AND_ASSIGN (FgVarNode); + // members + vector factors_; +}; + +#endif // BP_VARIABLE_H diff --git a/packages/CLPBN/clpbn/bp/GraphicalModel.h b/packages/CLPBN/clpbn/bp/GraphicalModel.h new file mode 100755 index 000000000..4aaf4baf3 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/GraphicalModel.h @@ -0,0 +1,17 @@ +#ifndef BP_GRAPHICALMODEL_H +#define BP_GRAPHICALMODEL_H + +#include "Variable.h" +#include "Shared.h" + +using namespace std; + +class GraphicalModel +{ + public: + virtual VarSet getVariables (void) const = 0; + + private: +}; + +#endif diff --git a/packages/CLPBN/clpbn/bp/HorusCli.cpp b/packages/CLPBN/clpbn/bp/HorusCli.cpp new file mode 100755 index 000000000..a4619566f --- /dev/null +++ b/packages/CLPBN/clpbn/bp/HorusCli.cpp @@ -0,0 +1,214 @@ +#include +#include +#include + +#include "BayesNet.h" +#include "BPSolver.h" + +#include "FactorGraph.h" +#include "SPSolver.h" + +using namespace std; + +void BayesianNetwork (int, const char* []); +void markovNetwork (int, const char* []); + +const string USAGE = "usage: \ +./hcli FILE [VARIABLE | OBSERVED_VARIABLE=EVIDENCE]..." ; + + +int +main (int argc, const char* argv[]) +{ + if (!argv[1]) { + cerr << "error: no graphical model specified" << endl; + cerr << USAGE << endl; + exit (0); + } + string fileName = argv[1]; + string extension = fileName.substr (fileName.find_last_of ('.') + 1); + if (extension == "xml") { + BayesianNetwork (argc, argv); + } else if (extension == "uai") { + markovNetwork (argc, argv); + } else { + cerr << "error: the graphical model must be defined either " ; + cerr << "in a xml file or uai file" << endl; + exit (0); + } + return 0; +} + + + +void +BayesianNetwork (int argc, const char* argv[]) +{ + BayesNet bn (argv[1]); + //bn.printNetwork(); + + NodeSet queryVars; + for (int i = 2; i < argc; i++) { + string arg = argv[i]; + if (arg.find ('=') == std::string::npos) { + BayesNode* queryVar = bn.getNode (arg); + if (queryVar) { + queryVars.push_back (queryVar); + } else { + cerr << "error: there isn't a variable labeled of " ; + cerr << "`" << arg << "'" ; + cerr << endl; + exit (0); + } + } else { + size_t pos = arg.find ('='); + string label = arg.substr (0, pos); + string state = arg.substr (pos + 1); + if (label.empty()) { + cerr << "error: missing left argument" << endl; + cerr << USAGE << endl; + exit (0); + } + if (state.empty()) { + cerr << "error: missing right argument" << endl; + cerr << USAGE << endl; + exit (0); + } + BayesNode* node = bn.getNode (label); + if (node) { + if (node->isValidState (state)) { + node->setEvidence (state); + } else { + cerr << "error: `" << state << "' " ; + cerr << "is not a valid state for " ; + cerr << "`" << node->getLabel() << "'" ; + cerr << endl; + exit (0); + } + } else { + cerr << "error: there isn't a variable labeled of " ; + cerr << "`" << label << "'" ; + cerr << endl; + exit (0); + } + } + } + + BPSolver solver (bn); + if (queryVars.size() == 0) { + solver.runSolver(); + solver.printAllPosterioris(); + } else if (queryVars.size() == 1) { + solver.runSolver(); + solver.printPosterioriOf (queryVars[0]); + } else { + Domain domain = BayesNet::getInstantiations(queryVars); + ParamSet params = solver.getJointDistribution (queryVars); + for (unsigned i = 0; i < params.size(); i++) { + cout << domain[i] << "\t" << params[i] << endl; + } + } + bn.freeDistributions(); +} + + + +void +markovNetwork (int argc, const char* argv[]) +{ + FactorGraph fg (argv[1]); + //fg.printFactorGraph(); + + VarSet queryVars; + for (int i = 2; i < argc; i++) { + string arg = argv[i]; + if (arg.find ('=') == std::string::npos) { + if (!Util::isInteger (arg)) { + cerr << "error: `" << arg << "' " ; + cerr << "is not a valid variable id" ; + cerr << endl; + exit (0); + } + unsigned varId; + stringstream ss; + ss << arg; + ss >> varId; + Variable* queryVar = fg.getVariableById (varId); + if (queryVar) { + queryVars.push_back (queryVar); + } else { + cerr << "error: there isn't a variable with " ; + cerr << "`" << varId << "' as id" ; + cerr << endl; + exit (0); + } + } else { + size_t pos = arg.find ('='); + if (arg.substr (0, pos).empty()) { + cerr << "error: missing left argument" << endl; + cerr << USAGE << endl; + exit (0); + } + if (arg.substr (pos + 1).empty()) { + cerr << "error: missing right argument" << endl; + cerr << USAGE << endl; + exit (0); + } + if (!Util::isInteger (arg.substr (0, pos))) { + cerr << "error: `" << arg.substr (0, pos) << "' " ; + cerr << "is not a variable id" ; + cerr << endl; + exit (0); + } + unsigned varId; + stringstream ss; + ss << arg.substr (0, pos); + ss >> varId; + Variable* var = fg.getVariableById (varId); + if (var) { + if (!Util::isInteger (arg.substr (pos + 1))) { + cerr << "error: `" << arg.substr (pos + 1) << "' " ; + cerr << "is not a state index" ; + cerr << endl; + exit (0); + } + int stateIndex; + stringstream ss; + ss << arg.substr (pos + 1); + ss >> stateIndex; + cout << "si: " << stateIndex << endl; + if (var->isValidStateIndex (stateIndex)) { + var->setEvidence (stateIndex); + } else { + cerr << "error: `" << stateIndex << "' " ; + cerr << "is not a valid state index for variable " ; + cerr << "`" << var->getVarId() << "'" ; + cerr << endl; + exit (0); + } + } else { + cerr << "error: there isn't a variable with " ; + cerr << "`" << varId << "' as id" ; + cerr << endl; + exit (0); + } + } + } + + SPSolver solver (fg); + if (queryVars.size() == 0) { + solver.runSolver(); + solver.printAllPosterioris(); + } else if (queryVars.size() == 1) { + solver.runSolver(); + solver.printPosterioriOf (queryVars[0]); + } else { + assert (false); //FIXME + //Domain domain = BayesNet::getInstantiations(queryVars); + //ParamSet params = solver.getJointDistribution (queryVars); + //for (unsigned i = 0; i < params.size(); i++) { + // cout << domain[i] << "\t" << params[i] << endl; + //} + } +} + diff --git a/packages/CLPBN/clpbn/bp/HorusYap.cpp b/packages/CLPBN/clpbn/bp/HorusYap.cpp new file mode 100755 index 000000000..eb2cbfa95 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/HorusYap.cpp @@ -0,0 +1,229 @@ +#include +#include +#include +#include +#include + +#include + +#include "callgrind.h" + +#include "BayesNet.h" +#include "BayesNode.h" +#include "BPSolver.h" + +using namespace std; + +int +createNetwork (void) +{ + Statistics::numCreatedNets ++; + cout << "creating network number " << Statistics::numCreatedNets << endl; + if (Statistics::numCreatedNets == 1) { + //CALLGRIND_START_INSTRUMENTATION; + } + BayesNet* bn = new BayesNet(); + + YAP_Term varList = YAP_ARG1; + while (varList != YAP_TermNil()) { + YAP_Term var = YAP_HeadOfTerm (varList); + unsigned varId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (1, var)); + unsigned dsize = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (2, var)); + int evidence = (int) YAP_IntOfTerm (YAP_ArgOfTerm (3, var)); + YAP_Term parentL = YAP_ArgOfTerm (4, var); + unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (5, var)); + NodeSet parents; + while (parentL != YAP_TermNil()) { + unsigned parentId = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (parentL)); + BayesNode* parent = bn->getNode (parentId); + if (!parent) { + parent = bn->addNode (parentId); + } + parents.push_back (parent); + parentL = YAP_TailOfTerm (parentL); + } + Distribution* dist = bn->getDistribution (distId); + if (!dist) { + dist = new Distribution (distId); + bn->addDistribution (dist); + } + BayesNode* node = bn->getNode (varId); + if (node) { + node->setData (dsize, evidence, parents, dist); + } else { + bn->addNode (varId, dsize, evidence, parents, dist); + } + varList = YAP_TailOfTerm (varList); + } + bn->setIndexes(); + + if (Statistics::numCreatedNets == 1688) { + Statistics::writeStats(); + //Statistics::writeStats(); + //CALLGRIND_STOP_INSTRUMENTATION; + //CALLGRIND_DUMP_STATS; + //exit (0); + } + YAP_Int p = (YAP_Int) (bn); + return YAP_Unify (YAP_MkIntTerm (p), YAP_ARG2); +} + + + +int +setExtraVarsInfo (void) +{ + BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1); + YAP_Term varsInfoL = YAP_ARG2; + while (varsInfoL != YAP_TermNil()) { + YAP_Term head = YAP_HeadOfTerm (varsInfoL); + unsigned varId = YAP_IntOfTerm (YAP_ArgOfTerm (1, head)); + YAP_Atom label = YAP_AtomOfTerm (YAP_ArgOfTerm (2, head)); + YAP_Term domainL = YAP_ArgOfTerm (3, head); + Domain domain; + while (domainL != YAP_TermNil()) { + YAP_Atom atom = YAP_AtomOfTerm (YAP_HeadOfTerm (domainL)); + domain.push_back ((char*) YAP_AtomName (atom)); + domainL = YAP_TailOfTerm (domainL); + } + BayesNode* node = bn->getNode (varId); + assert (node); + node->setLabel ((char*) YAP_AtomName (label)); + node->setDomain (domain); + varsInfoL = YAP_TailOfTerm (varsInfoL); + } + return TRUE; +} + + + +int +setParameters (void) +{ + BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1); + YAP_Term distList = YAP_ARG2; + while (distList != YAP_TermNil()) { + YAP_Term dist = YAP_HeadOfTerm (distList); + unsigned distId = (unsigned) YAP_IntOfTerm (YAP_ArgOfTerm (1, dist)); + YAP_Term paramL = YAP_ArgOfTerm (2, dist); + ParamSet params; + while (paramL!= YAP_TermNil()) { + params.push_back ((double) YAP_FloatOfTerm (YAP_HeadOfTerm (paramL))); + paramL = YAP_TailOfTerm (paramL); + } + bn->getDistribution(distId)->updateParameters(params); + distList = YAP_TailOfTerm (distList); + } + return TRUE; +} + + + +int +runSolver (void) +{ + BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1); + YAP_Term taskList = YAP_ARG2; + + vector tasks; + NodeSet marginalVars; + + while (taskList != YAP_TermNil()) { + if (YAP_IsPairTerm (YAP_HeadOfTerm (taskList))) { + NodeSet jointVars; + YAP_Term jointList = YAP_HeadOfTerm (taskList); + while (jointList != YAP_TermNil()) { + unsigned varId = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (jointList)); + assert (bn->getNode (varId)); + jointVars.push_back (bn->getNode (varId)); + jointList = YAP_TailOfTerm (jointList); + } + tasks.push_back (jointVars); + } else { + unsigned varId = (unsigned) YAP_IntOfTerm (YAP_HeadOfTerm (taskList)); + BayesNode* node = bn->getNode (varId); + assert (node); + tasks.push_back (NodeSet() = {node}); + marginalVars.push_back (node); + } + taskList = YAP_TailOfTerm (taskList); + } + /* + cout << "tasks to resolve:" << endl; + for (unsigned i = 0; i < tasks.size(); i++) { + cout << "i" << ": " ; + if (tasks[i].size() == 1) { + cout << tasks[i][0]->getVarId() << endl; + } else { + for (unsigned j = 0; j < tasks[i].size(); j++) { + cout << tasks[i][j]->getVarId() << " " ; + } + cout << endl; + } + } + */ + + cerr << "prunning now..." << endl; + BayesNet* prunedNet = bn->pruneNetwork (marginalVars); + bn->printNetworkToFile ("net.txt"); + BPSolver solver (*prunedNet); + cerr << "solving marginals now..." << endl; + solver.runSolver(); + cerr << "calculating joints now ..." << endl; + + vector results; + results.reserve (tasks.size()); + for (unsigned i = 0; i < tasks.size(); i++) { + if (tasks[i].size() == 1) { + BayesNode* node = prunedNet->getNode (tasks[i][0]->getVarId()); + results.push_back (solver.getPosterioriOf (node)); + } else { + BPSolver solver2 (*bn); + cout << "calculating an join dist on: " ; + for (unsigned j = 0; j < tasks[i].size(); j++) { + cout << tasks[i][j]->getVarId() << " " ; + } + cout << "..." << endl; + results.push_back (solver2.getJointDistribution (tasks[i])); + } + } + + delete prunedNet; + + YAP_Term list = YAP_TermNil(); + for (int i = results.size() - 1; i >= 0; i--) { + const ParamSet& beliefs = results[i]; + YAP_Term queryBeliefsL = YAP_TermNil(); + for (int j = beliefs.size() - 1; j >= 0; j--) { + YAP_Term belief = YAP_MkFloatTerm (beliefs[j]); + queryBeliefsL = YAP_MkPairTerm (belief, queryBeliefsL); + } + list = YAP_MkPairTerm (queryBeliefsL, list); + } + + return YAP_Unify (list, YAP_ARG3); +} + + + +int +deleteBayesNet (void) +{ + BayesNet* bn = (BayesNet*) YAP_IntOfTerm (YAP_ARG1); + bn->freeDistributions(); + delete bn; + return TRUE; +} + + + +extern "C" void +init_predicates (void) +{ + YAP_UserCPredicate ("create_network", createNetwork, 2); + YAP_UserCPredicate ("set_extra_vars_info", setExtraVarsInfo, 2); + YAP_UserCPredicate ("set_parameters", setParameters, 2); + YAP_UserCPredicate ("run_solver", runSolver, 3); + YAP_UserCPredicate ("delete_bayes_net", deleteBayesNet, 1); +} + diff --git a/packages/CLPBN/clpbn/bp/Makefile.in b/packages/CLPBN/clpbn/bp/Makefile.in index 201e1e76b..10f192755 100755 --- a/packages/CLPBN/clpbn/bp/Makefile.in +++ b/packages/CLPBN/clpbn/bp/Makefile.in @@ -21,7 +21,17 @@ YAPLIBDIR=@libdir@/Yap # CC=@CC@ CXX=@CXX@ -CXXFLAGS= @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ + +# normal +CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -DNDEBUG + +# debug +#CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -g -O0 + +# profiling (callgrind) +#CXXFLAGS= -std=c++0x @SHLIB_CXXFLAGS@ $(YAP_EXTRAS) $(DEFS) -D_YAP_NOT_INSTALLED_=1 -I$(srcdir) -I../../../.. -I$(srcdir)/../../../../include @CPPFLAGS@ -g -DNDEBUG + + # # # You shouldn't need to change what follows. @@ -38,64 +48,75 @@ CWD=$(PWD) HEADERS = \ - $(srcdir)/BayesianNetwork.h \ - $(srcdir)/BayesianNode.h \ - $(srcdir)/BpNetwork.h \ - $(srcdir)/BpNode.h \ + $(srcdir)/GraphicalModel.h \ + $(srcdir)/Variable.h \ + $(srcdir)/BayesNet.h \ + $(srcdir)/BayesNode.h \ $(srcdir)/Distribution.h \ $(srcdir)/CptEntry.h \ - $(srcdir)/BifInterface.h \ + $(srcdir)/FactorGraph.h \ + $(srcdir)/FgVarNode.h \ + $(srcdir)/Factor.h \ + $(srcdir)/Solver.h \ + $(srcdir)/BPSolver.h \ + $(srcdir)/BpNode.h \ + $(srcdir)/SPSolver.h \ + $(srcdir)/Shared.h \ $(srcdir)/xmlParser/xmlParser.h - + CPP_SOURCES = \ - $(srcdir)/BayesianNetwork.cpp \ - $(srcdir)/BayesianNode.cpp \ - $(srcdir)/BpNetwork.cpp \ + $(srcdir)/BayesNet.cpp \ + $(srcdir)/BayesNode.cpp \ + $(srcdir)/FactorGraph.cpp \ + $(srcdir)/Factor.cpp \ + $(srcdir)/BPSolver.cpp \ $(srcdir)/BpNode.cpp \ - $(srcdir)/Distribution.cpp \ - $(srcdir)/CptEntry.cpp \ - $(srcdir)/Horus.cpp \ - $(srcdir)/BifInterface.cpp \ - $(srcdir)/BifTest.cpp \ + $(srcdir)/SPSolver.cpp \ + $(srcdir)/HorusYap.cpp \ + $(srcdir)/HorusCli.cpp \ $(srcdir)/xmlParser/xmlParser.cpp OBJS = \ - BayesianNetwork.o \ - BayesianNode.o \ - BpNetwork.o \ + BayesNet.o \ + BayesNode.o \ + FactorGraph.o \ + Factor.o \ + BPSolver.o \ BpNode.o \ - Distribution.o \ - CptEntry.o \ - Horus.o + SPSolver.o \ + HorusYap.o -BIF_OBJS = \ - BayesianNetwork.o \ - BayesianNode.o \ - BpNetwork.o \ - BpNode.o \ - Distribution.o \ - CptEntry.o \ - BifInterface.o \ - BifTest.o \ - xmlParser.o +HCLI_OBJS = \ + BayesNet.o \ + BayesNode.o \ + FactorGraph.o \ + Factor.o \ + BPSolver.o \ + BpNode.o \ + SPSolver.o \ + HorusCli.o \ + xmlParser.o SOBJS=horus.@SO@ -all: $(SOBJS) biftest +all: $(SOBJS) hcli # default rule +%.o : $(srcdir)/%.cpp + $(CXX) -c $(CXXFLAGS) $< -o $@ + + xmlParser.o : $(srcdir)/xmlParser/xmlParser.cpp $(CXX) -c $(CXXFLAGS) $< -o $@ -%.o : $(srcdir)/%.cpp - $(CXX) -c $(CXXFLAGS) $< -o $@ @DO_SECOND_LD@horus.@SO@: $(OBJS) @DO_SECOND_LD@ @SHLIB_CXX_LD@ -o horus.@SO@ $(OBJS) @EXTRA_LIBS_FOR_SWIDLLS@ -biftest: $(BIF_OBJS) - $(CXX) -o biftest $(BIF_OBJS) + +hcli: $(HCLI_OBJS) + $(CXX) -o hcli $(HCLI_OBJS) install: all @@ -103,12 +124,12 @@ install: all clean: - rm -f *.o *~ $(OBJS) $(SOBJS) *.BAK biftest xmlParser/*.o + rm -f *.o *~ $(OBJS) $(SOBJS) *.BAK hcli xmlParser/*.o depend: $(HEADERS) $(CPP_SOURCES) -@if test "$(GCC)" = yes; then\ - $(CC) -MM -MG $(CFLAGS) -I$(srcdir) -I$(srcdir)/../../../../include -I$(srcdir)/../../../../H $(CPP_SOURCES) >> Makefile;\ + $(CC) -std=c++0x -MM -MG $(CFLAGS) -I$(srcdir) -I$(srcdir)/../../../../include -I$(srcdir)/../../../../H $(CPP_SOURCES) >> Makefile;\ else\ makedepend -f - -- $(CFLAGS) -I$(srcdir)/../../../../H -I$(srcdir)/../../../../include -- $(CPP_SOURCES) |\ sed 's|.*/\([^:]*\):|\1:|' >> Makefile ;\ diff --git a/packages/CLPBN/clpbn/bp/SPSolver.cpp b/packages/CLPBN/clpbn/bp/SPSolver.cpp new file mode 100755 index 000000000..fe0ea1e69 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/SPSolver.cpp @@ -0,0 +1,295 @@ +#include +#include +#include + +#include "SPSolver.h" +#include "FactorGraph.h" +#include "FgVarNode.h" +#include "Factor.h" + +SPSolver* Link::klass = 0; + + +SPSolver::SPSolver (const FactorGraph& fg) : Solver (&fg) +{ + fg_ = &fg; + accuracy_ = 0.0001; + maxIter_ = 10000; + //schedule_ = S_SEQ_FIXED; + //schedule_ = S_SEQ_RANDOM; + //schedule_ = S_SEQ_PARALLEL; + schedule_ = S_MAX_RESIDUAL; + Link::klass = this; + FgVarSet vars = fg_->getFgVarNodes(); + for (unsigned i = 0; i < vars.size(); i++) { + msgs_.push_back (new MessageBanket (vars[i])); + } +} + + + +SPSolver::~SPSolver (void) +{ + for (unsigned i = 0; i < msgs_.size(); i++) { + delete msgs_[i]; + } +} + + + +void +SPSolver::runSolver (void) +{ + nIter_ = 0; + vector factors = fg_->getFactors(); + for (unsigned i = 0; i < factors.size(); i++) { + FgVarSet neighbors = factors[i]->getFgVarNodes(); + for (unsigned j = 0; j < neighbors.size(); j++) { + updateOrder_.push_back (Link (factors[i], neighbors[j])); + } + } + + while (!converged() && nIter_ < maxIter_) { + if (DL >= 1) { + cout << endl; + cout << "****************************************" ; + cout << "****************************************" ; + cout << endl; + cout << " Iteration " << nIter_ + 1 << endl; + cout << "****************************************" ; + cout << "****************************************" ; + cout << endl; + } + + switch (schedule_) { + + case S_SEQ_RANDOM: + random_shuffle (updateOrder_.begin(), updateOrder_.end()); + // no break + + case S_SEQ_FIXED: + for (unsigned c = 0; c < updateOrder_.size(); c++) { + Link& link = updateOrder_[c]; + calculateNextMessage (link.source, link.destination); + updateMessage (updateOrder_[c]); + } + break; + + case S_PARALLEL: + for (unsigned c = 0; c < updateOrder_.size(); c++) { + Link link = updateOrder_[c]; + calculateNextMessage (link.source, link.destination); + } + for (unsigned c = 0; c < updateOrder_.size(); c++) { + Link link = updateOrder_[c]; + updateMessage (updateOrder_[c]); + } + break; + + case S_MAX_RESIDUAL: + maxResidualSchedule(); + break; + } + + nIter_++; + } + cout << endl; + if (DL >= 1) { + if (nIter_ < maxIter_) { + cout << "Loopy Sum-Product converged in " ; + cout << nIter_ << " iterations" << endl; + } else { + cout << "The maximum number of iterations was hit, terminating..." ; + cout << endl; + } + } +} + + + +ParamSet +SPSolver::getPosterioriOf (const Variable* var) const +{ + assert (var); + assert (var == fg_->getVariableById (var->getVarId())); + assert (var->getIndex() < msgs_.size()); + + ParamSet probs (var->getDomainSize(), 1); + if (var->hasEvidence()) { + for (unsigned i = 0; i < probs.size(); i++) { + if ((int)i != var->getEvidence()) { + probs[i] = 0; + } + } + + } else { + + MessageBanket* mb = msgs_[var->getIndex()]; + const FgVarNode* varNode = fg_->getFgVarNodes()[var->getIndex()]; + vector neighbors = varNode->getFactors(); + for (unsigned i = 0; i < neighbors.size(); i++) { + const Message& msg = mb->getMessage (neighbors[i]); + for (unsigned j = 0; j < msg.size(); j++) { + probs[j] *= msg[j]; + } + } + Util::normalize (probs); + } + + return probs; +} + + + +bool +SPSolver::converged (void) +{ + if (nIter_ == 0 || nIter_ == 1) { + return false; + } + bool converged = true; + for (unsigned i = 0; i < updateOrder_.size(); i++) { + double residual = getResidual (updateOrder_[i]); + if (DL >= 1) { + cout << updateOrder_[i].toString(); + cout << " residual = " << residual << endl; + } + if (residual > accuracy_) { + converged = false; + if (DL == 0) { + break; + } + } + } + return converged; +} + + + +void +SPSolver::maxResidualSchedule (void) +{ + if (nIter_ == 0) { + for (unsigned c = 0; c < updateOrder_.size(); c++) { + Link& l = updateOrder_[c]; + calculateNextMessage (l.source, l.destination); + if (DL >= 1) { + cout << updateOrder_[c].toString() << " residual = " ; + cout << getResidual (updateOrder_[c]) << endl; + } + } + sort (updateOrder_.begin(), updateOrder_.end(), compareResidual); + } else { + + for (unsigned c = 0; c < updateOrder_.size(); c++) { + Link& link = updateOrder_.front(); + updateMessage (link); + resetResidual (link); + + // update the messages that depend on message source --> destination + vector fstLevelNeighbors = link.destination->getFactors(); + for (unsigned i = 0; i < fstLevelNeighbors.size(); i++) { + if (fstLevelNeighbors[i] != link.source) { + FgVarSet sndLevelNeighbors; + sndLevelNeighbors = fstLevelNeighbors[i]->getFgVarNodes(); + for (unsigned j = 0; j < sndLevelNeighbors.size(); j++) { + if (sndLevelNeighbors[j] != link.destination) { + calculateNextMessage (fstLevelNeighbors[i], sndLevelNeighbors[j]); + } + } + } + } + sort (updateOrder_.begin(), updateOrder_.end(), compareResidual); + } + } +} + + + +void +SPSolver::updateMessage (const Link& link) +{ + updateMessage (link.source, link.destination); +} + + + +void +SPSolver::updateMessage (const Factor* src, const FgVarNode* dest) +{ + msgs_[dest->getIndex()]->updateMessage (src); +/* cout << src->getLabel() << " --> " << dest->getLabel() << endl; + cout << " m: " ; + Message msg = msgs_[dest->getIndex()]->getMessage (src); + for (unsigned i = 0; i < msg.size(); i++) { + if (i != 0) cout << ", " ; + cout << msg[i]; + } + cout << endl; +*/ +} + + + +void +SPSolver::calculateNextMessage (const Link& link) +{ + calculateNextMessage (link.source, link.destination); +} + + +void +SPSolver::calculateNextMessage (const Factor* src, const FgVarNode* dest) +{ + FgVarSet neighbors = src->getFgVarNodes(); + // calculate the product of MessageBankets sended + // to factor `src', except from var `dest' + Factor result = *src; + for (unsigned i = 0; i < neighbors.size(); i++) { + if (neighbors[i] != dest) { + Message msg (neighbors[i]->getDomainSize(), 1); + calculateVarFactorMessage (neighbors[i], src, msg); + result *= Factor (neighbors[i], msg); + } + } + // marginalize all vars except `dest' + for (unsigned i = 0; i < neighbors.size(); i++) { + if (neighbors[i] != dest) { + result.marginalizeVariable (neighbors[i]); + } + } + msgs_[dest->getIndex()]->setNextMessage (src, result.getParameters()); +} + + + +void +SPSolver::calculateVarFactorMessage (const FgVarNode* src, + const Factor* dest, + Message& placeholder) const +{ + assert (src->getDomainSize() == (int)placeholder.size()); + if (src->hasEvidence()) { + for (unsigned i = 0; i < placeholder.size(); i++) { + if ((int)i != src->getEvidence()) { + placeholder[i] = 0.0; + } else { + placeholder[i] = 1.0; + } + } + + } else { + + MessageBanket* mb = msgs_[src->getIndex()]; + vector neighbors = src->getFactors(); + for (unsigned i = 0; i < neighbors.size(); i++) { + if (neighbors[i] != dest) { + const Message& fromFactor = mb->getMessage (neighbors[i]); + for (unsigned j = 0; j < fromFactor.size(); j++) { + placeholder[j] *= fromFactor[j]; + } + } + } + } +} + diff --git a/packages/CLPBN/clpbn/bp/SPSolver.h b/packages/CLPBN/clpbn/bp/SPSolver.h new file mode 100755 index 000000000..421172166 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/SPSolver.h @@ -0,0 +1,171 @@ +#ifndef BP_SPSOLVER_H +#define BP_SPSOLVER_H + +#include +#include +#include +#include + +#include "Solver.h" +#include "FgVarNode.h" +#include "Factor.h" + +using namespace std; + +class FactorGraph; +class SPSolver; + +struct Link +{ + Link (Factor* s, FgVarNode* d) + { + source = s; + destination = d; + } + string toString (void) const + { + stringstream ss; + ss << source->getLabel() << " --> " ; + ss << destination->getLabel(); + return ss.str(); + } + Factor* source; + FgVarNode* destination; + static SPSolver* klass; +}; + + + +class MessageBanket +{ + public: + MessageBanket (const FgVarNode* var) + { + vector sources = var->getFactors(); + for (unsigned i = 0; i < sources.size(); i++) { + indexMap_.insert (make_pair (sources[i], i)); + currMsgs_.push_back (Message(var->getDomainSize(), 1)); + nextMsgs_.push_back (Message(var->getDomainSize(), -10)); + residuals_.push_back (0.0); + } + } + + void updateMessage (const Factor* source) + { + unsigned idx = getIndex(source); + currMsgs_[idx] = nextMsgs_[idx]; + } + + void setNextMessage (const Factor* source, const Message& msg) + { + unsigned idx = getIndex(source); + nextMsgs_[idx] = msg; + residuals_[idx] = computeResidual (source); + } + + const Message& getMessage (const Factor* source) const + { + return currMsgs_[getIndex(source)]; + } + + double getResidual (const Factor* source) const + { + return residuals_[getIndex(source)]; + } + + void resetResidual (const Factor* source) + { + residuals_[getIndex(source)] = 0.0; + } + + private: + double computeResidual (const Factor* source) + { + double change = 0.0; + unsigned idx = getIndex (source); + const Message& currMessage = currMsgs_[idx]; + const Message& nextMessage = nextMsgs_[idx]; + for (unsigned i = 0; i < currMessage.size(); i++) { + change += abs (currMessage[i] - nextMessage[i]); + } + return change; + } + + unsigned getIndex (const Factor* factor) const + { + assert (factor); + assert (indexMap_.find(factor) != indexMap_.end()); + return indexMap_.find(factor)->second; + } + + typedef map IndexMap; + + IndexMap indexMap_; + vector currMsgs_; + vector nextMsgs_; + vector residuals_; +}; + + + +class SPSolver : public Solver +{ + public: + SPSolver (const FactorGraph&); + ~SPSolver (void); + + void runSolver (void); + ParamSet getPosterioriOf (const Variable* var) const; + + private: + bool converged (void); + void maxResidualSchedule (void); + void updateMessage (const Link&); + void updateMessage (const Factor*, const FgVarNode*); + void calculateNextMessage (const Link&); + void calculateNextMessage (const Factor*, const FgVarNode*); + void calculateVarFactorMessage ( + const FgVarNode*, const Factor*, Message&) const; + double getResidual (const Link&) const; + void resetResidual (const Link&) const; + friend bool compareResidual (const Link&, const Link&); + + const FactorGraph* fg_; + vector msgs_; + Schedule schedule_; + int nIter_; + double accuracy_; + int maxIter_; + vector updateOrder_; +}; + + + +inline double +SPSolver::getResidual (const Link& link) const +{ + MessageBanket* mb = Link::klass->msgs_[link.destination->getIndex()]; + return mb->getResidual (link.source); +} + + + +inline void +SPSolver::resetResidual (const Link& link) const +{ + MessageBanket* mb = Link::klass->msgs_[link.destination->getIndex()]; + mb->resetResidual (link.source); +} + + + +inline bool +compareResidual (const Link& link1, const Link& link2) +{ + MessageBanket* mb1 = Link::klass->msgs_[link1.destination->getIndex()]; + MessageBanket* mb2 = Link::klass->msgs_[link2.destination->getIndex()]; + return mb1->getResidual(link1.source) > mb2->getResidual(link2.source); +} + +#endif + diff --git a/packages/CLPBN/clpbn/bp/Shared.h b/packages/CLPBN/clpbn/bp/Shared.h new file mode 100755 index 000000000..82afd3e51 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/Shared.h @@ -0,0 +1,203 @@ +#ifndef BP_SHARED_H +#define BP_SHARED_H + +#include +#include +#include +#include +#include +#include +#include + +// Macro to disallow the copy constructor and operator= functions +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +using namespace std; + +class Variable; +class BayesNode; +class FgVarNode; + +typedef double Param; +typedef vector ParamSet; +typedef vector Message; +typedef vector VarSet; +typedef vector NodeSet; +typedef vector FgVarSet; +typedef vector Domain; +typedef vector DomainConf; +typedef pair DomainConstr; +typedef unordered_map IndexMap; + + +//extern unsigned DL; +static const unsigned DL = 0; + +// number of digits to show when printing a parameter +static const unsigned PRECISION = 10; + +// shared by bp and sp solver +enum Schedule +{ + S_SEQ_FIXED, + S_SEQ_RANDOM, + S_PARALLEL, + S_MAX_RESIDUAL +}; + + +struct NetInfo +{ + NetInfo (unsigned c, double t) + { + counting = c; + solvingTime = t; + } + unsigned counting; + double solvingTime; +}; + +typedef map StatisticMap; + + +class Statistics +{ + public: + + static void updateStats (unsigned size, double time) + { + StatisticMap::iterator it = stats_.find(size); + if (it == stats_.end()) { + stats_.insert (make_pair (size, NetInfo (1, 0.0))); + } else { + it->second.counting ++; + it->second.solvingTime += time; + } + } + + static unsigned getCounting (unsigned size) + { + StatisticMap::iterator it = stats_.find(size); + assert (it != stats_.end()); + return it->second.counting; + } + + static void updateIterations (unsigned nIters) + { + totalOfIterations += nIters; + if (nIters > maxIterations) { + maxIterations = nIters; + } + } + + static void writeStats (void) + { + ofstream out ("../../stats.txt"); + if (!out.is_open()) { + cerr << "error: cannot open file to write at " ; + cerr << "Statistics:::updateStats()" << endl; + abort(); + } + unsigned avgIterations = 0; + if (numSolvedLoopyNets > 0) { + avgIterations = totalOfIterations / numSolvedLoopyNets; + } + double totalSolvingTime = 0.0; + for (StatisticMap::iterator it = stats_.begin(); + it != stats_.end(); it++) { + totalSolvingTime += it->second.solvingTime; + } + out << "created networks: " << numCreatedNets << endl; + out << "solver runs on polytrees: " << numSolvedPolyTrees << endl; + out << "solver runs on loopy networks: " << numSolvedLoopyNets << endl; + out << " unconverged: " << numUnconvergedRuns << endl; + out << " max iterations: " << maxIterations << endl; + out << " average iterations: " << avgIterations << endl; + out << "total solving time " << totalSolvingTime << endl; + out << endl; + out << "Network Size\tCounting\tSolving Time\tAverage Time" << endl; + for (StatisticMap::iterator it = stats_.begin(); + it != stats_.end(); it++) { + out << it->first; + out << "\t\t" << it->second.counting; + out << "\t\t" << it->second.solvingTime; + if (it->second.counting > 0) { + out << "\t\t" << it->second.solvingTime / it->second.counting; + } else { + out << "\t\t0.0" ; + } + out << endl; + } + out.close(); + } + + static unsigned numCreatedNets; + static unsigned numSolvedPolyTrees; + static unsigned numSolvedLoopyNets; + static unsigned numUnconvergedRuns; + + private: + static StatisticMap stats_; + static unsigned maxIterations; + static unsigned totalOfIterations; + +}; + + + +class Util +{ + public: + static void normalize (ParamSet& v) + { + double sum = 0.0; + for (unsigned i = 0; i < v.size(); i++) { + sum += v[i]; + } + assert (sum != 0.0); + for (unsigned i = 0; i < v.size(); i++) { + v[i] /= sum; + } + } + + static double getL1dist (const ParamSet& v1, const ParamSet& v2) + { + assert (v1.size() == v2.size()); + double dist = 0.0; + for (unsigned i = 0; i < v1.size(); i++) { + dist += abs (v1[i] - v2[i]); + } + return dist; + } + + static double getMaxNorm (const ParamSet& v1, const ParamSet& v2) + { + assert (v1.size() == v2.size()); + double max = 0.0; + for (unsigned i = 0; i < v1.size(); i++) { + double diff = abs (v1[i] - v2[i]); + if (diff > max) { + max = diff; + } + } + return max; + } + + static bool isInteger (const string& s) + { + stringstream ss1 (s); + stringstream ss2; + int integer; + ss1 >> integer; + ss2 << integer; + return (ss1.str() == ss2.str()); + } +}; + + +//unsigned Statistics::totalOfIterations = 0; + +#endif + diff --git a/packages/CLPBN/clpbn/bp/Solver.h b/packages/CLPBN/clpbn/bp/Solver.h new file mode 100644 index 000000000..483986278 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/Solver.h @@ -0,0 +1,50 @@ +#ifndef BP_SOLVER_H +#define BP_SOLVER_H + +#include + +#include "GraphicalModel.h" +#include "Variable.h" + +using namespace std; + +class Solver +{ + public: + Solver (const GraphicalModel* gm) + { + gm_ = gm; + } + virtual void runSolver (void) = 0; + virtual ParamSet getPosterioriOf (const Variable*) const = 0; + + void printPosterioriOf (const Variable* var) const + { + cout << endl; + cout << setw (20) << left << var->getLabel() << "posteriori" ; + cout << endl; + cout << "------------------------------" ; + cout << endl; + const Domain& domain = var->getDomain(); + ParamSet results = getPosterioriOf (var); + for (int xi = 0; xi < var->getDomainSize(); xi++) { + cout << setw (20) << domain[xi]; + cout << setprecision (PRECISION) << results[xi]; + cout << endl; + } + cout << endl; + } + + void printAllPosterioris (void) const + { + VarSet vars = gm_->getVariables(); + for (unsigned i = 0; i < vars.size(); i++) { + printPosterioriOf (vars[i]); + } + } + + private: + const GraphicalModel* gm_; +}; + +#endif diff --git a/packages/CLPBN/clpbn/bp/Variable.h b/packages/CLPBN/clpbn/bp/Variable.h new file mode 100755 index 000000000..63f3edcbc --- /dev/null +++ b/packages/CLPBN/clpbn/bp/Variable.h @@ -0,0 +1,143 @@ +#ifndef BP_GENERIC_VARIABLE_H +#define BP_GENERIC_VARIABLE_H + +#include + +#include +#include "Shared.h" + +using namespace std; + +class Variable +{ + public: + + Variable (unsigned varId) + { + this->varId_ = varId; + this->dsize_ = 0; + this->evidence_ = -1; + this->label_ = 0; + } + + Variable (unsigned varId, unsigned dsize, int evidence = -1) + { + assert (dsize != 0); + assert (evidence < (int)dsize); + this->varId_ = varId; + this->dsize_ = dsize; + this->evidence_ = evidence; + this->label_ = 0; + } + + Variable (unsigned varId, const Domain& domain, int evidence = -1) + { + assert (!domain.empty()); + assert (evidence < (int)domain.size()); + this->varId_ = varId; + this->dsize_ = domain.size(); + this->domain_ = domain; + this->evidence_ = evidence; + this->label_ = 0; + } + + ~Variable (void) + { + delete label_; + } + + unsigned getVarId (void) const { return varId_; } + unsigned getIndex (void) const { return index_; } + void setIndex (unsigned idx) { index_ = idx; } + int getDomainSize (void) const { return dsize_; } + bool hasEvidence (void) const { return evidence_ != -1; } + int getEvidence (void) const { return evidence_; } + bool hasDomain (void) { return !domain_.empty(); } + bool hasLabel (void) { return label_ != 0; } + + bool isValidStateIndex (int index) + { + return index >= 0 && index < dsize_; + } + + bool isValidState (const string& state) + { + return find (domain_.begin(), domain_.end(), state) != domain_.end(); + } + + Domain getDomain (void) const + { + assert (dsize_ != 0); + if (domain_.size() == 0) { + Domain d; + for (int i = 0; i < dsize_; i++) { + stringstream ss; + ss << "x" << i ; + d.push_back (ss.str()); + } + return d; + } else { + return domain_; + } + } + + void setDomainSize (unsigned dsize) + { + assert (dsize != 0); + dsize_ = dsize; + } + + void setDomain (const Domain& domain) + { + assert (!domain.empty()); + domain_ = domain; + dsize_ = domain.size(); + } + + void setEvidence (int ev) + { + assert (ev < dsize_); + evidence_ = ev; + } + + void setEvidence (const string& ev) + { + assert (isValidState (ev)); + for (unsigned i = 0; i < domain_.size(); i++) { + if (domain_[i] == ev) { + evidence_ = i; + } + } + } + + void setLabel (string label) + { + label_ = new string (label); + } + + string getLabel (void) const + { + if (label_ == 0) { + stringstream ss; + ss << "v" << varId_; + return ss.str(); + } else { + return *label_; + } + } + + protected: + unsigned varId_; + string* label_; + unsigned index_; + int evidence_; + + private: + DISALLOW_COPY_AND_ASSIGN (Variable); + Domain domain_; + int dsize_; + +}; + +#endif // BP_GENERIC_VARIABLE_H + diff --git a/packages/CLPBN/clpbn/bp/callgrind.h b/packages/CLPBN/clpbn/bp/callgrind.h new file mode 100755 index 000000000..d36b6f4eb --- /dev/null +++ b/packages/CLPBN/clpbn/bp/callgrind.h @@ -0,0 +1,147 @@ + +/* + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (callgrind.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of callgrind, a valgrind tool for cache simulation + and call tree tracing. + + Copyright (C) 2003-2010 Josef Weidendorfer. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (callgrind.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + +#ifndef __CALLGRIND_H +#define __CALLGRIND_H + +#include "valgrind.h" + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE ORDER OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end. + + The identification ('C','T') for Callgrind has historical + reasons: it was called "Calltree" before. Besides, ('C','G') would + clash with cachegrind. + */ + +typedef + enum { + VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C','T'), + VG_USERREQ__ZERO_STATS, + VG_USERREQ__TOGGLE_COLLECT, + VG_USERREQ__DUMP_STATS_AT, + VG_USERREQ__START_INSTRUMENTATION, + VG_USERREQ__STOP_INSTRUMENTATION + } Vg_CallgrindClientRequest; + +/* Dump current state of cost centers, and zero them afterwards */ +#define CALLGRIND_DUMP_STATS \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__DUMP_STATS, \ + 0, 0, 0, 0, 0); \ + } + +/* Dump current state of cost centers, and zero them afterwards. + The argument is appended to a string stating the reason which triggered + the dump. This string is written as a description field into the + profile data dump. */ +#define CALLGRIND_DUMP_STATS_AT(pos_str) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__DUMP_STATS_AT, \ + pos_str, 0, 0, 0, 0); \ + } + +/* Zero cost centers */ +#define CALLGRIND_ZERO_STATS \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__ZERO_STATS, \ + 0, 0, 0, 0, 0); \ + } + +/* Toggles collection state. + The collection state specifies whether the happening of events + should be noted or if they are to be ignored. Events are noted + by increment of counters in a cost center */ +#define CALLGRIND_TOGGLE_COLLECT \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__TOGGLE_COLLECT, \ + 0, 0, 0, 0, 0); \ + } + +/* Start full callgrind instrumentation if not already switched on. + When cache simulation is done, it will flush the simulated cache; + this will lead to an artifical cache warmup phase afterwards with + cache misses which would not have happened in reality. */ +#define CALLGRIND_START_INSTRUMENTATION \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__START_INSTRUMENTATION, \ + 0, 0, 0, 0, 0); \ + } + +/* Stop full callgrind instrumentation if not already switched off. + This flushes Valgrinds translation cache, and does no additional + instrumentation afterwards, which effectivly will run at the same + speed as the "none" tool (ie. at minimal slowdown). + Use this to bypass Callgrind aggregation for uninteresting code parts. + To start Callgrind in this mode to ignore the setup phase, use + the option "--instr-atstart=no". */ +#define CALLGRIND_STOP_INSTRUMENTATION \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__STOP_INSTRUMENTATION, \ + 0, 0, 0, 0, 0); \ + } + +#endif /* __CALLGRIND_H */ diff --git a/packages/CLPBN/clpbn/bp/examples/bayes-ball a.xml b/packages/CLPBN/clpbn/bp/examples/bayes-ball a.xml new file mode 100755 index 000000000..286b95f59 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/bayes-ball a.xml @@ -0,0 +1,76 @@ + + + + +Bayes-Ball: The Rational Pastime Network, Figure 4, a) + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 1 + 1
+
+ + + 2 + 1 + 3 + 1
+
+ + + 3 + 1
+
+ + + 4 + 1 + 5 + 1
+
+ + + 5 + 2 + 6 + 1
+
+ + + 6 + 3 + 1
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/bayes-ball c.xml b/packages/CLPBN/clpbn/bp/examples/bayes-ball c.xml new file mode 100755 index 000000000..44b291822 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/bayes-ball c.xml @@ -0,0 +1,74 @@ + + + + +Bayes-Ball: The Rational Pastime Network, Figure 4, c) + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 1 + 1
+
+ + + 2 + 1 + 3 + 1
+
+ + + 3 + 1
+
+ + + 4 + 5 + 1
+
+ + + 5 + 2 + 6 + 1
+
+ + + 6 + 1
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/burglary-alarm.uai b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.uai new file mode 100755 index 000000000..3f24754e2 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.uai @@ -0,0 +1,28 @@ +MARKOV +5 +2 2 2 2 2 +5 +1 0 +1 1 +3 2 0 1 +2 3 2 +2 4 2 + +2 + .001 .009 + +2 + .002 .008 + +8 + .95 .94 .29 .001 + .05 .06 .71 .999 + +4 + .9 .05 + .1 .95 + +4 + .7 .01 + .3 .99 + diff --git a/packages/CLPBN/clpbn/bp/examples/burglary-alarm.xml b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.xml new file mode 100755 index 000000000..36c7a500b --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.xml @@ -0,0 +1,81 @@ + + + + + + + +Simple Loop + + + B + b1 + b2 + + + + E + e1 + e2 + + + + A + a1 + a2 + + + + J + j1 + j2 + + + + M + m1 + m2 + + + + B + .001 .009
+
+ + + E + .002 .008
+
+ + + A + B + E + .95 .05 .94 .06 .29 .71 .001 .999
+
+ + + J + A + .9 .1 .05 .95
+
+ + + M + A + .7 .3 .01 .99
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/burglary-alarm.yap b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.yap new file mode 100755 index 000000000..9fd004712 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/burglary-alarm.yap @@ -0,0 +1,54 @@ + +:- use_module(library(clpbn)). + +:- set_clpbn_flag(solver, vel). + +% +% B E +% \ / +% \ / +% A +% / \ +% / \ +% J M +% + + +b(B) :- + b_table(BDist), + { B = b with p([b1, b2], BDist) }. + +e(E) :- + e_table(EDist), + { E = e with p([e1, e2], EDist) }. + +a(A) :- + b(B), + e(E), + a_table(ADist), + { A = a with p([a1, a2], ADist, [B, E]) }. + +j(J):- + a(A), + j_table(JDist), + { J = j with p([j1, j2], JDist, [A]) }. + +m(M):- + a(A), + m_table(MDist), + { M = m with p([m1, m2], MDist, [A]) }. + + +b_table([0.001, 0.009]). + +e_table([0.002, 0.008]). + +a_table([0.95, 0.94, 0.29, 0.001, + 0.05, 0.06, 0.71, 0.999]). + +j_table([0.9, 0.05, + 0.1, 0.95]). + +m_table([0.7, 0.01, + 0.3, 0.99]). + diff --git a/packages/CLPBN/clpbn/bp/examples/chain.xml b/packages/CLPBN/clpbn/bp/examples/chain.xml new file mode 100755 index 000000000..6b5882e5d --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/chain.xml @@ -0,0 +1,58 @@ + + + + + + +Simple Chain + + + A + a1 + a2 + + + + B + b1 + b2 + + + + C + c1 + c2 + + + + A + 0.3 0.7
+
+ + + B + A + 0.4 0.6 0.2 0.8
+
+ + + C + B + 0.9 0.1 0.25 0.75
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/convergence.xml b/packages/CLPBN/clpbn/bp/examples/convergence.xml new file mode 100755 index 000000000..8172042ed --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/convergence.xml @@ -0,0 +1,51 @@ + + + + + + +Simple Convergence + + + A + + + + + B + + + + + C + + + + + A + 1
+
+ + + B + 1
+
+ + + C + A + B + 1
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/divergence.xml b/packages/CLPBN/clpbn/bp/examples/divergence.xml new file mode 100755 index 000000000..69ef00f04 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/divergence.xml @@ -0,0 +1,51 @@ + + + + + + +Simple Divergence + + + A + + + + + B + + + + + C + + + + + A + 1
+
+ + + B + A + 1
+
+ + + C + A + 1
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/john-mary-call.xml b/packages/CLPBN/clpbn/bp/examples/john-mary-call.xml new file mode 100755 index 000000000..037134fc5 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/john-mary-call.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + +]> + + + + +John-Mary-Call + + + + Burglary + discrete + False + True + position = (145, 114) + + + + Earthquake + discrete + False + True + position = (351, 110) + + + + Alarm + discrete + False + True + position = (253, 224) + + + + JohnCalls + discrete + False + True + position = (156, 343) + + + + MaryCalls + discrete + False + True + position = (344, 341) + + + + + + Burglary + 0.999 0.0010
+
+ + + Earthquake + 0.998 0.0020
+
+ + + Alarm + Burglary + Earthquake + 0.999 0.71 0.06 0.05 0.0010 0.29 0.94 0.95
+
+ + + JohnCalls + Alarm + 0.95 0.1 0.05 0.9
+
+ + + MaryCalls + Alarm + 0.99 0.3 0.01 0.7
+
+ + +
diff --git a/packages/CLPBN/clpbn/bp/examples/loop.xml b/packages/CLPBN/clpbn/bp/examples/loop.xml new file mode 100755 index 000000000..2764d73d1 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/loop.xml @@ -0,0 +1,81 @@ + + + + + + +Loop + + + A + a1 + a2 + + + + B + b1 + b2 + + + + C + c1 + c2 + + + + D + d1 + d2 + + + + E + e1 + e2 + + + + A + .01 .09
+
+ + + B + A + .03 .97 .6 .4
+
+ + + C + A + E + .24 .76 .12 .88 .2 .4. 5. .6
+
+ + + D + B + C + .2 .8 .7 .3 .45 .55 .22 .78
+
+ + + E + .5 .6
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/loop.yap b/packages/CLPBN/clpbn/bp/examples/loop.yap new file mode 100755 index 000000000..c18784975 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/loop.yap @@ -0,0 +1,53 @@ + +:- use_module(library(clpbn)). + +:- set_clpbn_flag(solver, bp). + +% +% A E +% / \ / +% / \ / +% B C +% \ / +% \ / +% D +% + +a(A) :- + a_table(ADist), + { A = a with p([a1, a2], ADist) }. + +b(B) :- + a(A), + b_table(BDist), + { B = b with p([b1, b2], BDist, [A]) }. + +c(C) :- + a(A), + c_table(CDist), + { C = c with p([c1, c2], CDist, [A]) }. + +d(D) :- + b(B), + c(C), + d_table(DDist), + { D = d with p([d1, d2], DDist, [B, C]) }. + +e(E) :- + e_table(EDist), + { E = e with p([e1, e2], EDist) }. + + +a_table([0.005, 0.995]). + +b_table([0.02, 0.97, + 0.88, 0.03]). + +c_table([0.55, 0.94, + 0.45, 0.06]). + +d_table([0.192, 0.98, 0.33, 0.013, + 0.908, 0.02, 0.77, 0.987]). + +e_table([0.055, 0.945]). + diff --git a/packages/CLPBN/clpbn/bp/examples/neapolitan-A-F-joint.yap b/packages/CLPBN/clpbn/bp/examples/neapolitan-A-F-joint.yap new file mode 100755 index 000000000..4cb95eab4 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/neapolitan-A-F-joint.yap @@ -0,0 +1,55 @@ + +:- use_module(library(clpbn)). + +:- set_clpbn_flag(solver, bp). + +% +% B F +% \ / +% \ / +% A +% + +b(B) :- + b_table(BDist), + { B = b with p([b1, b2], BDist) }. + +f(F) :- + f_table(FDist), + { F = f with p([f1, f2], FDist) }. + +a(A) :- + b(B), + f(F), + a_table(ADist), + { A = a with p([a1, a2], ADist, [B, F]) }. + +d(D) :- + a(A), + f(F), + d_table(DDist), + { D = d with p([d1, d2, d3, d4], DDist, [A, F]) }. + + +b_table([0.005, 0.995]). + +f_table([0.03, 0.97]). + +a_table([0.992, 0.99, 0.2, 0.003, + 0.008, 0.01, 0.8, 0.997]). + +d_table([1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0]). + +%d_table([0.997, 0.001, 0.001, 0.001, +% 0.001, 0.997, 0.001, 0.001, +% 0.001, 0.001, 0.997, 0.001, +% 0.001, 0.001, 0.001, 0.997]). + +%d_table([0.15, 0.1, 0.7, 0.5, +% 0.25, 0.3, 0.2, 0.25, +% 0.3, 0.15, 0.35, 0.2, +% 0.3, 0.4, 0.2, 0.1]). + diff --git a/packages/CLPBN/clpbn/bp/examples/neapolitan.uai b/packages/CLPBN/clpbn/bp/examples/neapolitan.uai new file mode 100755 index 000000000..1339c83c2 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/neapolitan.uai @@ -0,0 +1,17 @@ +MARKOV +3 +2 2 2 +3 +1 0 +1 1 +3 2 0 1 + +2 + 0.005 0.995 + +2 + 0.03 0.97 + +8 + 0.992 0.99 0.2 0.003 + 0.008 0.01 0.8 0.997 diff --git a/packages/CLPBN/clpbn/bp/examples/neapolitan.xml b/packages/CLPBN/clpbn/bp/examples/neapolitan.xml new file mode 100755 index 000000000..0b359e274 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/neapolitan.xml @@ -0,0 +1,53 @@ + + + + + + +Neapolitan + + + B + b1 + b2 + + + + F + f1 + f2 + + + + A + a1 + a2 + + + + B + .005 .995
+
+ + + F + .03 .97
+
+ + + A + B + F + .992 .008 .99 .01 .2 .8 .003 .997
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/neapolitan.yap b/packages/CLPBN/clpbn/bp/examples/neapolitan.yap new file mode 100755 index 000000000..1d558d634 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/neapolitan.yap @@ -0,0 +1,35 @@ + +:- use_module(library(clpbn)). + +:- set_clpbn_flag(solver, bp). + +% +% B F +% \ / +% \ / +% A +% + + +b(B) :- + b_table(BDist), + { B = b with p([b1, b2], BDist) }. + +f(F) :- + f_table(FDist), + { F = f with p([f1, f2], FDist) }. + +a(A) :- + b(B), + f(F), + a_table(ADist), + { A = a with p([a1, a2], ADist, [B, F]) }. + + +b_table([0.005, 0.995]). + +f_table([0.03, 0.97]). + +a_table([0.992, 0.99, 0.2, 0.003, + 0.008, 0.01, 0.8, 0.997]). + diff --git a/packages/CLPBN/clpbn/bp/examples/several-parents-and-childs.xml b/packages/CLPBN/clpbn/bp/examples/several-parents-and-childs.xml new file mode 100755 index 000000000..e37c7ac5e --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/several-parents-and-childs.xml @@ -0,0 +1,128 @@ + + + + + + +Node with several parents and childs + + + A + a1 + a2 + + + + B + b1 + b2 + b3 + b4 + + + + C + c1 + c2 + c3 + + + + D + d1 + d2 + d3 + + + + E + e1 + e2 + e3 + e4 + + + + F + f1 + f2 + f3 + + + + G + g1 + g2 + + + + + A + .1 .2
+
+ + + B + .01 .02 .03 .04
+
+ + + C + .11 .22 .33
+
+ + + D + A + B + C + + .522 .008 .99 .01 .2 .8 .003 .457 .423 .007 .92 .04 .5 .232 .033 .227 .112 .048 .91 .21 .24 .18 .005 .227 + .212 .04 .59 .21 .6 .1 .023 .215 .913 .017 .96 .01 .55 .422 .013 .417 .272 .068 .61 .11 .26 .28 .205 .322 + .142 .028 .19 .11 .5 .67 .013 .437 .163 .067 .12 .06 .1 .262 .063 .167 .512 .028 .11 .41 .14 .68 .015 .92 +
+
+ + + E + D + + .111 .11 .1 + .222 .22 .2 + .333 .33 .3 + .444 .44 .4 +
+
+ + + F + D + + .112 .111 .110 + .223 .222 .221 + .334 .333 .332 +
+
+ + + G + D + + .101 .102 .103 + .201 .202 .203 +
+
+ +
+
+ diff --git a/packages/CLPBN/clpbn/bp/examples/test.uai b/packages/CLPBN/clpbn/bp/examples/test.uai new file mode 100755 index 000000000..f773cd9bf --- /dev/null +++ b/packages/CLPBN/clpbn/bp/examples/test.uai @@ -0,0 +1,36 @@ +MARKOV +5 +4 2 3 2 3 +7 +1 0 +1 1 +1 2 +1 3 +1 4 +2 0 1 +4 1 2 3 4 + +4 + 0.1 0.7 0.43 0.22 + +2 + 0.2 0.6 + +3 + 0.3 0.5 0.2 + +2 + 0.15 0.75 + +3 + 0.25 0.45 0.15 + +8 + 0.210 0.333 0.457 0.4 + 0.811 0.000 0.189 0.89 + +36 + 0.1 0.15 0.2 0.25 0.3 0.45 0.5 0.55 0.65 0.7 0.75 0.9 + 0.11 0.22 0.33 0.44 0.55 0.66 0.77 0.88 0.91 0.93 0.95 0.97 + 0.42 0.22 0.33 0.44 0.15 0.36 0.27 0.28 0.21 0.13 0.25 0.17 + diff --git a/packages/CLPBN/clpbn/bp/valgrind.h b/packages/CLPBN/clpbn/bp/valgrind.h new file mode 100755 index 000000000..0f5b37662 --- /dev/null +++ b/packages/CLPBN/clpbn/bp/valgrind.h @@ -0,0 +1,4536 @@ +/* -*- c -*- + ---------------------------------------------------------------- + + Notice that the following BSD-style license applies to this one + file (valgrind.h) only. The rest of Valgrind is licensed under the + terms of the GNU General Public License, version 2, unless + otherwise indicated. See the COPYING file in the source + distribution for details. + + ---------------------------------------------------------------- + + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2010 Julian Seward. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ---------------------------------------------------------------- + + Notice that the above BSD-style license applies to this one file + (valgrind.h) only. The entire rest of Valgrind is licensed under + the terms of the GNU General Public License, version 2. See the + COPYING file in the source distribution for details. + + ---------------------------------------------------------------- +*/ + + +/* This file is for inclusion into client (your!) code. + + You can use these macros to manipulate and query Valgrind's + execution inside your own programs. + + The resulting executables will still run without Valgrind, just a + little bit more slowly than they otherwise would, but otherwise + unchanged. When not running on valgrind, each client request + consumes very few (eg. 7) instructions, so the resulting performance + loss is negligible unless you plan to execute client requests + millions of times per second. Nevertheless, if that is still a + problem, you can compile with the NVALGRIND symbol defined (gcc + -DNVALGRIND) so that client requests are not even compiled in. */ + +#ifndef __VALGRIND_H +#define __VALGRIND_H + + +/* ------------------------------------------------------------------ */ +/* VERSION NUMBER OF VALGRIND */ +/* ------------------------------------------------------------------ */ + +/* Specify Valgrind's version number, so that user code can + conditionally compile based on our version number. Note that these + were introduced at version 3.6 and so do not exist in version 3.5 + or earlier. The recommended way to use them to check for "version + X.Y or later" is (eg) + +#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ + && (__VALGRIND_MAJOR__ > 3 \ + || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) +*/ +#define __VALGRIND_MAJOR__ 3 +#define __VALGRIND_MINOR__ 6 + + +#include + +/* Nb: this file might be included in a file compiled with -ansi. So + we can't use C++ style "//" comments nor the "asm" keyword (instead + use "__asm__"). */ + +/* Derive some tags indicating what the target platform is. Note + that in this file we're using the compiler's CPP symbols for + identifying architectures, which are different to the ones we use + within the rest of Valgrind. Note, __powerpc__ is active for both + 32 and 64-bit PPC, whereas __powerpc64__ is only active for the + latter (on Linux, that is). + + Misc note: how to find out what's predefined in gcc by default: + gcc -Wp,-dM somefile.c +*/ +#undef PLAT_ppc64_aix5 +#undef PLAT_ppc32_aix5 +#undef PLAT_x86_darwin +#undef PLAT_amd64_darwin +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64_linux +#undef PLAT_arm_linux + +#if defined(_AIX) && defined(__64BIT__) +# define PLAT_ppc64_aix5 1 +#elif defined(_AIX) && !defined(__64BIT__) +# define PLAT_ppc32_aix5 1 +#elif defined(__APPLE__) && defined(__i386__) +# define PLAT_x86_darwin 1 +#elif defined(__APPLE__) && defined(__x86_64__) +# define PLAT_amd64_darwin 1 +#elif defined(__linux__) && defined(__i386__) +# define PLAT_x86_linux 1 +#elif defined(__linux__) && defined(__x86_64__) +# define PLAT_amd64_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) +# define PLAT_ppc32_linux 1 +#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) +# define PLAT_ppc64_linux 1 +#elif defined(__linux__) && defined(__arm__) +# define PLAT_arm_linux 1 +#else +/* If we're not compiling for our target platform, don't generate + any inline asms. */ +# if !defined(NVALGRIND) +# define NVALGRIND 1 +# endif +#endif + + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ +/* in here of use to end-users -- skip to the next section. */ +/* ------------------------------------------------------------------ */ + +#if defined(NVALGRIND) + +/* Define NVALGRIND to completely remove the Valgrind magic sequence + from the compiled code (analogous to NDEBUG's effects on + assert()) */ +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { \ + (_zzq_rlval) = (_zzq_default); \ + } + +#else /* ! NVALGRIND */ + +/* The following defines the magic code sequences which the JITter + spots and handles magically. Don't look too closely at them as + they will rot your brain. + + The assembly code sequences for all architectures is in this one + file. This is because this file must be stand-alone, and we don't + want to have multiple files. + + For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default + value gets put in the return slot, so that everything works when + this is executed not under Valgrind. Args are passed in a memory + block, and so there's no intrinsic limit to the number that could + be passed, but it's currently five. + + The macro args are: + _zzq_rlval result lvalue + _zzq_default default value (result returned when running on real CPU) + _zzq_request request code + _zzq_arg1..5 request params + + The other two macros are used to support function wrapping, and are + a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the + guest's NRADDR pseudo-register and whatever other information is + needed to safely run the call original from the wrapper: on + ppc64-linux, the R2 value at the divert point is also needed. This + information is abstracted into a user-visible type, OrigFn. + + VALGRIND_CALL_NOREDIR_* behaves the same as the following on the + guest, but guarantees that the branch instruction will not be + redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: + branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a + complete inline asm, since it needs to be combined with more magic + inline asm stuff to be useful. +*/ + +/* ------------------------- x86-{linux,darwin} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "roll $3, %%edi ; roll $13, %%edi\n\t" \ + "roll $29, %%edi ; roll $19, %%edi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EDX = client_request ( %EAX ) */ \ + "xchgl %%ebx,%%ebx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %EAX = guest_NRADDR */ \ + "xchgl %%ecx,%%ecx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_EAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%EAX */ \ + "xchgl %%edx,%%edx\n\t" +#endif /* PLAT_x86_linux || PLAT_x86_darwin */ + +/* ------------------------ amd64-{linux,darwin} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) + +typedef + struct { + unsigned long long int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ + "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + { volatile unsigned long long int _zzq_args[6]; \ + volatile unsigned long long int _zzq_result; \ + _zzq_args[0] = (unsigned long long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RDX = client_request ( %RAX ) */ \ + "xchgq %%rbx,%%rbx" \ + : "=d" (_zzq_result) \ + : "a" (&_zzq_args[0]), "0" (_zzq_default) \ + : "cc", "memory" \ + ); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + volatile unsigned long long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %RAX = guest_NRADDR */ \ + "xchgq %%rcx,%%rcx" \ + : "=a" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_CALL_NOREDIR_RAX \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* call-noredir *%RAX */ \ + "xchgq %%rdx,%%rdx\n\t" +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ + "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned int _zzq_args[6]; \ + unsigned int _zzq_result; \ + unsigned int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 3,%1\n\t" /*default*/ \ + "mr 4,%2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" /*result*/ \ + : "=b" (_zzq_result) \ + : "b" (_zzq_default), "b" (_zzq_ptr) \ + : "cc", "memory", "r3", "r4"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64_linux) + +typedef + struct { + unsigned long long int nraddr; /* where's the code? */ + unsigned long long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned long long int _zzq_args[6]; \ + register unsigned long long int _zzq_result __asm__("r3"); \ + register unsigned long long int* _zzq_ptr __asm__("r4"); \ + _zzq_args[0] = (unsigned long long int)(_zzq_request); \ + _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1" \ + : "=r" (_zzq_result) \ + : "0" (_zzq_default), "r" (_zzq_ptr) \ + : "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned long long int __addr __asm__("r3"); \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2" \ + : "=r" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4" \ + : "=r" (__addr) \ + : \ + : "cc", "memory" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#endif /* PLAT_ppc64_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ + "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { volatile unsigned int _zzq_args[6]; \ + volatile unsigned int _zzq_result; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + __asm__ volatile("mov r3, %1\n\t" /*default*/ \ + "mov r4, %2\n\t" /*ptr*/ \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = client_request ( R4 ) */ \ + "orr r10, r10, r10\n\t" \ + "mov %0, r3" /*result*/ \ + : "=r" (_zzq_result) \ + : "r" (_zzq_default), "r" (&_zzq_args[0]) \ + : "cc","memory", "r3", "r4"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* R3 = guest_NRADDR */ \ + "orr r11, r11, r11\n\t" \ + "mov %0, r3" \ + : "=r" (__addr) \ + : \ + : "cc", "memory", "r3" \ + ); \ + _zzq_orig->nraddr = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R4 */ \ + "orr r12, r12, r12\n\t" + +#endif /* PLAT_arm_linux */ + +/* ------------------------ ppc32-aix5 ------------------------- */ + +#if defined(PLAT_ppc32_aix5) + +typedef + struct { + unsigned int nraddr; /* where's the code? */ + unsigned int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ + "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned int _zzq_args[7]; \ + register unsigned int _zzq_result; \ + register unsigned int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int)(_zzq_request); \ + _zzq_args[1] = (unsigned int)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int)(_zzq_arg5); \ + _zzq_args[6] = (unsigned int)(_zzq_default); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 4,%1\n\t" \ + "lwz 3, 24(4)\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" \ + : "=b" (_zzq_result) \ + : "b" (_zzq_ptr) \ + : "r3", "r4", "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#endif /* PLAT_ppc32_aix5 */ + +/* ------------------------ ppc64-aix5 ------------------------- */ + +#if defined(PLAT_ppc64_aix5) + +typedef + struct { + unsigned long long int nraddr; /* where's the code? */ + unsigned long long int r2; /* what tocptr do we need? */ + } + OrigFn; + +#define __SPECIAL_INSTRUCTION_PREAMBLE \ + "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ + "rotldi 0,0,61 ; rotldi 0,0,51\n\t" + +#define VALGRIND_DO_CLIENT_REQUEST( \ + _zzq_rlval, _zzq_default, _zzq_request, \ + _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ + \ + { unsigned long long int _zzq_args[7]; \ + register unsigned long long int _zzq_result; \ + register unsigned long long int* _zzq_ptr; \ + _zzq_args[0] = (unsigned int long long)(_zzq_request); \ + _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \ + _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \ + _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \ + _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \ + _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \ + _zzq_args[6] = (unsigned int long long)(_zzq_default); \ + _zzq_ptr = _zzq_args; \ + __asm__ volatile("mr 4,%1\n\t" \ + "ld 3, 48(4)\n\t" \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = client_request ( %R4 ) */ \ + "or 1,1,1\n\t" \ + "mr %0,3" \ + : "=b" (_zzq_result) \ + : "b" (_zzq_ptr) \ + : "r3", "r4", "cc", "memory"); \ + _zzq_rlval = _zzq_result; \ + } + +#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ + { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ + register unsigned long long int __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR */ \ + "or 2,2,2\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->nraddr = __addr; \ + __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ + /* %R3 = guest_NRADDR_GPR2 */ \ + "or 4,4,4\n\t" \ + "mr %0,3" \ + : "=b" (__addr) \ + : \ + : "r3", "cc", "memory" \ + ); \ + _zzq_orig->r2 = __addr; \ + } + +#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + __SPECIAL_INSTRUCTION_PREAMBLE \ + /* branch-and-link-to-noredir *%R11 */ \ + "or 3,3,3\n\t" + +#endif /* PLAT_ppc64_aix5 */ + +/* Insert assembly code for other platforms here... */ + +#endif /* NVALGRIND */ + + +/* ------------------------------------------------------------------ */ +/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ +/* ugly. It's the least-worst tradeoff I can think of. */ +/* ------------------------------------------------------------------ */ + +/* This section defines magic (a.k.a appalling-hack) macros for doing + guaranteed-no-redirection macros, so as to get from function + wrappers to the functions they are wrapping. The whole point is to + construct standard call sequences, but to do the call itself with a + special no-redirect call pseudo-instruction that the JIT + understands and handles specially. This section is long and + repetitious, and I can't see a way to make it shorter. + + The naming scheme is as follows: + + CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} + + 'W' stands for "word" and 'v' for "void". Hence there are + different macros for calling arity 0, 1, 2, 3, 4, etc, functions, + and for each, the possibility of returning a word-typed result, or + no result. +*/ + +/* Use these to write the name of your wrapper. NOTE: duplicates + VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */ + +/* Use an extra level of macroisation so as to ensure the soname/fnname + args are fully macro-expanded before pasting them together. */ +#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd + +#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ + VG_CONCAT4(_vgwZU_,soname,_,fnname) + +#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ + VG_CONCAT4(_vgwZZ_,soname,_,fnname) + +/* Use this macro from within a wrapper function to collect the + context (address and possibly other info) of the original function. + Once you have that you can then use it in one of the CALL_FN_ + macros. The type of the argument _lval is OrigFn. */ +#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) + +/* Derivatives of the main macros below, for calling functions + returning void. */ + +#define CALL_FN_v_v(fnptr) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_v(_junk,fnptr); } while (0) + +#define CALL_FN_v_W(fnptr, arg1) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_W(_junk,fnptr,arg1); } while (0) + +#define CALL_FN_v_WW(fnptr, arg1,arg2) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) + +#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) + +#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) + +#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) + +#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) + +#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ + do { volatile unsigned long _junk; \ + CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) + +/* ------------------------- x86-{linux,darwin} ---------------- */ + +#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) + +/* These regs are trashed by the hidden call. No need to mention eax + as gcc can already see that, plus causes gcc to bomb. */ +#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" + +/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $4, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $8, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $12, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $16, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $20, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $24, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $28, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $32, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $36, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $40, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $44, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "pushl 48(%%eax)\n\t" \ + "pushl 44(%%eax)\n\t" \ + "pushl 40(%%eax)\n\t" \ + "pushl 36(%%eax)\n\t" \ + "pushl 32(%%eax)\n\t" \ + "pushl 28(%%eax)\n\t" \ + "pushl 24(%%eax)\n\t" \ + "pushl 20(%%eax)\n\t" \ + "pushl 16(%%eax)\n\t" \ + "pushl 12(%%eax)\n\t" \ + "pushl 8(%%eax)\n\t" \ + "pushl 4(%%eax)\n\t" \ + "movl (%%eax), %%eax\n\t" /* target->%eax */ \ + VALGRIND_CALL_NOREDIR_EAX \ + "addl $48, %%esp\n" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_x86_linux || PLAT_x86_darwin */ + +/* ------------------------ amd64-{linux,darwin} --------------- */ + +#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) + +/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ + "rdi", "r8", "r9", "r10", "r11" + +/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned + long) == 8. */ + +/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ + macros. In order not to trash the stack redzone, we need to drop + %rsp by 128 before the hidden call, and restore afterwards. The + nastyness is that it is only by luck that the stack still appears + to be unwindable during the hidden call - since then the behaviour + of any routine using this macro does not match what the CFI data + says. Sigh. + + Why is this important? Imagine that a wrapper has a stack + allocated local, and passes to the hidden call, a pointer to it. + Because gcc does not know about the hidden call, it may allocate + that local in the redzone. Unfortunately the hidden call may then + trash it before it comes to use it. So we must step clear of the + redzone, for the duration of the hidden call, to make it safe. + + Probably the same problem afflicts the other redzone-style ABIs too + (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is + self describing (none of this CFI nonsense) so at least messing + with the stack pointer doesn't give a danger of non-unwindable + stack. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + "addq $128,%%rsp\n\t" \ + VALGRIND_CALL_NOREDIR_RAX \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $8, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $16, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $24, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $32, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $40, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "subq $128,%%rsp\n\t" \ + "pushq 96(%%rax)\n\t" \ + "pushq 88(%%rax)\n\t" \ + "pushq 80(%%rax)\n\t" \ + "pushq 72(%%rax)\n\t" \ + "pushq 64(%%rax)\n\t" \ + "pushq 56(%%rax)\n\t" \ + "movq 48(%%rax), %%r9\n\t" \ + "movq 40(%%rax), %%r8\n\t" \ + "movq 32(%%rax), %%rcx\n\t" \ + "movq 24(%%rax), %%rdx\n\t" \ + "movq 16(%%rax), %%rsi\n\t" \ + "movq 8(%%rax), %%rdi\n\t" \ + "movq (%%rax), %%rax\n\t" /* target->%rax */ \ + VALGRIND_CALL_NOREDIR_RAX \ + "addq $48, %%rsp\n" \ + "addq $128,%%rsp\n\t" \ + : /*out*/ "=a" (_res) \ + : /*in*/ "a" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */ + +/* ------------------------ ppc32-linux ------------------------ */ + +#if defined(PLAT_ppc32_linux) + +/* This is useful for finding out about the on-stack stuff: + + extern int f9 ( int,int,int,int,int,int,int,int,int ); + extern int f10 ( int,int,int,int,int,int,int,int,int,int ); + extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); + extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); + + int g9 ( void ) { + return f9(11,22,33,44,55,66,77,88,99); + } + int g10 ( void ) { + return f10(11,22,33,44,55,66,77,88,99,110); + } + int g11 ( void ) { + return f11(11,22,33,44,55,66,77,88,99,110,121); + } + int g12 ( void ) { + return f12(11,22,33,44,55,66,77,88,99,110,121,132); + } +*/ + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* These CALL_FN_ macros assume that on ppc32-linux, + sizeof(unsigned long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "addi 1,1,16\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "addi 1,1,-16\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "addi 1,1,16\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "addi 1,1,32\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)arg1; \ + _argvec[2] = (unsigned long)arg2; \ + _argvec[3] = (unsigned long)arg3; \ + _argvec[4] = (unsigned long)arg4; \ + _argvec[5] = (unsigned long)arg5; \ + _argvec[6] = (unsigned long)arg6; \ + _argvec[7] = (unsigned long)arg7; \ + _argvec[8] = (unsigned long)arg8; \ + _argvec[9] = (unsigned long)arg9; \ + _argvec[10] = (unsigned long)arg10; \ + _argvec[11] = (unsigned long)arg11; \ + _argvec[12] = (unsigned long)arg12; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "addi 1,1,-32\n\t" \ + /* arg12 */ \ + "lwz 3,48(11)\n\t" \ + "stw 3,20(1)\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,16(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,12(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,8(1)\n\t" \ + /* args1-8 */ \ + "lwz 3,4(11)\n\t" /* arg1->r3 */ \ + "lwz 4,8(11)\n\t" \ + "lwz 5,12(11)\n\t" \ + "lwz 6,16(11)\n\t" /* arg4->r6 */ \ + "lwz 7,20(11)\n\t" \ + "lwz 8,24(11)\n\t" \ + "lwz 9,28(11)\n\t" \ + "lwz 10,32(11)\n\t" /* arg8->r10 */ \ + "lwz 11,0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "addi 1,1,32\n\t" \ + "mr %0,3" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc32_linux */ + +/* ------------------------ ppc64-linux ------------------------ */ + +#if defined(PLAT_ppc64_linux) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)" /* restore tocptr */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + "addi 1,1,128" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-128\n\t" /* expand stack frame */ \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + "addi 1,1,128" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + "addi 1,1,144" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "addi 1,1,-144\n\t" /* expand stack frame */ \ + /* arg12 */ \ + "ld 3,96(11)\n\t" \ + "std 3,136(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + "addi 1,1,144" /* restore frame */ \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64_linux */ + +/* ------------------------- arm-linux ------------------------- */ + +#if defined(PLAT_arm_linux) + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14" + +/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[1]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[2]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + __asm__ volatile( \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + __asm__ volatile( \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[4]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + __asm__ volatile( \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0\n" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[5]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + __asm__ volatile( \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[6]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + __asm__ volatile( \ + "ldr r0, [%1, #20] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #4 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[7]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + __asm__ volatile( \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #8 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[8]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + __asm__ volatile( \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #12 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[9]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + __asm__ volatile( \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "push {r0, r1, r2, r3} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #16 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[10]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + __asm__ volatile( \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #20 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[11]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + __asm__ volatile( \ + "ldr r0, [%1, #40] \n\t" \ + "push {r0} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #24 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[12]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + __asm__ volatile( \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "push {r0, r1} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #28 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ + arg6,arg7,arg8,arg9,arg10, \ + arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[13]; \ + volatile unsigned long _res; \ + _argvec[0] = (unsigned long)_orig.nraddr; \ + _argvec[1] = (unsigned long)(arg1); \ + _argvec[2] = (unsigned long)(arg2); \ + _argvec[3] = (unsigned long)(arg3); \ + _argvec[4] = (unsigned long)(arg4); \ + _argvec[5] = (unsigned long)(arg5); \ + _argvec[6] = (unsigned long)(arg6); \ + _argvec[7] = (unsigned long)(arg7); \ + _argvec[8] = (unsigned long)(arg8); \ + _argvec[9] = (unsigned long)(arg9); \ + _argvec[10] = (unsigned long)(arg10); \ + _argvec[11] = (unsigned long)(arg11); \ + _argvec[12] = (unsigned long)(arg12); \ + __asm__ volatile( \ + "ldr r0, [%1, #40] \n\t" \ + "ldr r1, [%1, #44] \n\t" \ + "ldr r2, [%1, #48] \n\t" \ + "push {r0, r1, r2} \n\t" \ + "ldr r0, [%1, #20] \n\t" \ + "ldr r1, [%1, #24] \n\t" \ + "ldr r2, [%1, #28] \n\t" \ + "ldr r3, [%1, #32] \n\t" \ + "ldr r4, [%1, #36] \n\t" \ + "push {r0, r1, r2, r3, r4} \n\t" \ + "ldr r0, [%1, #4] \n\t" \ + "ldr r1, [%1, #8] \n\t" \ + "ldr r2, [%1, #12] \n\t" \ + "ldr r3, [%1, #16] \n\t" \ + "ldr r4, [%1] \n\t" /* target->r4 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ + "add sp, sp, #32 \n\t" \ + "mov %0, r0" \ + : /*out*/ "=r" (_res) \ + : /*in*/ "0" (&_argvec[0]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_arm_linux */ + +/* ------------------------ ppc32-aix5 ------------------------- */ + +#if defined(PLAT_ppc32_aix5) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Expand the stack frame, copying enough info that unwinding + still works. Trashes r3. */ + +#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ + "addi 1,1,-" #_n_fr "\n\t" \ + "lwz 3," #_n_fr "(1)\n\t" \ + "stw 3,0(1)\n\t" + +#define VG_CONTRACT_FRAME_BY(_n_fr) \ + "addi 1,1," #_n_fr "\n\t" + +/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned + long) == 4. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(64) \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(64) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(64) \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(64) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(72) \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,64(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(72) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "stw 2,-8(11)\n\t" /* save tocptr */ \ + "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(72) \ + /* arg12 */ \ + "lwz 3,48(11)\n\t" \ + "stw 3,68(1)\n\t" \ + /* arg11 */ \ + "lwz 3,44(11)\n\t" \ + "stw 3,64(1)\n\t" \ + /* arg10 */ \ + "lwz 3,40(11)\n\t" \ + "stw 3,60(1)\n\t" \ + /* arg9 */ \ + "lwz 3,36(11)\n\t" \ + "stw 3,56(1)\n\t" \ + /* args1-8 */ \ + "lwz 3, 4(11)\n\t" /* arg1->r3 */ \ + "lwz 4, 8(11)\n\t" /* arg2->r4 */ \ + "lwz 5, 12(11)\n\t" /* arg3->r5 */ \ + "lwz 6, 16(11)\n\t" /* arg4->r6 */ \ + "lwz 7, 20(11)\n\t" /* arg5->r7 */ \ + "lwz 8, 24(11)\n\t" /* arg6->r8 */ \ + "lwz 9, 28(11)\n\t" /* arg7->r9 */ \ + "lwz 10, 32(11)\n\t" /* arg8->r10 */ \ + "lwz 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "lwz 2,-8(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(72) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc32_aix5 */ + +/* ------------------------ ppc64-aix5 ------------------------- */ + +#if defined(PLAT_ppc64_aix5) + +/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ + +/* These regs are trashed by the hidden call. */ +#define __CALLER_SAVED_REGS \ + "lr", "ctr", "xer", \ + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ + "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ + "r11", "r12", "r13" + +/* Expand the stack frame, copying enough info that unwinding + still works. Trashes r3. */ + +#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ + "addi 1,1,-" #_n_fr "\n\t" \ + "ld 3," #_n_fr "(1)\n\t" \ + "std 3,0(1)\n\t" + +#define VG_CONTRACT_FRAME_BY(_n_fr) \ + "addi 1,1," #_n_fr "\n\t" + +/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned + long) == 8. */ + +#define CALL_FN_W_v(lval, orig) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+0]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_W(lval, orig, arg1) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+1]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+2]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+3]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+4]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+5]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+6]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+7]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+8]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+9]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(128) \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(128) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+10]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(128) \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(128) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+11]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(144) \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(144) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ + arg7,arg8,arg9,arg10,arg11,arg12) \ + do { \ + volatile OrigFn _orig = (orig); \ + volatile unsigned long _argvec[3+12]; \ + volatile unsigned long _res; \ + /* _argvec[0] holds current r2 across the call */ \ + _argvec[1] = (unsigned long)_orig.r2; \ + _argvec[2] = (unsigned long)_orig.nraddr; \ + _argvec[2+1] = (unsigned long)arg1; \ + _argvec[2+2] = (unsigned long)arg2; \ + _argvec[2+3] = (unsigned long)arg3; \ + _argvec[2+4] = (unsigned long)arg4; \ + _argvec[2+5] = (unsigned long)arg5; \ + _argvec[2+6] = (unsigned long)arg6; \ + _argvec[2+7] = (unsigned long)arg7; \ + _argvec[2+8] = (unsigned long)arg8; \ + _argvec[2+9] = (unsigned long)arg9; \ + _argvec[2+10] = (unsigned long)arg10; \ + _argvec[2+11] = (unsigned long)arg11; \ + _argvec[2+12] = (unsigned long)arg12; \ + __asm__ volatile( \ + "mr 11,%1\n\t" \ + VG_EXPAND_FRAME_BY_trashes_r3(512) \ + "std 2,-16(11)\n\t" /* save tocptr */ \ + "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ + VG_EXPAND_FRAME_BY_trashes_r3(144) \ + /* arg12 */ \ + "ld 3,96(11)\n\t" \ + "std 3,136(1)\n\t" \ + /* arg11 */ \ + "ld 3,88(11)\n\t" \ + "std 3,128(1)\n\t" \ + /* arg10 */ \ + "ld 3,80(11)\n\t" \ + "std 3,120(1)\n\t" \ + /* arg9 */ \ + "ld 3,72(11)\n\t" \ + "std 3,112(1)\n\t" \ + /* args1-8 */ \ + "ld 3, 8(11)\n\t" /* arg1->r3 */ \ + "ld 4, 16(11)\n\t" /* arg2->r4 */ \ + "ld 5, 24(11)\n\t" /* arg3->r5 */ \ + "ld 6, 32(11)\n\t" /* arg4->r6 */ \ + "ld 7, 40(11)\n\t" /* arg5->r7 */ \ + "ld 8, 48(11)\n\t" /* arg6->r8 */ \ + "ld 9, 56(11)\n\t" /* arg7->r9 */ \ + "ld 10, 64(11)\n\t" /* arg8->r10 */ \ + "ld 11, 0(11)\n\t" /* target->r11 */ \ + VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ + "mr 11,%1\n\t" \ + "mr %0,3\n\t" \ + "ld 2,-16(11)\n\t" /* restore tocptr */ \ + VG_CONTRACT_FRAME_BY(144) \ + VG_CONTRACT_FRAME_BY(512) \ + : /*out*/ "=r" (_res) \ + : /*in*/ "r" (&_argvec[2]) \ + : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ + ); \ + lval = (__typeof__(lval)) _res; \ + } while (0) + +#endif /* PLAT_ppc64_aix5 */ + + +/* ------------------------------------------------------------------ */ +/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ +/* */ +/* ------------------------------------------------------------------ */ + +/* Some request codes. There are many more of these, but most are not + exposed to end-user view. These are the public ones, all of the + form 0x1000 + small_number. + + Core ones are in the range 0x00000000--0x0000ffff. The non-public + ones start at 0x2000. +*/ + +/* These macros are used by tools -- they must be public, but don't + embed them into other programs. */ +#define VG_USERREQ_TOOL_BASE(a,b) \ + ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) +#define VG_IS_TOOL_USERREQ(a, b, v) \ + (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) + +/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! + This enum comprises an ABI exported by Valgrind to programs + which use client requests. DO NOT CHANGE THE ORDER OF THESE + ENTRIES, NOR DELETE ANY -- add new ones at the end. */ +typedef + enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, + VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, + + /* These allow any function to be called from the simulated + CPU but run on the real CPU. Nb: the first arg passed to + the function is always the ThreadId of the running + thread! So CLIENT_CALL0 actually requires a 1 arg + function, etc. */ + VG_USERREQ__CLIENT_CALL0 = 0x1101, + VG_USERREQ__CLIENT_CALL1 = 0x1102, + VG_USERREQ__CLIENT_CALL2 = 0x1103, + VG_USERREQ__CLIENT_CALL3 = 0x1104, + + /* Can be useful in regression testing suites -- eg. can + send Valgrind's output to /dev/null and still count + errors. */ + VG_USERREQ__COUNT_ERRORS = 0x1201, + + /* These are useful and can be interpreted by any tool that + tracks malloc() et al, by using vg_replace_malloc.c. */ + VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, + VG_USERREQ__FREELIKE_BLOCK = 0x1302, + /* Memory pool support. */ + VG_USERREQ__CREATE_MEMPOOL = 0x1303, + VG_USERREQ__DESTROY_MEMPOOL = 0x1304, + VG_USERREQ__MEMPOOL_ALLOC = 0x1305, + VG_USERREQ__MEMPOOL_FREE = 0x1306, + VG_USERREQ__MEMPOOL_TRIM = 0x1307, + VG_USERREQ__MOVE_MEMPOOL = 0x1308, + VG_USERREQ__MEMPOOL_CHANGE = 0x1309, + VG_USERREQ__MEMPOOL_EXISTS = 0x130a, + + /* Allow printfs to valgrind log. */ + /* The first two pass the va_list argument by value, which + assumes it is the same size as or smaller than a UWord, + which generally isn't the case. Hence are deprecated. + The second two pass the vargs by reference and so are + immune to this problem. */ + /* both :: char* fmt, va_list vargs (DEPRECATED) */ + VG_USERREQ__PRINTF = 0x1401, + VG_USERREQ__PRINTF_BACKTRACE = 0x1402, + /* both :: char* fmt, va_list* vargs */ + VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, + + /* Stack support. */ + VG_USERREQ__STACK_REGISTER = 0x1501, + VG_USERREQ__STACK_DEREGISTER = 0x1502, + VG_USERREQ__STACK_CHANGE = 0x1503, + + /* Wine support */ + VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601 + } Vg_ClientRequest; + +#if !defined(__GNUC__) +# define __extension__ /* */ +#endif + +/* Returns the number of Valgrinds this code is running under. That + is, 0 if running natively, 1 if running under Valgrind, 2 if + running under Valgrind which is running under another Valgrind, + etc. */ +#define RUNNING_ON_VALGRIND __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \ + VG_USERREQ__RUNNING_ON_VALGRIND, \ + 0, 0, 0, 0, 0); \ + _qzz_res; \ + }) + + +/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + + _qzz_len - 1]. Useful if you are debugging a JITter or some such, + since it provides a way to make sure valgrind will retranslate the + invalidated area. Returns no value. */ +#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__DISCARD_TRANSLATIONS, \ + _qzz_addr, _qzz_len, 0, 0, 0); \ + } + + +/* These requests are for getting Valgrind itself to print something. + Possibly with a backtrace. This is a really ugly hack. The return value + is the number of characters printed, excluding the "**** " part at the + start and the backtrace (if present). */ + +#if defined(NVALGRIND) + +# define VALGRIND_PRINTF(...) +# define VALGRIND_PRINTF_BACKTRACE(...) + +#else /* NVALGRIND */ + +/* Modern GCC will optimize the static routine out if unused, + and unused attribute will shut down warnings about it. */ +static int VALGRIND_PRINTF(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +static int +VALGRIND_PRINTF(const char *format, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, + VG_USERREQ__PRINTF_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); + va_end(vargs); + return (int)_qzz_res; +} + +static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) + __attribute__((format(__printf__, 1, 2), __unused__)); +static int +VALGRIND_PRINTF_BACKTRACE(const char *format, ...) +{ + unsigned long _qzz_res; + va_list vargs; + va_start(vargs, format); + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, + VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, + (unsigned long)format, + (unsigned long)&vargs, + 0, 0, 0); + va_end(vargs); + return (int)_qzz_res; +} + +#endif /* NVALGRIND */ + + +/* These requests allow control to move from the simulated CPU to the + real CPU, calling an arbitary function. + + Note that the current ThreadId is inserted as the first argument. + So this call: + + VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) + + requires f to have this signature: + + Word f(Word tid, Word arg1, Word arg2) + + where "Word" is a word-sized type. + + Note that these client requests are not entirely reliable. For example, + if you call a function with them that subsequently calls printf(), + there's a high chance Valgrind will crash. Generally, your prospects of + these working are made higher if the called function does not refer to + any global variables, and does not refer to any libc or other functions + (printf et al). Any kind of entanglement with libc or dynamic linking is + likely to have a bad outcome, for tricky reasons which we've grappled + with a lot in the past. +*/ +#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL0, \ + _qyy_fn, \ + 0, 0, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL1, \ + _qyy_fn, \ + _qyy_arg1, 0, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL2, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, 0, 0); \ + _qyy_res; \ + }) + +#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ + __extension__ \ + ({unsigned long _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__CLIENT_CALL3, \ + _qyy_fn, \ + _qyy_arg1, _qyy_arg2, \ + _qyy_arg3, 0); \ + _qyy_res; \ + }) + + +/* Counts the number of errors that have been recorded by a tool. Nb: + the tool must record the errors with VG_(maybe_record_error)() or + VG_(unique_error)() for them to be counted. */ +#define VALGRIND_COUNT_ERRORS \ + __extension__ \ + ({unsigned int _qyy_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ + VG_USERREQ__COUNT_ERRORS, \ + 0, 0, 0, 0, 0); \ + _qyy_res; \ + }) + +/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing + when heap blocks are allocated in order to give accurate results. This + happens automatically for the standard allocator functions such as + malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, + delete[], etc. + + But if your program uses a custom allocator, this doesn't automatically + happen, and Valgrind will not do as well. For example, if you allocate + superblocks with mmap() and then allocates chunks of the superblocks, all + Valgrind's observations will be at the mmap() level and it won't know that + the chunks should be considered separate entities. In Memcheck's case, + that means you probably won't get heap block overrun detection (because + there won't be redzones marked as unaddressable) and you definitely won't + get any leak detection. + + The following client requests allow a custom allocator to be annotated so + that it can be handled accurately by Valgrind. + + VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated + by a malloc()-like function. For Memcheck (an illustrative case), this + does two things: + + - It records that the block has been allocated. This means any addresses + within the block mentioned in error messages will be + identified as belonging to the block. It also means that if the block + isn't freed it will be detected by the leak checker. + + - It marks the block as being addressable and undefined (if 'is_zeroed' is + not set), or addressable and defined (if 'is_zeroed' is set). This + controls how accesses to the block by the program are handled. + + 'addr' is the start of the usable block (ie. after any + redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator + can apply redzones -- these are blocks of padding at the start and end of + each block. Adding redzones is recommended as it makes it much more likely + Valgrind will spot block overruns. `is_zeroed' indicates if the memory is + zeroed (or filled with another predictable value), as is the case for + calloc(). + + VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a + heap block -- that will be used by the client program -- is allocated. + It's best to put it at the outermost level of the allocator if possible; + for example, if you have a function my_alloc() which calls + internal_alloc(), and the client request is put inside internal_alloc(), + stack traces relating to the heap block will contain entries for both + my_alloc() and internal_alloc(), which is probably not what you want. + + For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out + custom blocks from within a heap block, B, that has been allocated with + malloc/calloc/new/etc, then block B will be *ignored* during leak-checking + -- the custom blocks will take precedence. + + VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For + Memcheck, it does two things: + + - It records that the block has been deallocated. This assumes that the + block was annotated as having been allocated via + VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. + + - It marks the block as being unaddressable. + + VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a + heap block is deallocated. + + In many cases, these two client requests will not be enough to get your + allocator working well with Memcheck. More specifically, if your allocator + writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call + will be necessary to mark the memory as addressable just before the zeroing + occurs, otherwise you'll get a lot of invalid write errors. For example, + you'll need to do this if your allocator recycles freed blocks, but it + zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). + Alternatively, if your allocator reuses freed blocks for allocator-internal + data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. + + Really, what's happening is a blurring of the lines between the client + program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the + memory should be considered unaddressable to the client program, but the + allocator knows more than the rest of the client program and so may be able + to safely access it. Extra client requests are necessary for Valgrind to + understand the distinction between the allocator and the rest of the + program. + + Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request; it + has to be emulated with MALLOCLIKE/FREELIKE and memory copying. + + Ignored if addr == 0. +*/ +#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MALLOCLIKE_BLOCK, \ + addr, sizeB, rzB, is_zeroed, 0); \ + } + +/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. + Ignored if addr == 0. +*/ +#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__FREELIKE_BLOCK, \ + addr, rzB, 0, 0, 0); \ + } + +/* Create a memory pool. */ +#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__CREATE_MEMPOOL, \ + pool, rzB, is_zeroed, 0, 0); \ + } + +/* Destroy a memory pool. */ +#define VALGRIND_DESTROY_MEMPOOL(pool) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__DESTROY_MEMPOOL, \ + pool, 0, 0, 0, 0); \ + } + +/* Associate a piece of memory with a memory pool. */ +#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_ALLOC, \ + pool, addr, size, 0, 0); \ + } + +/* Disassociate a piece of memory from a memory pool. */ +#define VALGRIND_MEMPOOL_FREE(pool, addr) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_FREE, \ + pool, addr, 0, 0, 0); \ + } + +/* Disassociate any pieces outside a particular range. */ +#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_TRIM, \ + pool, addr, size, 0, 0); \ + } + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MOVE_MEMPOOL, \ + poolA, poolB, 0, 0, 0); \ + } + +/* Resize and/or move a piece associated with a memory pool. */ +#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_CHANGE, \ + pool, addrA, addrB, size, 0); \ + } + +/* Return 1 if a mempool exists, else 0. */ +#define VALGRIND_MEMPOOL_EXISTS(pool) \ + __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__MEMPOOL_EXISTS, \ + pool, 0, 0, 0, 0); \ + _qzz_res; \ + }) + +/* Mark a piece of memory as being a stack. Returns a stack id. */ +#define VALGRIND_STACK_REGISTER(start, end) \ + __extension__ \ + ({unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__STACK_REGISTER, \ + start, end, 0, 0, 0); \ + _qzz_res; \ + }) + +/* Unmark the piece of memory associated with a stack id as being a + stack. */ +#define VALGRIND_STACK_DEREGISTER(id) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__STACK_DEREGISTER, \ + id, 0, 0, 0, 0); \ + } + +/* Change the start and end address of the stack id. */ +#define VALGRIND_STACK_CHANGE(id, start, end) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__STACK_CHANGE, \ + id, start, end, 0, 0); \ + } + +/* Load PDB debug info for Wine PE image_map. */ +#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ + {unsigned int _qzz_res; \ + VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \ + VG_USERREQ__LOAD_PDB_DEBUGINFO, \ + fd, ptr, total_size, delta, 0); \ + } + + +#undef PLAT_x86_linux +#undef PLAT_amd64_linux +#undef PLAT_ppc32_linux +#undef PLAT_ppc64_linux +#undef PLAT_arm_linux +#undef PLAT_ppc32_aix5 +#undef PLAT_ppc64_aix5 + +#endif /* __VALGRIND_H */ diff --git a/packages/CLPBN/clpbn/graphviz.yap b/packages/CLPBN/clpbn/graphviz.yap index 6d81cf3da..825fae3a1 100644 --- a/packages/CLPBN/clpbn/graphviz.yap +++ b/packages/CLPBN/clpbn/graphviz.yap @@ -22,7 +22,7 @@ output_var(Stream, V) :- Parents = [_|_], !, format(Stream, ' ',[]), output_parents(Stream, Parents), - format(' -> ',[]), + format(Stream,' -> ',[]), output_key(Stream,Key), nl(Stream). output_var(_, _). diff --git a/packages/CLPBN/clpbn/table.yap b/packages/CLPBN/clpbn/table.yap index 0acd09478..9c07503bc 100644 --- a/packages/CLPBN/clpbn/table.yap +++ b/packages/CLPBN/clpbn/table.yap @@ -96,7 +96,7 @@ clpbn_table(F/N,M) :- Key =.. L1, atom_concat(F, '___tabled', NF), L2 = [_|Args], - S1 =.. [NF|Args], + _S1 =.. [NF|Args], L0 = [_|OArgs], S2 =.. [NF|OArgs], asserta(clpbn_table(S, M, S2)), diff --git a/packages/CLPBN/clpbn/vel.yap b/packages/CLPBN/clpbn/ve.yap similarity index 89% rename from packages/CLPBN/clpbn/vel.yap rename to packages/CLPBN/clpbn/ve.yap index 40940e272..be2696bd1 100644 --- a/packages/CLPBN/clpbn/vel.yap +++ b/packages/CLPBN/clpbn/ve.yap @@ -14,10 +14,10 @@ *********************************/ -:- module(clpbn_vel, [vel/3, - check_if_vel_done/1, - init_vel_solver/4, - run_vel_solver/3]). +:- module(clpbn_ve, [ve/3, + check_if_ve_done/1, + init_ve_solver/4, + run_ve_solver/3]). :- attribute size/1, all_diffs/1. @@ -64,40 +64,41 @@ [check_for_agg_vars/2]). -check_if_vel_done(Var) :- +check_if_ve_done(Var) :- get_atts(Var, [size(_)]), !. % % implementation of the well known variable elimination algorithm % -vel([[]],_,_) :- !. -vel([LVs],Vs0,AllDiffs) :- - init_vel_solver([LVs], Vs0, AllDiffs, State), +ve([[]],_,_) :- !. +ve([LVs],Vs0,AllDiffs) :- + init_ve_solver([LVs], Vs0, AllDiffs, State), % variable elimination proper - run_vel_solver([LVs], [LPs], State), + run_ve_solver([LVs], [LPs], State), % bind Probs back to variables so that they can be output. clpbn_bind_vals([LVs],[LPs],AllDiffs). -init_vel_solver(Qs, Vs0, _, LVis) :- +init_ve_solver(Qs, Vs0, _, LVis) :- check_for_agg_vars(Vs0, Vs1), % LVi will have a list of CLPBN variables % Tables0 will have the full data on each variable init_influences(Vs1, G, RG), - init_vel_solver_for_questions(Qs, G, RG, _, LVis). + init_ve_solver_for_questions(Qs, G, RG, _, LVis). -init_vel_solver_for_questions([], _, _, [], []). -init_vel_solver_for_questions([Vs|MVs], G, RG, [NVs|MNVs0], [NVs|LVis]) :- +init_ve_solver_for_questions([], _, _, [], []). +init_ve_solver_for_questions([Vs|MVs], G, RG, [NVs|MNVs0], [NVs|LVis]) :- influences(Vs, _, NVs0, G, RG), sort(NVs0, NVs), %clpbn_gviz:clpbn2gviz(user_error, test, NVs, Vs), - init_vel_solver_for_questions(MVs, G, RG, MNVs0, LVis). + init_ve_solver_for_questions(MVs, G, RG, MNVs0, LVis). % use a findall to recover space without needing for GC -run_vel_solver(LVs, LPs, LNVs) :- - findall(Ps, solve_vel(LVs, LNVs, Ps), LPs). +run_ve_solver(LVs, LPs, LNVs) :- + findall(Ps, solve_ve(LVs, LNVs, Ps), LPs). -solve_vel([LVs|_], [NVs0|_], Ps) :- -% length(NVs0, L), (L > 64 -> clpbn_gviz:clpbn2gviz(user_error,sort,NVs0,LVs) ; true ), +solve_ve([LVs|_], [NVs0|_], Ps) :- +% length(NVs0, L), (L > 415 -> clpbn_gviz:clpbn2gviz(user_error,sort,NVs0,LVs) ; true ), +% length(NVs0, L), writeln(+LVs:L), find_all_clpbn_vars(NVs0, NVs0, LV0, LVi, Tables0), sort(LV0, LV), % construct the graph @@ -108,8 +109,8 @@ solve_vel([LVs|_], [NVs0|_], Ps) :- % move from potentials back to probabilities normalise_CPT(Dist,MPs), list_from_CPT(MPs, Ps). -solve_vel([_|MoreLVs], [_|MoreLVis], Ps) :- - solve_vel(MoreLVs, MoreLVis, Ps). +solve_ve([_|MoreLVs], [_|MoreLVis], Ps) :- + solve_ve(MoreLVs, MoreLVis, Ps). exps([],[]). exps([L|LD],[O|LDE]) :- @@ -133,7 +134,7 @@ find_all_clpbn_vars([V|Vs], NVs0, [Var|LV], ProcessedVars, [table(I,Table,Parent % variables with evidence should not be processed. (var(Ev) -> Var = var(V,I,Sz,Vals,Parents,Ev,_,_), - vel_get_dist_size(V,Sz), + ve_get_dist_size(V,Sz), ProcessedVars = [Var|ProcessedVars0] ; ProcessedVars = ProcessedVars0 @@ -191,7 +192,7 @@ compute_size([tab(_,Vs,_)|Tabs],Vs0,K) :- multiply_sizes([],K,K). multiply_sizes([V|Vs],K0,K) :- - vel_get_dist_size(V, Sz), + ve_get_dist_size(V, Sz), KI is K0*Sz, multiply_sizes(Vs,KI,K). @@ -280,9 +281,9 @@ update_tables([tab(Tab0,Vs,Sz)|Tabs],[tab(Tab0,Vs,Sz)|NTabs],Table,V) :- update_tables([_|Tabs],NTabs,Table,V) :- update_tables(Tabs,NTabs,Table,V). -vel_get_dist_size(V,Sz) :- +ve_get_dist_size(V,Sz) :- get_atts(V, [size(Sz)]), !. -vel_get_dist_size(V,Sz) :- +ve_get_dist_size(V,Sz) :- clpbn:get_atts(V,dist(Id,_)), !, get_dist_domain_size(Id,Sz), put_atts(V, [size(Sz)]). diff --git a/packages/CLPBN/learning/em.yap b/packages/CLPBN/learning/em.yap index 7e3f64c31..234912f3f 100644 --- a/packages/CLPBN/learning/em.yap +++ b/packages/CLPBN/learning/em.yap @@ -11,6 +11,7 @@ [clpbn_init_graph/1, clpbn_init_solver/5, clpbn_run_solver/4, + clpbn_finalize_solver/1, clpbn_flag/2]). :- use_module(library('clpbn/dists'), @@ -53,6 +54,7 @@ em(Items, MaxError, MaxIts, Tables, Likelihood) :- catch(init_em(Items, State),Error,handle_em(Error)), em_loop(0, 0.0, State, MaxError, MaxIts, Likelihood, Tables), + clpbn_finalize_solver(State), assert(em_found(Tables, Likelihood)), fail. % get rid of new random variables the easy way :) @@ -90,7 +92,7 @@ init_em(Items, state( AllDists, AllDistInstances, MargVars, SolverVars)) :- em_loop(Its, Likelihood0, State, MaxError, MaxIts, LikelihoodF, FTables) :- estimate(State, LPs), maximise(State, Tables, LPs, Likelihood), - writeln(Likelihood:Its:Likelihood0:Tables), +% writeln(Likelihood:Its:Likelihood0:Tables), ( ( abs((Likelihood - Likelihood0)/Likelihood) < MaxError @@ -205,7 +207,7 @@ compute_parameters([Id-Samples|Dists], [Id-NewTable|Tables], MDistTable, Lik0, empty_dist(Id, Table0), add_samples(Samples, Table0, MDistTable), soften_sample(Table0, SoftenedTable), - matrix:matrix_sum(Table0,TotM), +% matrix:matrix_sum(Table0,TotM), normalise_counts(SoftenedTable, NewTable), compute_likelihood(Table0, NewTable, DeltaLik), dist_new_table(Id, NewTable), diff --git a/packages/CLPBN/learning/example/school_params.yap b/packages/CLPBN/learning/example/school_params.yap index f97119b77..199e4534f 100644 --- a/packages/CLPBN/learning/example/school_params.yap +++ b/packages/CLPBN/learning/example/school_params.yap @@ -4,13 +4,14 @@ :- [pos:train]. -:- ['~/Yap/work/packages/CLPBN/clpbn/examples/School/school_32']. +:- ['../../examples/School/school_32']. -:- ['~/Yap/work/packages/CLPBN/learning/em']. +:- use_module(library(clpbn/learning/em)). %:- clpbn:set_clpbn_flag(em_solver,gibbs). -:- clpbn:set_clpbn_flag(em_solver,jt). -%:- clpbn:set_clpbn_flag(em_solver,vel). +%:- clpbn:set_clpbn_flag(em_solver,jt). +:- clpbn:set_clpbn_flag(em_solver,ve). +%:- clpbn:set_clpbn_flag(em_solver,bp). timed_main :- statistics(runtime, _), @@ -24,6 +25,19 @@ main :- em(L,0.01,10,CPTs,Lik), writeln(Lik:CPTs). +debug_school :- + graph(L), + em(L,0.01,10,CPTs,Lik), + writeln(Lik:CPTs). + +run_queries([]). +run_queries(Q.L) :- + call(Q), + run_queries(L). + +graph([professor_ability(p0,_G131367),professor_ability(p1,h),professor_ability(p2,_G131377),professor_ability(p3,_G131382),professor_ability(p4,_G131387),professor_ability(p5,_G131392),professor_ability(p6,_G131397),professor_ability(p7,l),professor_ability(p8,m),professor_ability(p9,h),professor_ability(p10,m),professor_ability(p11,_G131422),professor_ability(p12,_G131427),professor_ability(p13,_G131432),professor_ability(p14,_G131437),professor_ability(p15,_G131442),professor_ability(p16,_G131447),professor_ability(p17,m),professor_ability(p18,l),professor_ability(p19,h),professor_ability(p20,h),professor_ability(p21,_G131472),professor_ability(p22,m),professor_ability(p23,m),professor_ability(p24,l),professor_ability(p25,m),professor_ability(p26,_G131497),professor_ability(p27,h),professor_ability(p28,h),professor_ability(p29,_G131512),professor_ability(p30,_G131517),professor_ability(p31,_G131522),professor_popularity(p0,h),professor_popularity(p1,h),professor_popularity(p2,_G131537),professor_popularity(p3,h),professor_popularity(p4,h),professor_popularity(p5,h),professor_popularity(p6,l),professor_popularity(p7,l),professor_popularity(p8,_G131567),professor_popularity(p9,_G131572),professor_popularity(p10,l),professor_popularity(p11,_G131582),professor_popularity(p12,h),professor_popularity(p13,l),professor_popularity(p14,_G131597),professor_popularity(p15,h),professor_popularity(p16,m),professor_popularity(p17,_G131612),professor_popularity(p18,_G131617),professor_popularity(p19,_G131622),professor_popularity(p20,_G131627),professor_popularity(p21,h),professor_popularity(p22,_G131637),professor_popularity(p23,_G131642),professor_popularity(p24,l),professor_popularity(p25,_G131652),professor_popularity(p26,_G131657),professor_popularity(p27,h),professor_popularity(p28,h),professor_popularity(p29,_G131672),professor_popularity(p30,m),professor_popularity(p31,_G131682),registration_grade(r0,a),registration_grade(r1,_G131692),registration_grade(r2,_G131697),registration_grade(r3,c),registration_grade(r4,c),registration_grade(r5,c),registration_grade(r6,_G131717),registration_grade(r7,a),registration_grade(r8,b),registration_grade(r9,_G131732),registration_grade(r10,_G131737),registration_grade(r11,a),registration_grade(r12,_G131747),registration_grade(r13,a),registration_grade(r14,_G131757),registration_grade(r15,b),registration_grade(r16,a),registration_grade(r17,b),registration_grade(r18,_G131777),registration_grade(r19,_G131782),registration_grade(r20,c),registration_grade(r21,_G131792),registration_grade(r22,_G131797),registration_grade(r23,_G131802),registration_grade(r24,b),registration_grade(r25,a),registration_grade(r26,_G131817),registration_grade(r27,_G131822),registration_grade(r28,c),registration_grade(r29,b),registration_grade(r30,c),registration_grade(r31,b),registration_grade(r32,_G131847),registration_grade(r33,a),registration_grade(r34,c),registration_grade(r35,c),registration_grade(r36,a),registration_grade(r37,a),registration_grade(r38,c),registration_grade(r39,a),registration_grade(r40,_G131887),registration_grade(r41,_G131892),registration_grade(r42,_G131897),registration_grade(r43,a),registration_grade(r44,a),registration_grade(r45,a),registration_grade(r46,a),registration_grade(r47,_G131922),registration_grade(r48,_G131927),registration_grade(r49,b),registration_grade(r50,b),registration_grade(r51,b),registration_grade(r52,_G131947),registration_grade(r53,a),registration_grade(r54,_G131957),registration_grade(r55,a),registration_grade(r56,c),registration_grade(r57,_G131972),registration_grade(r58,_G131977),registration_grade(r59,_G131982),registration_grade(r60,_G131987),registration_grade(r61,a),registration_grade(r62,_G131997),registration_grade(r63,b),registration_grade(r64,b),registration_grade(r65,b),registration_grade(r66,_G132017),registration_grade(r67,b),registration_grade(r68,a),registration_grade(r69,_G132032),registration_grade(r70,_G132037),registration_grade(r71,_G132042),registration_grade(r72,_G132047),registration_grade(r73,_G132052),registration_grade(r74,a),registration_grade(r75,_G132062),registration_grade(r76,_G132067),registration_grade(r77,_G132072),registration_grade(r78,b),registration_grade(r79,_G132082),registration_grade(r80,_G132087),registration_grade(r81,_G132092),registration_grade(r82,_G132097),registration_grade(r83,_G132102),registration_grade(r84,_G132107),registration_grade(r85,b),registration_grade(r86,_G132117),registration_grade(r87,b),registration_grade(r88,_G132127),registration_grade(r89,_G132132),registration_grade(r90,_G132137),registration_grade(r91,a),registration_grade(r92,_G132147),registration_grade(r93,_G132152),registration_grade(r94,_G132157),registration_grade(r95,_G132162),registration_grade(r96,_G132167),registration_grade(r97,a),registration_grade(r98,b),registration_grade(r99,b),registration_grade(r100,a),registration_grade(r101,a),registration_grade(r102,a),registration_grade(r103,_G132202),registration_grade(r104,_G132207),registration_grade(r105,c),registration_grade(r106,b),registration_grade(r107,b),registration_grade(r108,_G132227),registration_grade(r109,_G132232),registration_grade(r110,a),registration_grade(r111,_G132242),registration_grade(r112,_G132247),registration_grade(r113,_G132252),registration_grade(r114,_G132257),registration_grade(r115,d),registration_grade(r116,b),registration_grade(r117,_G132272),registration_grade(r118,_G132277),registration_grade(r119,b),registration_grade(r120,b),registration_grade(r121,_G132292),registration_grade(r122,_G132297),registration_grade(r123,a),registration_grade(r124,a),registration_grade(r125,_G132312),registration_grade(r126,_G132317),registration_grade(r127,b),registration_grade(r128,a),registration_grade(r129,c),registration_grade(r130,a),registration_grade(r131,a),registration_grade(r132,b),registration_grade(r133,_G132352),registration_grade(r134,_G132357),registration_grade(r135,_G132362),registration_grade(r136,_G132367),registration_grade(r137,b),registration_grade(r138,a),registration_grade(r139,_G132382),registration_grade(r140,_G132387),registration_grade(r141,b),registration_grade(r142,_G132397),registration_grade(r143,b),registration_grade(r144,c),registration_grade(r145,b),registration_grade(r146,_G132417),registration_grade(r147,_G132422),registration_grade(r148,_G132427),registration_grade(r149,a),registration_grade(r150,_G132437),registration_grade(r151,a),registration_grade(r152,_G132447),registration_grade(r153,_G132452),registration_grade(r154,a),registration_grade(r155,c),registration_grade(r156,b),registration_grade(r157,b),registration_grade(r158,c),registration_grade(r159,b),registration_grade(r160,a),registration_grade(r161,_G132492),registration_grade(r162,_G132497),registration_grade(r163,_G132502),registration_grade(r164,b),registration_grade(r165,b),registration_grade(r166,_G132517),registration_grade(r167,a),registration_grade(r168,a),registration_grade(r169,_G132532),registration_grade(r170,_G132537),registration_grade(r171,a),registration_grade(r172,c),registration_grade(r173,b),registration_grade(r174,_G132557),registration_grade(r175,_G132562),registration_grade(r176,b),registration_grade(r177,c),registration_grade(r178,b),registration_grade(r179,d),registration_grade(r180,c),registration_grade(r181,a),registration_grade(r182,b),registration_grade(r183,a),registration_grade(r184,_G132607),registration_grade(r185,_G132612),registration_grade(r186,c),registration_grade(r187,a),registration_grade(r188,a),registration_grade(r189,_G132632),registration_grade(r190,_G132637),registration_grade(r191,_G132642),registration_grade(r192,b),registration_grade(r193,c),registration_grade(r194,b),registration_grade(r195,_G132662),registration_grade(r196,_G132667),registration_grade(r197,_G132672),registration_grade(r198,_G132677),registration_grade(r199,b),registration_grade(r200,_G132687),registration_grade(r201,c),registration_grade(r202,a),registration_grade(r203,_G132702),registration_grade(r204,_G132707),registration_grade(r205,_G132712),registration_grade(r206,a),registration_grade(r207,a),registration_grade(r208,_G132727),registration_grade(r209,b),registration_grade(r210,a),registration_grade(r211,d),registration_grade(r212,_G132747),registration_grade(r213,_G132752),registration_grade(r214,_G132757),registration_grade(r215,a),registration_grade(r216,_G132767),registration_grade(r217,_G132772),registration_grade(r218,_G132777),registration_grade(r219,_G132782),registration_grade(r220,_G132787),registration_grade(r221,b),registration_grade(r222,c),registration_grade(r223,_G132802),registration_grade(r224,_G132807),registration_grade(r225,b),registration_grade(r226,d),registration_grade(r227,b),registration_grade(r228,c),registration_grade(r229,b),registration_grade(r230,a),registration_grade(r231,_G132842),registration_grade(r232,_G132847),registration_grade(r233,b),registration_grade(r234,_G132857),registration_grade(r235,c),registration_grade(r236,b),registration_grade(r237,_G132872),registration_grade(r238,d),registration_grade(r239,b),registration_grade(r240,b),registration_grade(r241,_G132892),registration_grade(r242,b),registration_grade(r243,_G132902),registration_grade(r244,b),registration_grade(r245,a),registration_grade(r246,b),registration_grade(r247,_G132922),registration_grade(r248,b),registration_grade(r249,_G132932),registration_grade(r250,a),registration_grade(r251,_G132942),registration_grade(r252,b),registration_grade(r253,_G132952),registration_grade(r254,_G132957),registration_grade(r255,_G132962),registration_grade(r256,_G132967),registration_grade(r257,b),registration_grade(r258,_G132977),registration_grade(r259,a),registration_grade(r260,b),registration_grade(r261,a),registration_grade(r262,_G132997),registration_grade(r263,_G133002),registration_grade(r264,_G133007),registration_grade(r265,a),registration_grade(r266,_G133017),registration_grade(r267,_G133022),registration_grade(r268,c),registration_grade(r269,a),registration_grade(r270,_G133037),registration_grade(r271,_G133042),registration_grade(r272,_G133047),registration_grade(r273,b),registration_grade(r274,c),registration_grade(r275,a),registration_grade(r276,a),registration_grade(r277,_G133072),registration_grade(r278,_G133077),registration_grade(r279,_G133082),registration_grade(r280,_G133087),registration_grade(r281,b),registration_grade(r282,d),registration_grade(r283,_G133102),registration_grade(r284,b),registration_grade(r285,_G133112),registration_grade(r286,_G133117),registration_grade(r287,_G133122),registration_grade(r288,_G133127),registration_grade(r289,_G133132),registration_grade(r290,b),registration_grade(r291,c),registration_grade(r292,_G133147),registration_grade(r293,_G133152),registration_grade(r294,_G133157),registration_grade(r295,a),registration_grade(r296,b),registration_grade(r297,_G133172),registration_grade(r298,a),registration_grade(r299,a),registration_grade(r300,_G133187),registration_grade(r301,b),registration_grade(r302,b),registration_grade(r303,_G133202),registration_grade(r304,a),registration_grade(r305,_G133212),registration_grade(r306,_G133217),registration_grade(r307,_G133222),registration_grade(r308,c),registration_grade(r309,_G133232),registration_grade(r310,a),registration_grade(r311,a),registration_grade(r312,a),registration_grade(r313,_G133252),registration_grade(r314,_G133257),registration_grade(r315,c),registration_grade(r316,_G133267),registration_grade(r317,_G133272),registration_grade(r318,c),registration_grade(r319,c),registration_grade(r320,b),registration_grade(r321,b),registration_grade(r322,_G133297),registration_grade(r323,c),registration_grade(r324,b),registration_grade(r325,b),registration_grade(r326,_G133317),registration_grade(r327,c),registration_grade(r328,b),registration_grade(r329,_G133332),registration_grade(r330,_G133337),registration_grade(r331,_G133342),registration_grade(r332,_G133347),registration_grade(r333,_G133352),registration_grade(r334,_G133357),registration_grade(r335,d),registration_grade(r336,b),registration_grade(r337,b),registration_grade(r338,b),registration_grade(r339,_G133382),registration_grade(r340,_G133387),registration_grade(r341,_G133392),registration_grade(r342,_G133397),registration_grade(r343,a),registration_grade(r344,c),registration_grade(r345,_G133412),registration_grade(r346,b),registration_grade(r347,_G133422),registration_grade(r348,a),registration_grade(r349,a),registration_grade(r350,b),registration_grade(r351,b),registration_grade(r352,_G133447),registration_grade(r353,_G133452),registration_grade(r354,_G133457),registration_grade(r355,_G133462),registration_grade(r356,b),registration_grade(r357,b),registration_grade(r358,_G133477),registration_grade(r359,a),registration_grade(r360,_G133487),registration_grade(r361,_G133492),registration_grade(r362,c),registration_grade(r363,_G133502),registration_grade(r364,b),registration_grade(r365,_G133512),registration_grade(r366,b),registration_grade(r367,_G133522),registration_grade(r368,a),registration_grade(r369,c),registration_grade(r370,b),registration_grade(r371,_G133542),registration_grade(r372,_G133547),registration_grade(r373,_G133552),registration_grade(r374,b),registration_grade(r375,b),registration_grade(r376,a),registration_grade(r377,a),registration_grade(r378,a),registration_grade(r379,_G133582),registration_grade(r380,_G133587),registration_grade(r381,c),registration_grade(r382,_G133597),registration_grade(r383,_G133602),registration_grade(r384,b),registration_grade(r385,_G133612),registration_grade(r386,d),registration_grade(r387,_G133622),registration_grade(r388,_G133627),registration_grade(r389,a),registration_grade(r390,_G133637),registration_grade(r391,_G133642),registration_grade(r392,_G133647),registration_grade(r393,b),registration_grade(r394,c),registration_grade(r395,b),registration_grade(r396,_G133667),registration_grade(r397,a),registration_grade(r398,_G133677),registration_grade(r399,_G133682),registration_grade(r400,_G133687),registration_grade(r401,c),registration_grade(r402,_G133697),registration_grade(r403,_G133702),registration_grade(r404,a),registration_grade(r405,_G133712),registration_grade(r406,_G133717),registration_grade(r407,_G133722),registration_grade(r408,a),registration_grade(r409,a),registration_grade(r410,b),registration_grade(r411,b),registration_grade(r412,_G133747),registration_grade(r413,a),registration_grade(r414,_G133757),registration_grade(r415,_G133762),registration_grade(r416,_G133767),registration_grade(r417,_G133772),registration_grade(r418,a),registration_grade(r419,a),registration_grade(r420,a),registration_grade(r421,c),registration_grade(r422,b),registration_grade(r423,_G133802),registration_grade(r424,a),registration_grade(r425,b),registration_grade(r426,c),registration_grade(r427,c),registration_grade(r428,_G133827),registration_grade(r429,c),registration_grade(r430,_G133837),registration_grade(r431,_G133842),registration_grade(r432,c),registration_grade(r433,_G133852),registration_grade(r434,a),registration_grade(r435,_G133862),registration_grade(r436,_G133867),registration_grade(r437,c),registration_grade(r438,b),registration_grade(r439,_G133882),registration_grade(r440,c),registration_grade(r441,a),registration_grade(r442,c),registration_grade(r443,_G133902),registration_grade(r444,_G133907),registration_grade(r445,_G133912),registration_grade(r446,_G133917),registration_grade(r447,d),registration_grade(r448,_G133927),registration_grade(r449,b),registration_grade(r450,_G133937),registration_grade(r451,_G133942),registration_grade(r452,b),registration_grade(r453,_G133952),registration_grade(r454,_G133957),registration_grade(r455,_G133962),registration_grade(r456,c),registration_grade(r457,_G133972),registration_grade(r458,_G133977),registration_grade(r459,_G133982),registration_grade(r460,_G133987),registration_grade(r461,_G133992),registration_grade(r462,a),registration_grade(r463,d),registration_grade(r464,a),registration_grade(r465,_G134012),registration_grade(r466,_G134017),registration_grade(r467,b),registration_grade(r468,_G134027),registration_grade(r469,_G134032),registration_grade(r470,_G134037),registration_grade(r471,_G134042),registration_grade(r472,a),registration_grade(r473,c),registration_grade(r474,b),registration_grade(r475,_G134062),registration_grade(r476,_G134067),registration_grade(r477,b),registration_grade(r478,a),registration_grade(r479,b),registration_grade(r480,a),registration_grade(r481,_G134092),registration_grade(r482,b),registration_grade(r483,a),registration_grade(r484,_G134107),registration_grade(r485,_G134112),registration_grade(r486,_G134117),registration_grade(r487,_G134122),registration_grade(r488,a),registration_grade(r489,_G134132),registration_grade(r490,_G134137),registration_grade(r491,c),registration_grade(r492,b),registration_grade(r493,a),registration_grade(r494,_G134157),registration_grade(r495,_G134162),registration_grade(r496,_G134167),registration_grade(r497,c),registration_grade(r498,_G134177),registration_grade(r499,c),registration_grade(r500,b),registration_grade(r501,_G134192),registration_grade(r502,a),registration_grade(r503,_G134202),registration_grade(r504,_G134207),registration_grade(r505,_G134212),registration_grade(r506,c),registration_grade(r507,a),registration_grade(r508,_G134227),registration_grade(r509,_G134232),registration_grade(r510,_G134237),registration_grade(r511,_G134242),registration_grade(r512,b),registration_grade(r513,_G134252),registration_grade(r514,_G134257),registration_grade(r515,c),registration_grade(r516,_G134267),registration_grade(r517,_G134272),registration_grade(r518,_G134277),registration_grade(r519,a),registration_grade(r520,b),registration_grade(r521,a),registration_grade(r522,b),registration_grade(r523,_G134302),registration_grade(r524,b),registration_grade(r525,c),registration_grade(r526,c),registration_grade(r527,c),registration_grade(r528,a),registration_grade(r529,_G134332),registration_grade(r530,a),registration_grade(r531,_G134342),registration_grade(r532,a),registration_grade(r533,_G134352),registration_grade(r534,b),registration_grade(r535,c),registration_grade(r536,a),registration_grade(r537,_G134372),registration_grade(r538,_G134377),registration_grade(r539,_G134382),registration_grade(r540,_G134387),registration_grade(r541,c),registration_grade(r542,a),registration_grade(r543,a),registration_grade(r544,b),registration_grade(r545,a),registration_grade(r546,b),registration_grade(r547,_G134422),registration_grade(r548,c),registration_grade(r549,_G134432),registration_grade(r550,a),registration_grade(r551,_G134442),registration_grade(r552,c),registration_grade(r553,_G134452),registration_grade(r554,b),registration_grade(r555,_G134462),registration_grade(r556,_G134467),registration_grade(r557,_G134472),registration_grade(r558,_G134477),registration_grade(r559,b),registration_grade(r560,_G134487),registration_grade(r561,a),registration_grade(r562,_G134497),registration_grade(r563,_G134502),registration_grade(r564,_G134507),registration_grade(r565,d),registration_grade(r566,c),registration_grade(r567,a),registration_grade(r568,a),registration_grade(r569,_G134532),registration_grade(r570,_G134537),registration_grade(r571,_G134542),registration_grade(r572,b),registration_grade(r573,a),registration_grade(r574,_G134557),registration_grade(r575,a),registration_grade(r576,_G134567),registration_grade(r577,_G134572),registration_grade(r578,b),registration_grade(r579,a),registration_grade(r580,_G134587),registration_grade(r581,_G134592),registration_grade(r582,_G134597),registration_grade(r583,_G134602),registration_grade(r584,a),registration_grade(r585,c),registration_grade(r586,b),registration_grade(r587,_G134622),registration_grade(r588,_G134627),registration_grade(r589,c),registration_grade(r590,_G134637),registration_grade(r591,c),registration_grade(r592,b),registration_grade(r593,_G134652),registration_grade(r594,c),registration_grade(r595,b),registration_grade(r596,_G134667),registration_grade(r597,_G134672),registration_grade(r598,a),registration_grade(r599,_G134682),registration_grade(r600,a),registration_grade(r601,b),registration_grade(r602,_G134697),registration_grade(r603,d),registration_grade(r604,_G134707),registration_grade(r605,a),registration_grade(r606,_G134717),registration_grade(r607,_G134722),registration_grade(r608,a),registration_grade(r609,b),registration_grade(r610,_G134737),registration_grade(r611,_G134742),registration_grade(r612,c),registration_grade(r613,_G134752),registration_grade(r614,_G134757),registration_grade(r615,b),registration_grade(r616,_G134767),registration_grade(r617,a),registration_grade(r618,_G134777),registration_grade(r619,_G134782),registration_grade(r620,a),registration_grade(r621,_G134792),registration_grade(r622,b),registration_grade(r623,_G134802),registration_grade(r624,a),registration_grade(r625,_G134812),registration_grade(r626,a),registration_grade(r627,_G134822),registration_grade(r628,a),registration_grade(r629,_G134832),registration_grade(r630,_G134837),registration_grade(r631,_G134842),registration_grade(r632,a),registration_grade(r633,_G134852),registration_grade(r634,b),registration_grade(r635,_G134862),registration_grade(r636,d),registration_grade(r637,c),registration_grade(r638,a),registration_grade(r639,b),registration_grade(r640,_G134887),registration_grade(r641,_G134892),registration_grade(r642,c),registration_grade(r643,_G134902),registration_grade(r644,_G134907),registration_grade(r645,_G134912),registration_grade(r646,_G134917),registration_grade(r647,b),registration_grade(r648,a),registration_grade(r649,_G134932),registration_grade(r650,c),registration_grade(r651,b),registration_grade(r652,b),registration_grade(r653,_G134952),registration_grade(r654,b),registration_grade(r655,a),registration_grade(r656,_G134967),registration_grade(r657,a),registration_grade(r658,a),registration_grade(r659,a),registration_grade(r660,a),registration_grade(r661,c),registration_grade(r662,_G134997),registration_grade(r663,a),registration_grade(r664,_G135007),registration_grade(r665,a),registration_grade(r666,b),registration_grade(r667,_G135022),registration_grade(r668,d),registration_grade(r669,b),registration_grade(r670,a),registration_grade(r671,_G135042),registration_grade(r672,c),registration_grade(r673,a),registration_grade(r674,_G135057),registration_grade(r675,_G135062),registration_grade(r676,a),registration_grade(r677,a),registration_grade(r678,a),registration_grade(r679,a),registration_grade(r680,_G135087),registration_grade(r681,_G135092),registration_grade(r682,_G135097),registration_grade(r683,b),registration_grade(r684,_G135107),registration_grade(r685,_G135112),registration_grade(r686,b),registration_grade(r687,a),registration_grade(r688,c),registration_grade(r689,_G135132),registration_grade(r690,a),registration_grade(r691,_G135142),registration_grade(r692,_G135147),registration_grade(r693,b),registration_grade(r694,_G135157),registration_grade(r695,_G135162),registration_grade(r696,a),registration_grade(r697,_G135172),registration_grade(r698,_G135177),registration_grade(r699,_G135182),registration_grade(r700,a),registration_grade(r701,_G135192),registration_grade(r702,a),registration_grade(r703,_G135202),registration_grade(r704,c),registration_grade(r705,b),registration_grade(r706,_G135217),registration_grade(r707,a),registration_grade(r708,b),registration_grade(r709,_G135232),registration_grade(r710,_G135237),registration_grade(r711,b),registration_grade(r712,_G135247),registration_grade(r713,a),registration_grade(r714,_G135257),registration_grade(r715,a),registration_grade(r716,a),registration_grade(r717,a),registration_grade(r718,a),registration_grade(r719,_G135282),registration_grade(r720,_G135287),registration_grade(r721,_G135292),registration_grade(r722,_G135297),registration_grade(r723,_G135302),registration_grade(r724,_G135307),registration_grade(r725,c),registration_grade(r726,a),registration_grade(r727,_G135322),registration_grade(r728,b),registration_grade(r729,_G135332),registration_grade(r730,_G135337),registration_grade(r731,_G135342),registration_grade(r732,a),registration_grade(r733,a),registration_grade(r734,b),registration_grade(r735,_G135362),registration_grade(r736,a),registration_grade(r737,_G135372),registration_grade(r738,_G135377),registration_grade(r739,a),registration_grade(r740,_G135387),registration_grade(r741,_G135392),registration_grade(r742,_G135397),registration_grade(r743,_G135402),registration_grade(r744,a),registration_grade(r745,b),registration_grade(r746,_G135417),registration_grade(r747,_G135422),registration_grade(r748,b),registration_grade(r749,c),registration_grade(r750,_G135437),registration_grade(r751,c),registration_grade(r752,_G135447),registration_grade(r753,c),registration_grade(r754,_G135457),registration_grade(r755,c),registration_grade(r756,_G135467),registration_grade(r757,_G135472),registration_grade(r758,b),registration_grade(r759,_G135482),registration_grade(r760,_G135487),registration_grade(r761,a),registration_grade(r762,_G135497),registration_grade(r763,a),registration_grade(r764,a),registration_grade(r765,a),registration_grade(r766,_G135517),registration_grade(r767,c),registration_grade(r768,_G135527),registration_grade(r769,_G135532),registration_grade(r770,b),registration_grade(r771,_G135542),registration_grade(r772,a),registration_grade(r773,b),registration_grade(r774,b),registration_grade(r775,a),registration_grade(r776,_G135567),registration_grade(r777,c),registration_grade(r778,c),registration_grade(r779,b),registration_grade(r780,a),registration_grade(r781,_G135592),registration_grade(r782,a),registration_grade(r783,_G135602),registration_grade(r784,_G135607),registration_grade(r785,_G135612),registration_grade(r786,c),registration_grade(r787,a),registration_grade(r788,_G135627),registration_grade(r789,_G135632),registration_grade(r790,b),registration_grade(r791,b),registration_grade(r792,_G135647),registration_grade(r793,_G135652),registration_grade(r794,_G135657),registration_grade(r795,_G135662),registration_grade(r796,_G135667),registration_grade(r797,a),registration_grade(r798,_G135677),registration_grade(r799,_G135682),registration_grade(r800,_G135687),registration_grade(r801,b),registration_grade(r802,_G135697),registration_grade(r803,b),registration_grade(r804,_G135707),registration_grade(r805,_G135712),registration_grade(r806,_G135717),registration_grade(r807,a),registration_grade(r808,_G135727),registration_grade(r809,_G135732),registration_grade(r810,_G135737),registration_grade(r811,d),registration_grade(r812,c),registration_grade(r813,_G135752),registration_grade(r814,c),registration_grade(r815,_G135762),registration_grade(r816,_G135767),registration_grade(r817,a),registration_grade(r818,_G135777),registration_grade(r819,b),registration_grade(r820,d),registration_grade(r821,b),registration_grade(r822,_G135797),registration_grade(r823,a),registration_grade(r824,_G135807),registration_grade(r825,b),registration_grade(r826,b),registration_grade(r827,_G135822),registration_grade(r828,_G135827),registration_grade(r829,b),registration_grade(r830,_G135837),registration_grade(r831,_G135842),registration_grade(r832,b),registration_grade(r833,b),registration_grade(r834,_G135857),registration_grade(r835,a),registration_grade(r836,a),registration_grade(r837,c),registration_grade(r838,_G135877),registration_grade(r839,b),registration_grade(r840,b),registration_grade(r841,a),registration_grade(r842,a),registration_grade(r843,b),registration_grade(r844,_G135907),registration_grade(r845,c),registration_grade(r846,b),registration_grade(r847,b),registration_grade(r848,_G135927),registration_grade(r849,_G135932),registration_grade(r850,_G135937),registration_grade(r851,_G135942),registration_grade(r852,_G135947),registration_grade(r853,_G135952),registration_grade(r854,_G135957),registration_grade(r855,_G135962),registration_grade(r856,_G135967),student_intelligence(s0,l),student_intelligence(s1,_G135977),student_intelligence(s2,_G135982),student_intelligence(s3,h),student_intelligence(s4,h),student_intelligence(s5,h),student_intelligence(s6,m),student_intelligence(s7,h),student_intelligence(s8,h),student_intelligence(s9,_G136017),student_intelligence(s10,m),student_intelligence(s11,_G136027),student_intelligence(s12,h),student_intelligence(s13,h),student_intelligence(s14,_G136042),student_intelligence(s15,_G136047),student_intelligence(s16,_G136052),student_intelligence(s17,m),student_intelligence(s18,m),student_intelligence(s19,_G136067),student_intelligence(s20,m),student_intelligence(s21,_G136077),student_intelligence(s22,h),student_intelligence(s23,_G136087),student_intelligence(s24,_G136092),student_intelligence(s25,h),student_intelligence(s26,_G136102),student_intelligence(s27,m),student_intelligence(s28,m),student_intelligence(s29,_G136117),student_intelligence(s30,h),student_intelligence(s31,m),student_intelligence(s32,m),student_intelligence(s33,_G136137),student_intelligence(s34,l),student_intelligence(s35,m),student_intelligence(s36,l),student_intelligence(s37,_G136157),student_intelligence(s38,_G136162),student_intelligence(s39,h),student_intelligence(s40,h),student_intelligence(s41,m),student_intelligence(s42,_G136182),student_intelligence(s43,_G136187),student_intelligence(s44,_G136192),student_intelligence(s45,_G136197),student_intelligence(s46,l),student_intelligence(s47,h),student_intelligence(s48,_G136212),student_intelligence(s49,_G136217),student_intelligence(s50,_G136222),student_intelligence(s51,_G136227),student_intelligence(s52,_G136232),student_intelligence(s53,m),student_intelligence(s54,_G136242),student_intelligence(s55,h),student_intelligence(s56,l),student_intelligence(s57,_G136257),student_intelligence(s58,h),student_intelligence(s59,_G136267),student_intelligence(s60,m),student_intelligence(s61,h),student_intelligence(s62,_G136282),student_intelligence(s63,_G136287),student_intelligence(s64,l),student_intelligence(s65,_G136297),student_intelligence(s66,h),student_intelligence(s67,m),student_intelligence(s68,_G136312),student_intelligence(s69,_G136317),student_intelligence(s70,_G136322),student_intelligence(s71,m),student_intelligence(s72,_G136332),student_intelligence(s73,_G136337),student_intelligence(s74,_G136342),student_intelligence(s75,h),student_intelligence(s76,h),student_intelligence(s77,h),student_intelligence(s78,_G136362),student_intelligence(s79,m),student_intelligence(s80,_G136372),student_intelligence(s81,_G136377),student_intelligence(s82,_G136382),student_intelligence(s83,_G136387),student_intelligence(s84,_G136392),student_intelligence(s85,_G136397),student_intelligence(s86,_G136402),student_intelligence(s87,h),student_intelligence(s88,h),student_intelligence(s89,_G136417),student_intelligence(s90,h),student_intelligence(s91,_G136427),student_intelligence(s92,h),student_intelligence(s93,_G136437),student_intelligence(s94,_G136442),student_intelligence(s95,_G136447),student_intelligence(s96,_G136452),student_intelligence(s97,_G136457),student_intelligence(s98,_G136462),student_intelligence(s99,l),student_intelligence(s100,h),student_intelligence(s101,_G136477),student_intelligence(s102,m),student_intelligence(s103,h),student_intelligence(s104,l),student_intelligence(s105,m),student_intelligence(s106,_G136502),student_intelligence(s107,l),student_intelligence(s108,m),student_intelligence(s109,_G136517),student_intelligence(s110,m),student_intelligence(s111,h),student_intelligence(s112,m),student_intelligence(s113,h),student_intelligence(s114,_G136542),student_intelligence(s115,h),student_intelligence(s116,_G136552),student_intelligence(s117,m),student_intelligence(s118,_G136562),student_intelligence(s119,h),student_intelligence(s120,h),student_intelligence(s121,_G136577),student_intelligence(s122,m),student_intelligence(s123,_G136587),student_intelligence(s124,h),student_intelligence(s125,_G136597),student_intelligence(s126,m),student_intelligence(s127,m),student_intelligence(s128,_G136612),student_intelligence(s129,h),student_intelligence(s130,_G136622),student_intelligence(s131,h),student_intelligence(s132,_G136632),student_intelligence(s133,_G136637),student_intelligence(s134,h),student_intelligence(s135,_G136647),student_intelligence(s136,m),student_intelligence(s137,m),student_intelligence(s138,l),student_intelligence(s139,h),student_intelligence(s140,_G136672),student_intelligence(s141,_G136677),student_intelligence(s142,_G136682),student_intelligence(s143,_G136687),student_intelligence(s144,h),student_intelligence(s145,h),student_intelligence(s146,m),student_intelligence(s147,m),student_intelligence(s148,_G136712),student_intelligence(s149,_G136717),student_intelligence(s150,l),student_intelligence(s151,h),student_intelligence(s152,h),student_intelligence(s153,_G136737),student_intelligence(s154,_G136742),student_intelligence(s155,_G136747),student_intelligence(s156,m),student_intelligence(s157,m),student_intelligence(s158,h),student_intelligence(s159,_G136767),student_intelligence(s160,_G136772),student_intelligence(s161,_G136777),student_intelligence(s162,h),student_intelligence(s163,m),student_intelligence(s164,_G136792),student_intelligence(s165,m),student_intelligence(s166,m),student_intelligence(s167,_G136807),student_intelligence(s168,_G136812),student_intelligence(s169,_G136817),student_intelligence(s170,_G136822),student_intelligence(s171,m),student_intelligence(s172,_G136832),student_intelligence(s173,h),student_intelligence(s174,h),student_intelligence(s175,_G136847),student_intelligence(s176,_G136852),student_intelligence(s177,m),student_intelligence(s178,_G136862),student_intelligence(s179,m),student_intelligence(s180,m),student_intelligence(s181,h),student_intelligence(s182,m),student_intelligence(s183,h),student_intelligence(s184,_G136892),student_intelligence(s185,m),student_intelligence(s186,m),student_intelligence(s187,m),student_intelligence(s188,_G136912),student_intelligence(s189,m),student_intelligence(s190,h),student_intelligence(s191,l),student_intelligence(s192,_G136932),student_intelligence(s193,m),student_intelligence(s194,m),student_intelligence(s195,_G136947),student_intelligence(s196,h),student_intelligence(s197,_G136957),student_intelligence(s198,h),student_intelligence(s199,m),student_intelligence(s200,h),student_intelligence(s201,_G136977),student_intelligence(s202,h),student_intelligence(s203,m),student_intelligence(s204,h),student_intelligence(s205,_G136997),student_intelligence(s206,_G137002),student_intelligence(s207,h),student_intelligence(s208,_G137012),student_intelligence(s209,h),student_intelligence(s210,_G137022),student_intelligence(s211,_G137027),student_intelligence(s212,m),student_intelligence(s213,h),student_intelligence(s214,h),student_intelligence(s215,_G137047),student_intelligence(s216,h),student_intelligence(s217,_G137057),student_intelligence(s218,h),student_intelligence(s219,_G137067),student_intelligence(s220,_G137072),student_intelligence(s221,h),student_intelligence(s222,_G137082),student_intelligence(s223,_G137087),student_intelligence(s224,l),student_intelligence(s225,l),student_intelligence(s226,m),student_intelligence(s227,_G137107),student_intelligence(s228,h),student_intelligence(s229,_G137117),student_intelligence(s230,_G137122),student_intelligence(s231,_G137127),student_intelligence(s232,m),student_intelligence(s233,_G137137),student_intelligence(s234,_G137142),student_intelligence(s235,_G137147),student_intelligence(s236,_G137152),student_intelligence(s237,h),student_intelligence(s238,h),student_intelligence(s239,h),student_intelligence(s240,_G137172),student_intelligence(s241,_G137177),student_intelligence(s242,l),student_intelligence(s243,_G137187),student_intelligence(s244,_G137192),student_intelligence(s245,l),student_intelligence(s246,_G137202),student_intelligence(s247,h),student_intelligence(s248,m),student_intelligence(s249,_G137217),student_intelligence(s250,m),student_intelligence(s251,_G137227),student_intelligence(s252,_G137232),student_intelligence(s253,m),student_intelligence(s254,_G137242),student_intelligence(s255,m),course_difficulty(c0,_G137252),course_difficulty(c1,m),course_difficulty(c2,_G137262),course_difficulty(c3,_G137267),course_difficulty(c4,_G137272),course_difficulty(c5,l),course_difficulty(c6,m),course_difficulty(c7,h),course_difficulty(c8,h),course_difficulty(c9,_G137297),course_difficulty(c10,m),course_difficulty(c11,_G137307),course_difficulty(c12,m),course_difficulty(c13,_G137317),course_difficulty(c14,m),course_difficulty(c15,_G137327),course_difficulty(c16,l),course_difficulty(c17,h),course_difficulty(c18,_G137342),course_difficulty(c19,l),course_difficulty(c20,_G137352),course_difficulty(c21,_G137357),course_difficulty(c22,_G137362),course_difficulty(c23,_G137367),course_difficulty(c24,_G137372),course_difficulty(c25,m),course_difficulty(c26,_G137382),course_difficulty(c27,_G137387),course_difficulty(c28,m),course_difficulty(c29,_G137397),course_difficulty(c30,_G137402),course_difficulty(c31,m),course_difficulty(c32,l),course_difficulty(c33,m),course_difficulty(c34,_G137422),course_difficulty(c35,_G137427),course_difficulty(c36,h),course_difficulty(c37,m),course_difficulty(c38,m),course_difficulty(c39,_G137447),course_difficulty(c40,h),course_difficulty(c41,_G137457),course_difficulty(c42,_G137462),course_difficulty(c43,m),course_difficulty(c44,m),course_difficulty(c45,_G137477),course_difficulty(c46,m),course_difficulty(c47,_G137487),course_difficulty(c48,m),course_difficulty(c49,l),course_difficulty(c50,_G137502),course_difficulty(c51,h),course_difficulty(c52,_G137512),course_difficulty(c53,_G137517),course_difficulty(c54,_G137522),course_difficulty(c55,h),course_difficulty(c56,_G137532),course_difficulty(c57,_G137537),course_difficulty(c58,_G137542),course_difficulty(c59,m),course_difficulty(c60,_G137552),course_difficulty(c61,m),course_difficulty(c62,l),course_difficulty(c63,_G137567),registration_satisfaction(r0,_G137572),registration_satisfaction(r1,l),registration_satisfaction(r2,_G137582),registration_satisfaction(r3,_G137587),registration_satisfaction(r4,h),registration_satisfaction(r5,h),registration_satisfaction(r6,_G137602),registration_satisfaction(r7,h),registration_satisfaction(r8,_G137612),registration_satisfaction(r9,h),registration_satisfaction(r10,_G137622),registration_satisfaction(r11,_G137627),registration_satisfaction(r12,_G137632),registration_satisfaction(r13,h),registration_satisfaction(r14,m),registration_satisfaction(r15,h),registration_satisfaction(r16,h),registration_satisfaction(r17,l),registration_satisfaction(r18,l),registration_satisfaction(r19,_G137667),registration_satisfaction(r20,_G137672),registration_satisfaction(r21,_G137677),registration_satisfaction(r22,h),registration_satisfaction(r23,_G137687),registration_satisfaction(r24,_G137692),registration_satisfaction(r25,_G137697),registration_satisfaction(r26,_G137702),registration_satisfaction(r27,_G137707),registration_satisfaction(r28,h),registration_satisfaction(r29,_G137717),registration_satisfaction(r30,l),registration_satisfaction(r31,_G137727),registration_satisfaction(r32,_G137732),registration_satisfaction(r33,h),registration_satisfaction(r34,_G137742),registration_satisfaction(r35,h),registration_satisfaction(r36,m),registration_satisfaction(r37,h),registration_satisfaction(r38,_G137762),registration_satisfaction(r39,h),registration_satisfaction(r40,_G137772),registration_satisfaction(r41,_G137777),registration_satisfaction(r42,_G137782),registration_satisfaction(r43,h),registration_satisfaction(r44,_G137792),registration_satisfaction(r45,h),registration_satisfaction(r46,m),registration_satisfaction(r47,_G137807),registration_satisfaction(r48,_G137812),registration_satisfaction(r49,h),registration_satisfaction(r50,_G137822),registration_satisfaction(r51,_G137827),registration_satisfaction(r52,h),registration_satisfaction(r53,_G137837),registration_satisfaction(r54,h),registration_satisfaction(r55,h),registration_satisfaction(r56,_G137852),registration_satisfaction(r57,h),registration_satisfaction(r58,_G137862),registration_satisfaction(r59,_G137867),registration_satisfaction(r60,h),registration_satisfaction(r61,h),registration_satisfaction(r62,h),registration_satisfaction(r63,h),registration_satisfaction(r64,h),registration_satisfaction(r65,h),registration_satisfaction(r66,h),registration_satisfaction(r67,_G137907),registration_satisfaction(r68,h),registration_satisfaction(r69,m),registration_satisfaction(r70,_G137922),registration_satisfaction(r71,_G137927),registration_satisfaction(r72,_G137932),registration_satisfaction(r73,h),registration_satisfaction(r74,h),registration_satisfaction(r75,h),registration_satisfaction(r76,_G137952),registration_satisfaction(r77,_G137957),registration_satisfaction(r78,m),registration_satisfaction(r79,h),registration_satisfaction(r80,h),registration_satisfaction(r81,h),registration_satisfaction(r82,l),registration_satisfaction(r83,_G137987),registration_satisfaction(r84,m),registration_satisfaction(r85,h),registration_satisfaction(r86,_G138002),registration_satisfaction(r87,_G138007),registration_satisfaction(r88,h),registration_satisfaction(r89,_G138017),registration_satisfaction(r90,_G138022),registration_satisfaction(r91,h),registration_satisfaction(r92,_G138032),registration_satisfaction(r93,_G138037),registration_satisfaction(r94,l),registration_satisfaction(r95,_G138047),registration_satisfaction(r96,h),registration_satisfaction(r97,_G138057),registration_satisfaction(r98,h),registration_satisfaction(r99,h),registration_satisfaction(r100,_G138072),registration_satisfaction(r101,_G138077),registration_satisfaction(r102,h),registration_satisfaction(r103,h),registration_satisfaction(r104,h),registration_satisfaction(r105,_G138097),registration_satisfaction(r106,_G138102),registration_satisfaction(r107,l),registration_satisfaction(r108,l),registration_satisfaction(r109,h),registration_satisfaction(r110,_G138122),registration_satisfaction(r111,h),registration_satisfaction(r112,_G138132),registration_satisfaction(r113,_G138137),registration_satisfaction(r114,m),registration_satisfaction(r115,_G138147),registration_satisfaction(r116,h),registration_satisfaction(r117,_G138157),registration_satisfaction(r118,h),registration_satisfaction(r119,h),registration_satisfaction(r120,l),registration_satisfaction(r121,_G138177),registration_satisfaction(r122,_G138182),registration_satisfaction(r123,l),registration_satisfaction(r124,_G138192),registration_satisfaction(r125,m),registration_satisfaction(r126,h),registration_satisfaction(r127,h),registration_satisfaction(r128,h),registration_satisfaction(r129,h),registration_satisfaction(r130,h),registration_satisfaction(r131,_G138227),registration_satisfaction(r132,m),registration_satisfaction(r133,_G138237),registration_satisfaction(r134,m),registration_satisfaction(r135,_G138247),registration_satisfaction(r136,h),registration_satisfaction(r137,h),registration_satisfaction(r138,h),registration_satisfaction(r139,_G138267),registration_satisfaction(r140,h),registration_satisfaction(r141,_G138277),registration_satisfaction(r142,h),registration_satisfaction(r143,h),registration_satisfaction(r144,h),registration_satisfaction(r145,l),registration_satisfaction(r146,_G138302),registration_satisfaction(r147,l),registration_satisfaction(r148,m),registration_satisfaction(r149,h),registration_satisfaction(r150,_G138322),registration_satisfaction(r151,_G138327),registration_satisfaction(r152,h),registration_satisfaction(r153,_G138337),registration_satisfaction(r154,_G138342),registration_satisfaction(r155,m),registration_satisfaction(r156,h),registration_satisfaction(r157,_G138357),registration_satisfaction(r158,l),registration_satisfaction(r159,m),registration_satisfaction(r160,h),registration_satisfaction(r161,_G138377),registration_satisfaction(r162,m),registration_satisfaction(r163,_G138387),registration_satisfaction(r164,m),registration_satisfaction(r165,m),registration_satisfaction(r166,l),registration_satisfaction(r167,_G138407),registration_satisfaction(r168,h),registration_satisfaction(r169,h),registration_satisfaction(r170,_G138422),registration_satisfaction(r171,_G138427),registration_satisfaction(r172,h),registration_satisfaction(r173,_G138437),registration_satisfaction(r174,_G138442),registration_satisfaction(r175,_G138447),registration_satisfaction(r176,h),registration_satisfaction(r177,h),registration_satisfaction(r178,h),registration_satisfaction(r179,l),registration_satisfaction(r180,_G138472),registration_satisfaction(r181,_G138477),registration_satisfaction(r182,_G138482),registration_satisfaction(r183,_G138487),registration_satisfaction(r184,_G138492),registration_satisfaction(r185,_G138497),registration_satisfaction(r186,_G138502),registration_satisfaction(r187,h),registration_satisfaction(r188,m),registration_satisfaction(r189,_G138517),registration_satisfaction(r190,h),registration_satisfaction(r191,h),registration_satisfaction(r192,m),registration_satisfaction(r193,h),registration_satisfaction(r194,_G138542),registration_satisfaction(r195,_G138547),registration_satisfaction(r196,_G138552),registration_satisfaction(r197,h),registration_satisfaction(r198,h),registration_satisfaction(r199,h),registration_satisfaction(r200,_G138572),registration_satisfaction(r201,h),registration_satisfaction(r202,_G138582),registration_satisfaction(r203,_G138587),registration_satisfaction(r204,_G138592),registration_satisfaction(r205,_G138597),registration_satisfaction(r206,h),registration_satisfaction(r207,h),registration_satisfaction(r208,h),registration_satisfaction(r209,h),registration_satisfaction(r210,_G138622),registration_satisfaction(r211,_G138627),registration_satisfaction(r212,h),registration_satisfaction(r213,_G138637),registration_satisfaction(r214,_G138642),registration_satisfaction(r215,h),registration_satisfaction(r216,h),registration_satisfaction(r217,h),registration_satisfaction(r218,m),registration_satisfaction(r219,h),registration_satisfaction(r220,h),registration_satisfaction(r221,_G138677),registration_satisfaction(r222,_G138682),registration_satisfaction(r223,h),registration_satisfaction(r224,h),registration_satisfaction(r225,_G138697),registration_satisfaction(r226,_G138702),registration_satisfaction(r227,h),registration_satisfaction(r228,_G138712),registration_satisfaction(r229,l),registration_satisfaction(r230,h),registration_satisfaction(r231,_G138727),registration_satisfaction(r232,h),registration_satisfaction(r233,m),registration_satisfaction(r234,_G138742),registration_satisfaction(r235,h),registration_satisfaction(r236,_G138752),registration_satisfaction(r237,_G138757),registration_satisfaction(r238,m),registration_satisfaction(r239,m),registration_satisfaction(r240,h),registration_satisfaction(r241,h),registration_satisfaction(r242,m),registration_satisfaction(r243,_G138787),registration_satisfaction(r244,_G138792),registration_satisfaction(r245,_G138797),registration_satisfaction(r246,h),registration_satisfaction(r247,_G138807),registration_satisfaction(r248,_G138812),registration_satisfaction(r249,h),registration_satisfaction(r250,h),registration_satisfaction(r251,h),registration_satisfaction(r252,h),registration_satisfaction(r253,h),registration_satisfaction(r254,h),registration_satisfaction(r255,h),registration_satisfaction(r256,_G138852),registration_satisfaction(r257,m),registration_satisfaction(r258,h),registration_satisfaction(r259,_G138867),registration_satisfaction(r260,_G138872),registration_satisfaction(r261,_G138877),registration_satisfaction(r262,h),registration_satisfaction(r263,m),registration_satisfaction(r264,_G138892),registration_satisfaction(r265,_G138897),registration_satisfaction(r266,l),registration_satisfaction(r267,_G138907),registration_satisfaction(r268,_G138912),registration_satisfaction(r269,_G138917),registration_satisfaction(r270,l),registration_satisfaction(r271,h),registration_satisfaction(r272,_G138932),registration_satisfaction(r273,h),registration_satisfaction(r274,h),registration_satisfaction(r275,_G138947),registration_satisfaction(r276,_G138952),registration_satisfaction(r277,h),registration_satisfaction(r278,h),registration_satisfaction(r279,_G138967),registration_satisfaction(r280,_G138972),registration_satisfaction(r281,_G138977),registration_satisfaction(r282,_G138982),registration_satisfaction(r283,_G138987),registration_satisfaction(r284,_G138992),registration_satisfaction(r285,m),registration_satisfaction(r286,h),registration_satisfaction(r287,_G139007),registration_satisfaction(r288,_G139012),registration_satisfaction(r289,l),registration_satisfaction(r290,m),registration_satisfaction(r291,h),registration_satisfaction(r292,m),registration_satisfaction(r293,_G139037),registration_satisfaction(r294,h),registration_satisfaction(r295,_G139047),registration_satisfaction(r296,_G139052),registration_satisfaction(r297,_G139057),registration_satisfaction(r298,_G139062),registration_satisfaction(r299,_G139067),registration_satisfaction(r300,l),registration_satisfaction(r301,_G139077),registration_satisfaction(r302,_G139082),registration_satisfaction(r303,h),registration_satisfaction(r304,h),registration_satisfaction(r305,_G139097),registration_satisfaction(r306,_G139102),registration_satisfaction(r307,_G139107),registration_satisfaction(r308,l),registration_satisfaction(r309,m),registration_satisfaction(r310,_G139122),registration_satisfaction(r311,_G139127),registration_satisfaction(r312,h),registration_satisfaction(r313,_G139137),registration_satisfaction(r314,h),registration_satisfaction(r315,h),registration_satisfaction(r316,l),registration_satisfaction(r317,l),registration_satisfaction(r318,_G139162),registration_satisfaction(r319,_G139167),registration_satisfaction(r320,_G139172),registration_satisfaction(r321,l),registration_satisfaction(r322,h),registration_satisfaction(r323,_G139187),registration_satisfaction(r324,h),registration_satisfaction(r325,h),registration_satisfaction(r326,_G139202),registration_satisfaction(r327,m),registration_satisfaction(r328,h),registration_satisfaction(r329,h),registration_satisfaction(r330,_G139222),registration_satisfaction(r331,h),registration_satisfaction(r332,l),registration_satisfaction(r333,_G139237),registration_satisfaction(r334,_G139242),registration_satisfaction(r335,h),registration_satisfaction(r336,_G139252),registration_satisfaction(r337,h),registration_satisfaction(r338,h),registration_satisfaction(r339,_G139267),registration_satisfaction(r340,_G139272),registration_satisfaction(r341,l),registration_satisfaction(r342,h),registration_satisfaction(r343,_G139287),registration_satisfaction(r344,_G139292),registration_satisfaction(r345,m),registration_satisfaction(r346,h),registration_satisfaction(r347,m),registration_satisfaction(r348,_G139312),registration_satisfaction(r349,h),registration_satisfaction(r350,m),registration_satisfaction(r351,_G139327),registration_satisfaction(r352,l),registration_satisfaction(r353,h),registration_satisfaction(r354,h),registration_satisfaction(r355,_G139347),registration_satisfaction(r356,_G139352),registration_satisfaction(r357,m),registration_satisfaction(r358,_G139362),registration_satisfaction(r359,_G139367),registration_satisfaction(r360,_G139372),registration_satisfaction(r361,m),registration_satisfaction(r362,_G139382),registration_satisfaction(r363,_G139387),registration_satisfaction(r364,_G139392),registration_satisfaction(r365,_G139397),registration_satisfaction(r366,h),registration_satisfaction(r367,h),registration_satisfaction(r368,h),registration_satisfaction(r369,h),registration_satisfaction(r370,_G139422),registration_satisfaction(r371,_G139427),registration_satisfaction(r372,h),registration_satisfaction(r373,h),registration_satisfaction(r374,_G139442),registration_satisfaction(r375,h),registration_satisfaction(r376,_G139452),registration_satisfaction(r377,_G139457),registration_satisfaction(r378,_G139462),registration_satisfaction(r379,h),registration_satisfaction(r380,_G139472),registration_satisfaction(r381,_G139477),registration_satisfaction(r382,h),registration_satisfaction(r383,h),registration_satisfaction(r384,_G139492),registration_satisfaction(r385,m),registration_satisfaction(r386,_G139502),registration_satisfaction(r387,h),registration_satisfaction(r388,_G139512),registration_satisfaction(r389,_G139517),registration_satisfaction(r390,_G139522),registration_satisfaction(r391,l),registration_satisfaction(r392,_G139532),registration_satisfaction(r393,_G139537),registration_satisfaction(r394,h),registration_satisfaction(r395,_G139547),registration_satisfaction(r396,h),registration_satisfaction(r397,h),registration_satisfaction(r398,l),registration_satisfaction(r399,h),registration_satisfaction(r400,_G139572),registration_satisfaction(r401,l),registration_satisfaction(r402,h),registration_satisfaction(r403,h),registration_satisfaction(r404,h),registration_satisfaction(r405,h),registration_satisfaction(r406,_G139602),registration_satisfaction(r407,_G139607),registration_satisfaction(r408,_G139612),registration_satisfaction(r409,h),registration_satisfaction(r410,h),registration_satisfaction(r411,_G139627),registration_satisfaction(r412,_G139632),registration_satisfaction(r413,l),registration_satisfaction(r414,h),registration_satisfaction(r415,m),registration_satisfaction(r416,_G139652),registration_satisfaction(r417,h),registration_satisfaction(r418,_G139662),registration_satisfaction(r419,_G139667),registration_satisfaction(r420,_G139672),registration_satisfaction(r421,_G139677),registration_satisfaction(r422,_G139682),registration_satisfaction(r423,_G139687),registration_satisfaction(r424,h),registration_satisfaction(r425,h),registration_satisfaction(r426,_G139702),registration_satisfaction(r427,_G139707),registration_satisfaction(r428,_G139712),registration_satisfaction(r429,_G139717),registration_satisfaction(r430,l),registration_satisfaction(r431,m),registration_satisfaction(r432,_G139732),registration_satisfaction(r433,_G139737),registration_satisfaction(r434,h),registration_satisfaction(r435,m),registration_satisfaction(r436,_G139752),registration_satisfaction(r437,h),registration_satisfaction(r438,l),registration_satisfaction(r439,_G139767),registration_satisfaction(r440,h),registration_satisfaction(r441,h),registration_satisfaction(r442,_G139782),registration_satisfaction(r443,_G139787),registration_satisfaction(r444,_G139792),registration_satisfaction(r445,_G139797),registration_satisfaction(r446,h),registration_satisfaction(r447,m),registration_satisfaction(r448,l),registration_satisfaction(r449,_G139817),registration_satisfaction(r450,h),registration_satisfaction(r451,_G139827),registration_satisfaction(r452,_G139832),registration_satisfaction(r453,_G139837),registration_satisfaction(r454,_G139842),registration_satisfaction(r455,_G139847),registration_satisfaction(r456,h),registration_satisfaction(r457,h),registration_satisfaction(r458,_G139862),registration_satisfaction(r459,_G139867),registration_satisfaction(r460,l),registration_satisfaction(r461,h),registration_satisfaction(r462,h),registration_satisfaction(r463,_G139887),registration_satisfaction(r464,_G139892),registration_satisfaction(r465,_G139897),registration_satisfaction(r466,l),registration_satisfaction(r467,_G139907),registration_satisfaction(r468,_G139912),registration_satisfaction(r469,h),registration_satisfaction(r470,h),registration_satisfaction(r471,_G139927),registration_satisfaction(r472,_G139932),registration_satisfaction(r473,_G139937),registration_satisfaction(r474,_G139942),registration_satisfaction(r475,h),registration_satisfaction(r476,_G139952),registration_satisfaction(r477,_G139957),registration_satisfaction(r478,_G139962),registration_satisfaction(r479,_G139967),registration_satisfaction(r480,_G139972),registration_satisfaction(r481,_G139977),registration_satisfaction(r482,_G139982),registration_satisfaction(r483,h),registration_satisfaction(r484,_G139992),registration_satisfaction(r485,h),registration_satisfaction(r486,h),registration_satisfaction(r487,_G140007),registration_satisfaction(r488,_G140012),registration_satisfaction(r489,m),registration_satisfaction(r490,_G140022),registration_satisfaction(r491,_G140027),registration_satisfaction(r492,h),registration_satisfaction(r493,_G140037),registration_satisfaction(r494,_G140042),registration_satisfaction(r495,h),registration_satisfaction(r496,h),registration_satisfaction(r497,_G140057),registration_satisfaction(r498,_G140062),registration_satisfaction(r499,h),registration_satisfaction(r500,m),registration_satisfaction(r501,h),registration_satisfaction(r502,_G140082),registration_satisfaction(r503,_G140087),registration_satisfaction(r504,m),registration_satisfaction(r505,_G140097),registration_satisfaction(r506,_G140102),registration_satisfaction(r507,_G140107),registration_satisfaction(r508,_G140112),registration_satisfaction(r509,_G140117),registration_satisfaction(r510,_G140122),registration_satisfaction(r511,l),registration_satisfaction(r512,h),registration_satisfaction(r513,h),registration_satisfaction(r514,_G140142),registration_satisfaction(r515,_G140147),registration_satisfaction(r516,_G140152),registration_satisfaction(r517,m),registration_satisfaction(r518,_G140162),registration_satisfaction(r519,h),registration_satisfaction(r520,_G140172),registration_satisfaction(r521,h),registration_satisfaction(r522,h),registration_satisfaction(r523,h),registration_satisfaction(r524,h),registration_satisfaction(r525,_G140197),registration_satisfaction(r526,h),registration_satisfaction(r527,_G140207),registration_satisfaction(r528,_G140212),registration_satisfaction(r529,h),registration_satisfaction(r530,_G140222),registration_satisfaction(r531,_G140227),registration_satisfaction(r532,_G140232),registration_satisfaction(r533,_G140237),registration_satisfaction(r534,l),registration_satisfaction(r535,_G140247),registration_satisfaction(r536,h),registration_satisfaction(r537,h),registration_satisfaction(r538,_G140262),registration_satisfaction(r539,_G140267),registration_satisfaction(r540,_G140272),registration_satisfaction(r541,_G140277),registration_satisfaction(r542,h),registration_satisfaction(r543,h),registration_satisfaction(r544,_G140292),registration_satisfaction(r545,h),registration_satisfaction(r546,_G140302),registration_satisfaction(r547,_G140307),registration_satisfaction(r548,h),registration_satisfaction(r549,_G140317),registration_satisfaction(r550,_G140322),registration_satisfaction(r551,h),registration_satisfaction(r552,m),registration_satisfaction(r553,m),registration_satisfaction(r554,l),registration_satisfaction(r555,m),registration_satisfaction(r556,_G140352),registration_satisfaction(r557,_G140357),registration_satisfaction(r558,_G140362),registration_satisfaction(r559,_G140367),registration_satisfaction(r560,_G140372),registration_satisfaction(r561,_G140377),registration_satisfaction(r562,h),registration_satisfaction(r563,_G140387),registration_satisfaction(r564,h),registration_satisfaction(r565,_G140397),registration_satisfaction(r566,l),registration_satisfaction(r567,_G140407),registration_satisfaction(r568,h),registration_satisfaction(r569,h),registration_satisfaction(r570,h),registration_satisfaction(r571,_G140427),registration_satisfaction(r572,_G140432),registration_satisfaction(r573,_G140437),registration_satisfaction(r574,_G140442),registration_satisfaction(r575,_G140447),registration_satisfaction(r576,_G140452),registration_satisfaction(r577,_G140457),registration_satisfaction(r578,l),registration_satisfaction(r579,h),registration_satisfaction(r580,m),registration_satisfaction(r581,h),registration_satisfaction(r582,h),registration_satisfaction(r583,h),registration_satisfaction(r584,h),registration_satisfaction(r585,h),registration_satisfaction(r586,_G140502),registration_satisfaction(r587,_G140507),registration_satisfaction(r588,_G140512),registration_satisfaction(r589,l),registration_satisfaction(r590,h),registration_satisfaction(r591,_G140527),registration_satisfaction(r592,_G140532),registration_satisfaction(r593,_G140537),registration_satisfaction(r594,l),registration_satisfaction(r595,m),registration_satisfaction(r596,h),registration_satisfaction(r597,_G140557),registration_satisfaction(r598,_G140562),registration_satisfaction(r599,h),registration_satisfaction(r600,_G140572),registration_satisfaction(r601,m),registration_satisfaction(r602,h),registration_satisfaction(r603,_G140587),registration_satisfaction(r604,_G140592),registration_satisfaction(r605,h),registration_satisfaction(r606,h),registration_satisfaction(r607,l),registration_satisfaction(r608,_G140612),registration_satisfaction(r609,h),registration_satisfaction(r610,_G140622),registration_satisfaction(r611,h),registration_satisfaction(r612,l),registration_satisfaction(r613,_G140637),registration_satisfaction(r614,_G140642),registration_satisfaction(r615,_G140647),registration_satisfaction(r616,h),registration_satisfaction(r617,h),registration_satisfaction(r618,h),registration_satisfaction(r619,h),registration_satisfaction(r620,_G140672),registration_satisfaction(r621,_G140677),registration_satisfaction(r622,h),registration_satisfaction(r623,_G140687),registration_satisfaction(r624,_G140692),registration_satisfaction(r625,l),registration_satisfaction(r626,_G140702),registration_satisfaction(r627,h),registration_satisfaction(r628,h),registration_satisfaction(r629,h),registration_satisfaction(r630,h),registration_satisfaction(r631,h),registration_satisfaction(r632,h),registration_satisfaction(r633,_G140737),registration_satisfaction(r634,_G140742),registration_satisfaction(r635,_G140747),registration_satisfaction(r636,_G140752),registration_satisfaction(r637,_G140757),registration_satisfaction(r638,h),registration_satisfaction(r639,_G140767),registration_satisfaction(r640,h),registration_satisfaction(r641,h),registration_satisfaction(r642,_G140782),registration_satisfaction(r643,_G140787),registration_satisfaction(r644,h),registration_satisfaction(r645,_G140797),registration_satisfaction(r646,h),registration_satisfaction(r647,h),registration_satisfaction(r648,_G140812),registration_satisfaction(r649,_G140817),registration_satisfaction(r650,_G140822),registration_satisfaction(r651,_G140827),registration_satisfaction(r652,_G140832),registration_satisfaction(r653,_G140837),registration_satisfaction(r654,h),registration_satisfaction(r655,h),registration_satisfaction(r656,m),registration_satisfaction(r657,_G140857),registration_satisfaction(r658,h),registration_satisfaction(r659,h),registration_satisfaction(r660,h),registration_satisfaction(r661,_G140877),registration_satisfaction(r662,_G140882),registration_satisfaction(r663,h),registration_satisfaction(r664,_G140892),registration_satisfaction(r665,h),registration_satisfaction(r666,l),registration_satisfaction(r667,h),registration_satisfaction(r668,l),registration_satisfaction(r669,_G140917),registration_satisfaction(r670,h),registration_satisfaction(r671,_G140927),registration_satisfaction(r672,_G140932),registration_satisfaction(r673,_G140937),registration_satisfaction(r674,h),registration_satisfaction(r675,l),registration_satisfaction(r676,_G140952),registration_satisfaction(r677,_G140957),registration_satisfaction(r678,h),registration_satisfaction(r679,h),registration_satisfaction(r680,m),registration_satisfaction(r681,_G140977),registration_satisfaction(r682,_G140982),registration_satisfaction(r683,h),registration_satisfaction(r684,_G140992),registration_satisfaction(r685,h),registration_satisfaction(r686,h),registration_satisfaction(r687,_G141007),registration_satisfaction(r688,_G141012),registration_satisfaction(r689,_G141017),registration_satisfaction(r690,h),registration_satisfaction(r691,h),registration_satisfaction(r692,h),registration_satisfaction(r693,_G141037),registration_satisfaction(r694,h),registration_satisfaction(r695,_G141047),registration_satisfaction(r696,_G141052),registration_satisfaction(r697,_G141057),registration_satisfaction(r698,h),registration_satisfaction(r699,h),registration_satisfaction(r700,_G141072),registration_satisfaction(r701,h),registration_satisfaction(r702,_G141082),registration_satisfaction(r703,_G141087),registration_satisfaction(r704,l),registration_satisfaction(r705,_G141097),registration_satisfaction(r706,_G141102),registration_satisfaction(r707,_G141107),registration_satisfaction(r708,_G141112),registration_satisfaction(r709,m),registration_satisfaction(r710,l),registration_satisfaction(r711,h),registration_satisfaction(r712,h),registration_satisfaction(r713,h),registration_satisfaction(r714,m),registration_satisfaction(r715,_G141147),registration_satisfaction(r716,h),registration_satisfaction(r717,h),registration_satisfaction(r718,l),registration_satisfaction(r719,l),registration_satisfaction(r720,_G141172),registration_satisfaction(r721,h),registration_satisfaction(r722,h),registration_satisfaction(r723,h),registration_satisfaction(r724,h),registration_satisfaction(r725,_G141197),registration_satisfaction(r726,h),registration_satisfaction(r727,_G141207),registration_satisfaction(r728,_G141212),registration_satisfaction(r729,_G141217),registration_satisfaction(r730,h),registration_satisfaction(r731,h),registration_satisfaction(r732,_G141232),registration_satisfaction(r733,_G141237),registration_satisfaction(r734,h),registration_satisfaction(r735,h),registration_satisfaction(r736,_G141252),registration_satisfaction(r737,h),registration_satisfaction(r738,_G141262),registration_satisfaction(r739,h),registration_satisfaction(r740,h),registration_satisfaction(r741,h),registration_satisfaction(r742,h),registration_satisfaction(r743,_G141287),registration_satisfaction(r744,_G141292),registration_satisfaction(r745,m),registration_satisfaction(r746,h),registration_satisfaction(r747,_G141307),registration_satisfaction(r748,_G141312),registration_satisfaction(r749,_G141317),registration_satisfaction(r750,_G141322),registration_satisfaction(r751,_G141327),registration_satisfaction(r752,m),registration_satisfaction(r753,m),registration_satisfaction(r754,_G141342),registration_satisfaction(r755,l),registration_satisfaction(r756,_G141352),registration_satisfaction(r757,h),registration_satisfaction(r758,h),registration_satisfaction(r759,l),registration_satisfaction(r760,_G141372),registration_satisfaction(r761,h),registration_satisfaction(r762,_G141382),registration_satisfaction(r763,_G141387),registration_satisfaction(r764,_G141392),registration_satisfaction(r765,h),registration_satisfaction(r766,_G141402),registration_satisfaction(r767,_G141407),registration_satisfaction(r768,_G141412),registration_satisfaction(r769,_G141417),registration_satisfaction(r770,m),registration_satisfaction(r771,_G141427),registration_satisfaction(r772,_G141432),registration_satisfaction(r773,m),registration_satisfaction(r774,h),registration_satisfaction(r775,h),registration_satisfaction(r776,_G141452),registration_satisfaction(r777,_G141457),registration_satisfaction(r778,h),registration_satisfaction(r779,_G141467),registration_satisfaction(r780,h),registration_satisfaction(r781,m),registration_satisfaction(r782,m),registration_satisfaction(r783,m),registration_satisfaction(r784,l),registration_satisfaction(r785,l),registration_satisfaction(r786,h),registration_satisfaction(r787,h),registration_satisfaction(r788,_G141512),registration_satisfaction(r789,_G141517),registration_satisfaction(r790,_G141522),registration_satisfaction(r791,h),registration_satisfaction(r792,_G141532),registration_satisfaction(r793,_G141537),registration_satisfaction(r794,_G141542),registration_satisfaction(r795,_G141547),registration_satisfaction(r796,h),registration_satisfaction(r797,h),registration_satisfaction(r798,m),registration_satisfaction(r799,_G141567),registration_satisfaction(r800,m),registration_satisfaction(r801,h),registration_satisfaction(r802,h),registration_satisfaction(r803,h),registration_satisfaction(r804,_G141592),registration_satisfaction(r805,_G141597),registration_satisfaction(r806,_G141602),registration_satisfaction(r807,_G141607),registration_satisfaction(r808,_G141612),registration_satisfaction(r809,_G141617),registration_satisfaction(r810,h),registration_satisfaction(r811,_G141627),registration_satisfaction(r812,h),registration_satisfaction(r813,m),registration_satisfaction(r814,l),registration_satisfaction(r815,_G141647),registration_satisfaction(r816,_G141652),registration_satisfaction(r817,_G141657),registration_satisfaction(r818,_G141662),registration_satisfaction(r819,h),registration_satisfaction(r820,h),registration_satisfaction(r821,_G141677),registration_satisfaction(r822,m),registration_satisfaction(r823,_G141687),registration_satisfaction(r824,m),registration_satisfaction(r825,l),registration_satisfaction(r826,l),registration_satisfaction(r827,l),registration_satisfaction(r828,_G141712),registration_satisfaction(r829,_G141717),registration_satisfaction(r830,h),registration_satisfaction(r831,_G141727),registration_satisfaction(r832,m),registration_satisfaction(r833,_G141737),registration_satisfaction(r834,_G141742),registration_satisfaction(r835,_G141747),registration_satisfaction(r836,h),registration_satisfaction(r837,h),registration_satisfaction(r838,l),registration_satisfaction(r839,_G141767),registration_satisfaction(r840,m),registration_satisfaction(r841,_G141777),registration_satisfaction(r842,_G141782),registration_satisfaction(r843,h),registration_satisfaction(r844,_G141792),registration_satisfaction(r845,_G141797),registration_satisfaction(r846,_G141802),registration_satisfaction(r847,_G141807),registration_satisfaction(r848,l),registration_satisfaction(r849,_G141817),registration_satisfaction(r850,_G141822),registration_satisfaction(r851,h),registration_satisfaction(r852,h),registration_satisfaction(r853,h),registration_satisfaction(r854,m),registration_satisfaction(r855,_G141847),registration_satisfaction(r856,_G141852)]). + + % % change to 0.0, 0.1, 0.2 to make things simpler/harder % diff --git a/packages/CLPBN/learning/learn_utils.yap b/packages/CLPBN/learning/learn_utils.yap index 9d0523dd9..713f19da4 100644 --- a/packages/CLPBN/learning/learn_utils.yap +++ b/packages/CLPBN/learning/learn_utils.yap @@ -38,7 +38,7 @@ run_all(M:Gs) :- run_all([],_). run_all([G|Gs],M) :- % (G = _:ge(ybr136w,t8,23,-1) -> nb_getval(clpbn_tables, Tab), writeln(Tab) ; true ), - ( call(M:G) -> true ; writeln(bad:M:G), start_low_level_trace, M:G ; halt ), + ( call(M:G) -> true ; throw(bad_call(M:G)) ), run_all(Gs,M). clpbn_vars(Vs,BVars) :- diff --git a/packages/chr b/packages/chr index bf6525f85..b2eb894ce 160000 --- a/packages/chr +++ b/packages/chr @@ -1 +1 @@ -Subproject commit bf6525f85cfcf3c08fff8cf91fb189fe71dc34fd +Subproject commit b2eb894ce3e41925070215f800d6df3a356dc29d diff --git a/packages/meld/examples/pagerank/l4.meld b/packages/meld/examples/pagerank/l4.meld index e727e038c..77d5acc62 100644 --- a/packages/meld/examples/pagerank/l4.meld +++ b/packages/meld/examples/pagerank/l4.meld @@ -1,7 +1,7 @@ %edge(0,1). -%edge(0,4). -%edge(1,4). +edge(0,4). %edge(1,2). -edge(2,3). +edge(1,4). +%edge(2,3). edge(2,4). edge(3,4). diff --git a/packages/meld/examples/pagerank/pagerank.meld b/packages/meld/examples/pagerank/pagerank.meld index 3167955ec..d0c4756e2 100644 --- a/packages/meld/examples/pagerank/pagerank.meld +++ b/packages/meld/examples/pagerank/pagerank.meld @@ -1,6 +1,5 @@ type rank(node, int, float). -type reachable(node, node). type calcRank(node, int, sum float). % type persistent numPages(node, int). type persistent numPages(node, sum int). @@ -8,21 +7,24 @@ type numLinks(node, sum int). type path(node, node). const damping = 0.85. -const num_iterations = 4. +const num_iterations = 100. % extern float to_float(int). % extern float float_abs(float). rank(A, 0, 1.0 / to_float(T)) :- numPages(A,T). rank(A, I, V) :- + numLinks(B,L), numPages(A, Ps), calcRank(A, I, T), - Before = I - 1, - rank(A, Before, VOld), - V = (damping + (1.0 - damping) * T)/to_float(Ps), +% Before = I - 1, +% rank(A, Before, VOld), + V = damping + (1.0 - damping) * T, I =< num_iterations. % //float_abs((damping + (1.0 - damping) * T) - VOld) > 0.001. +calcRank(A, I + 1, 0.0) :- + rank(A, I, _). calcRank(A, I + 1, O / to_float(C)) :- edge(B, A), rank(B, I, O),