1:- module( bims, [bims/0,bims/1,bims_version/2,bims_citation/2] ).    2
    3:- use_module( library(lib) ).    4% :- ensure_loaded( '../src/mcmcms' ).
    5% :- ensure_loaded( '../src/init_lib' ).
    6:- lib( source(bims), homonyms(true) ).    7
    8:- lib(mcmcms/12).    9:- lib(os_unique_by_date/2).   10:- lib(write_terms/2).   11:- lib(n_digits/3).   12:- lib(clean_module/1).   13:- lib(report_triggers/1).   14:- lib(bims_bb_remove/2).   15:- lib(remove_template_duplicates/2).   16:- lib(get_date_time/1).   17:- lib(head_to_spec/2).   18:- lib(ord_only_add_elem/3).  % needed on ad_expand
   19:- lib(to_list/2).   20
   21:- lib(end(bims)).   22% :- lib_pack_end( bims ).

Bims- Bayesian inference over model structures.

Introduction

Bims (Bayesian inference over model structures) implements MCMC learning over statistical models defined in the Dlp (Distributional logic programming) probabilistic language.

Bims is released under GPL2, or Artistic 2.0

Currently there are 2 model spaces supported:

Additional model spaces can be easily implemented by defining new likelihood plug-ins and programming appropriate priors.

Examples provided

Carts examples

?- bims( [] ).
?- bims( [data(carts),models(carts),likelihood(carts)] ).

The above are two equivalent ways to run the Carts example provided.

This runs 3 chains each of length 100 on the default Carts data using the default likelihood. The default dataset is the breast cancer Winsconsin (BCW) data from the machine learning repository. There are 2 categories, 9 variables and 683 data points in this dataset. You can view the data with

?- edit( pack(bims/data/carts) ).

The default likelihood is an implementation of the classification likelihood function presented in: H Chipman, E George, and R McCulloch. Bayesian CART model search (with discussion). J. of the American Statistical Association, 93:935–960, 1998.

Bns examples

?- bims( [models(bns)] ).
?- bims( [data(bns),models(bns),likelihood(bns)] ).

The above are two equivalent ways to run the Bns example provided.

This runs 3 chains each of length 100 on the default bns data using default likelihood. The dataset is a sampled dataset from the ASIA network and it comprises of 8 variables and 2295 datapoints. You can view the data with

?- edit( pack(bims/data/bns) ).

The default BN likelihood is an instance of the BDeu metric for scoring BN structures.

W. L. Buntine. Theory refinement of Bayesian networks. In Bruce D’Ambrosio, Philippe Smets, and Piero Bonissone, editors, Proceedings of the Seventh Annual Conference on Uncertainty in Artificial Intelligence (UAI–1991), pages 52–60, 1991

David Heckerman, Dan Geiger, and David M. Chickering. Learning Bayesian networks: The combination of knowledge and statistical data. Machine Learning, 20(3):197–243, 1995.

Learning models from new datasets

An easy way to run Bims on your data is to create a new directory and within that sub-directory data/ copy your data there and pass options data/1 to the basename of the data file.

For example,

?- bims( data(mydata) ).

Learning new statistical models.

By defining a new likelihood function and new priors the system can be used on new statistical models.

Pack info

author
- Nicos Angelopoulos, http://stoics.org.uk/~nicos
- James Cussens (University of York), http://cs.york.ac.uk/~jc
version
- 2.0.0 2017/2/21
- 2.2.0 2017/4/18
See also
- http://stoics.org.uk/~nicos/sware/bims
license
- MIT */
To be done
- bims_default(-Def).
- test on Windows (and Mac ?)
  118bims_defaults( ArgsPrv, [    
  119                chains(3), 
  120                report([]),
  121                results_dir(Dir),
  122                iterations(100),
  123                tempered([]),
  124                seeds(1),
  125                progress_percentage(10),
  126                progress_stub('.'),
  127                DefModelT,
  128                prior(ModelSingular),
  129                likelihood(Model),
  130                data(Model),
  131                backtrack(uc),
  132                top_goal(ModelSingular),
  133                debug(true)
  134        ] ) :-
  135               to_list( ArgsPrv, Args ),
  136               ( (memberchk(results_dir(ArgsDir),Args),ground(ArgsDir)) ->
  137                    make_directory(ArgsDir)
  138                    ;
  139                    true
  140               ),
  141               DefModel = carts,
  142               DefModelT = models(DefModel),
  143               append( Args, [DefModelT], Partial ),
  144               memberchk( models(Model), Partial ),
  145               atom_singular( Model, ModelSingular ),
  146               bims_args_results_dir( Args, Dir ).
 bims
 bims(+File)
bims(+Opts)
Run a number of MCMC runs for a single prior defined by a Distributional Logic Program (DLP).

If the argument (File) corresponds to an existing file, then it is taken to be a settings file. Each argument should be a fact correspond to a known option. For example

chains(3).
iterations(100).
seeds([1,2,3]).

If the argument (Opts) does not correspond to a file is take to be a list of option terms.

The simplest way to use the software is to make a new directory and run some MCMC chains. The default call,

?- bims().    % equivelant to ?- bims([]).

runs a 3 chains (R=3, below) 100 iterations (I=100) MCMC simulation. The models learnt are classifications trees (carts) based on the default prior and the data are the BCW dataset. The above call is equivelant to:

?- bims([models(carts)]).

To run a toy BN learning example run

?- bims( [models(bns)] ).

This runs 3 chains on some synthetic data of the 8-nodal Asia BN.

To get familiar on how to run bims on private data, make a new directory, create a subdirecory data and copy file bims(data/asia.pl) to data/test_local.pl.

?- bims( [data(test_local)] ).

Opts

chains(R=3)
number of chains or runs. Each chain is identified by N in 1...R.
iterations(I=100)
number of iterations per run. Strictly speaking this is iterations - 1. That is: I is the number of models in each chain produced.
models(Models=carts)
type of the models in the chain. An alternative type of model type is bns.
debug(Dbg=true)
If Dbg==true, run debug(bims) to get debuging messages. If Dbg==false, nodebug(bims) is called.
seeds(Seeds=1)
hash seeds for each run (1-1000), if length of Seeds is less than R, additional items added consequtively from last value. So for instance, seeds(1) when chains(3) is given expands to seeds([1,2,3]).
likelihood(Lk=Model)
likelihood to use, default depends on Model chosen (system provided models, have a nameshake default likelihood, for example carts likelihood is the default likelihood for carts models)
data(Data=Model)
a term that indicates the data for the runs. The precise way of loading and calls depend on Lk (the likelihood function) via the hook model_data_load/2, and what the prior (see option top_goal(Top)) expects. In general the dependency is with the likelihood, with the prior expected to be compatible with what the likelihood dictates in terms of data. In the likelihoods provided, Data is the stem of a filename that is loaded in memory. The file is looked for in Dir/Data[.pl] where Dir is looked for in [./data,bims(Model/data/)].
top_goal(Top=Model)
the top goal for running the MCMC simulations. Should be the partial call corresponding to a predicate defined in Prior, as completed by adding the model as the last argument.
prior(Prior=Model)
a file defining the prior DLP. Each model space has a default nameshake prior. The prior file is looked for in dlps and bims(dlps).
backtrack(Backtract=uc)
backtracking strategy (fix me: add details)
tempered(Tempered=[])
hot chains (fixme: add details) - this is an advanced feature undocumented for now
results_dir(Rdir=res-Dstamp)
results directory. If absent default is used. If present but a variable the default is used and returned as the instantiation to this variable. The directory should not exist prior to the call. The default method uses a time stamp to provide uniqueness. (fixme: add prefix(Pfx) recognition)
report(These)
where These is a listable set of reportable tokens (should match 1st argument of known_reportable_term/2). =[all|_] or all is expanded to reporting all known reportable terms.
progress_percentage(Pc=10)
the percentage at which to report progress of all runs (>100 or non numbers for no progress reporting)
progress_stub(Stub = .)
the stub marking progress

All file name based options: Lk, Data, Prior or Rdir, are passed through absolute_file_name/2.

The predicate generates one results directory (Rdir) and files recording information about each run (R) are placed in Rdir.

*/

  243bims :- bims( [] ).
  244
  245bims( ArgsPrv ) :-
  246    to_list( ArgsPrv, Args ),
  247    bims_defaults( Args, Defs ),
  248    append( Args, Defs, Opts ),
  249    debug( bims, 'Bims options: ~w', [Opts] ),
  250    bims_option_debug( Opts, DbgRestore ),
  251    memberchk( results_dir(ResDPrv), Opts ),
  252    absolute_file_name( ResDPrv, ResD ),
  253    debug( bims, 'Results directory: ~w', ResD ),
  254    memberchk( chains(Runs), Opts ),
  255    bims_option_seeds( Opts, Seeds ),
  256    remove_template_duplicates( Opts, UnqOpts ),
  257    number_codes( Runs, Rcodes ),
  258    length( Rcodes, RcLen ),
  259    n_digits( RcLen, 0, Zero ),
  260    atomic_list_concat( [Zero,'opts.pl'], '-', BoptsB ),
  261    directory_file_path( ResD, BoptsB, BroF ),
  262    bims_write_options( BroF, UnqOpts ),
  263    % fixme: likel
  264    % likelihood(Lk=Model)
  265    % model(Mdl), 
  266    PersOpts = [ models(Model), prior(Dlp), likelihood(Lkl), 
  267                 data(Data), top_goal(Goal),
  268               report(These)
  269               ],
  270    maplist( list_element(Opts), PersOpts ),
  271    report_triggers( These ),
  272    bims_ensure_likelihood_loaded( Model, Lkl, AbsLkl ),
  273    bims_ensure_data_loaded( Model, Lkl, Data, AbsData ),
  274    bims_locate_prior_file( Model, Dlp, AbsDlp ),
  275    bims_write_abs_options( BroF, abs(AbsLkl,AbsData,AbsDlp) ),
  276    bims_runs( Runs, 1, RcLen, Model, AbsDlp, Seeds, ResD, Goal, Opts ),
  277    get_date_time( Now ),
  278    write_terms( BroF, finished_at(Now), mode(append) ),
  279    bims_option_debug_set( DbgRestore ).
  280
  281bims_runs( 0, _I, _Dgs, _Mdl, _, _Seelds, _ResD, _Goal, _Opts ) :-
  282    !,
  283    debug( bims, 'Finished all runs', [] ).
  284bims_runs( R, I, Dgs, Mdl, Dlp, [Seed|Seeds], ResD, Goal, Opts ) :-
  285    copy_term( Goal, TopG ),
  286    % * Out, *Stats, Kernel, ModelType, Prior, PB, Repeats, Data, HotChainsIds, *Seed, SGl
  287    % Out = chain_output( 01-chain.pl ), Stats= 01_stats.txt
  288    debug( bims, 'Run: ~d', I ),
  289    n_digits( Dgs, I, Iat ),
  290    bims_out_file( ResD, Iat, chain, pl, Chain ),
  291    bims_out_file( ResD, Iat, stats, pl, Stats ),
  292    bims_out_file( ResD, Iat, report, pl, Rep ), % fixme: nicer name ?
  293    MCopts = [ backtrack(BckT), iterations(Its), tempered(Hot), 
  294               progress_percentage(Pc), progress_stub(Stub) 
  295            ],
  296    maplist( list_element(Opts), MCopts ), %fixme: allow lists
  297    bims_progress_reporter( Its, Pc, Stub ),
  298    bims_backtrack_term( BckT, Bck, P ),
  299    mcmcms( Chain, Stats, Rep, Bck, Mdl, Dlp, P, Its, true, Hot, Seed, TopG ),
  300    !, % fixme: do some cleaning
  301    J is I + 1,
  302    Q is R - 1,
  303    bims_runs( Q, J, Dgs, Mdl, Dlp, Seeds, ResD, Goal, Opts ).
 bims_version(-Vers, -Date)
Version Mj:Mn:Fx, and release date date(Y,M,D).
version
- 2:2:0

*/

See also
- doc/Releases.txt for more detail on change log
  313bims_version( 2:2:0, date(2017,4,18) ).
  314
  315% version( 1:0:0, date(2014,12,15) ).
  316% version( 2:0:0, date(2017,2,21) ). % IJAR paper
  317% version( 2:1:0, date(2017,2,21) ). % pack lib
  318% version( 2:2:0, date(2017,2,21) ). % web-doc, de-git
 bims_citation(-Atom, -Bibterm)
Succeeds once for each publication related to this library. Atom is the atom representation suitable for printing while Bibterm is a bibtex(Type,Key,Pairs) term of the same publication. Produces all related publications on backtracking.

?- bims_citation( A, G ), write( A ) nl.

Distributional Logic Programming for Bayesian Knowledge Representation.

Nicos Angelopoulos and James Cussens.

International Journal of Approximate Reasoning (IJAR).

Volume 80, January 2017, pages 52-66.

*/

  339bims_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  340    Atom = 'Distributional Logic Programming for Bayesian Knowledge Representation. 
  341Nicos Angelopoulos and James Cussens. 
  342International Journal of Approximate Reasoning (IJAR).
  343Volume 80, January 2017, pages 52-66.',
  344    Type = article,
  345    Key  = 'AngelopoulosN_CussensJ_2017',
  346    Pairs = [
  347               author = 'Nicos Angelopoulos and James Cussens',
  348               title  = 'Distributional Logic Programming for Bayesian Knowledge',
  349               journal= 'International Journal of Approximate Reasoning',
  350               year   = 2017,
  351               month  = 'January',
  352               volume = 80,
  353               pages  = '52-66',
  354               url    = 'http://www.sciencedirect.com/science/article/pii/S0888613X16301232'
  355     ].
  356bims_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  357    Atom  = 'Bayesian learning of Bayesian Networks with informative priors.
  358Nicos Angelopoulos and James Cussens (2008).
  359Special issue on BN learning. Annals of Mathematics and Artificial Intelligence (AMAI) 54(1-3), 53-98.',
  360    Type  = article,
  361    Key   = 'AngelopoulosN_Cussens_2008',
  362    Pairs = [
  363               author = 'Nicos Angelopoulos and James Cussens',
  364               title  = 'Bayesian learning of Bayesian Networks with informative priors.',
  365               year   = '2008',
  366               journal= 'Special issue on BN learning. Annals of Mathematics and Artificial Intelligence (AMAI)',
  367               volume = '54',
  368               issue  = '1-3',
  369               pages  = '53-98',
  370               url    = 'http://dx.doi.org/10.1007/s10472-009-9133-x'
  371           ].
  372bims_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  373    Atom    = 'Exploiting Informative Priors for Bayesian Classification and Regression Trees.
  374Nicos Angelopoulos and James Cussens (2005)
  375In 19th International Joint Conference on Artificial Intelligence (IJCAI-05), 641-646, Edinburgh, UK, August 2005.',
  376    Type    = inproceedings,
  377    Key     = 'AngelopoulosN_Cussens_2005',
  378    Pairs   = [
  379                title   = 'Exploiting Informative Priors for Bayesian Classification and Regression Trees',
  380                author  = 'Nicos Angelopoulos and James Cussens',
  381                year    = '2005',
  382                inproceedings = 'In 19th International Joint Conference on Artificial Intelligence (IJCAI-05)',
  383                pages   = '641-646',
  384                address = 'Edinburgh, UK',
  385                month   = 'August',
  386                year    = 2005
  387            ].
  388bims_citation( Atom, bibtex(Type,Key,Pairs) ) :-
  389    Atom    = 'Markov chain Monte Carlo using tree-based priors on model structure.
  390Nicos Angelopoulos and James Cussens (2001).
  391In 17th Conference on Uncertainty in Artificial Intelligence (UAI-2001), 16-23, Seattle, USA.',
  392    Type    = inproceedings,
  393    Key     = 'AngelopoulosN_Cussens_2001',
  394    Pairs   = [
  395                title   = 'Markov chain Monte Carlo using tree-based priors on model structure.',
  396                author  = 'Nicos Angelopoulos and James Cussens',
  397                year    = 2001,
  398                proceedings = 'In 17th Conference on Uncertainty in Artificial Intelligence (UAI-2001)',
  399                pages   = '16-23',
  400                address = 'Seattle, USA'
  401            ].
  402
  403bims_lib( Spec ) :-
  404    ( Spec = Fname/_Arity -> true; Spec = Fname ),
  405    ensure_loaded( bims(src/lib/Fname) ).
 bims_option_seeds(+Opts, -Seeds)
Get the seed ids (Sids) to be used with runs from options, Opts. Ensures Sids is at least as long as runs in Opts.
  412bims_option_seeds( Opts, Seeds ) :-
  413    memberchk( chains(Runs), Opts ),
  414    memberchk( seeds(PrvSeedS), Opts ),
  415    to_list( PrvSeedS, PrvSeeds ),
  416    length( PrvSeeds, PrvLen ),
  417    Diff is max( Runs - PrvLen, 0 ),
  418    last( PrvSeeds, Last ),
  419    findall( A, (  between(1,Diff,I),
  420                 A is Last + I
  421                ), As ),
  422    append( PrvSeeds, As, Seeds ).
 bims_option_debug(Opts, -Bef)
Start debugging messages if debug(true) is in Opts. Before indicates the state of bims debugging prior to the call. The values for Before are: false or true.
  430bims_option_debug( Opts, Bef ) :-
  431    memberchk( debug(Dbg), Opts ),
  432    debugging( bims, Bef ),
  433    !,
  434    bims_option_debug_set( Dbg ).
  435
  436bims_option_debug_set( true ) :-
  437    debug( bims ).
  438bims_option_debug_set( false) :-
  439    nodebug( bims ).
 bims_out_file(+ResD, +Iat, +Tkn, +Ext, +File)
Construct a bims output File from a results directory, an iteration atom (Iat) a token (Tkn) and an extension (Ext).
 ?- bims:bims_out_file( dir, '01', chain, pl, File ).
 File = 'dir/01-chain.pl'.
  449bims_out_file( Dir, Iat, Tkn, Ext, File ) :-
  450    atomic_list_concat( [Iat,Tkn], '-', Bstem ),
  451    file_name_extension( Bstem, Ext, Bname ),
  452    directory_file_path( Dir, Bname, File ).
  453
  454bims_ensure_data_loaded( Model, Lkl, DataT, DataF ) :-
  455    DataT =.. [Data|Args],
  456    % generic section
  457    clean_module( data ),
  458    AbsOpts = [file_type(directory),solutions(all)],
  459    findall( BimsDD, absolute_file_name(bims(data),BimsDD,AbsOpts), BimsDDs ),
  460    debug( bims, 'Bims data dirs: ~w', [BimsDDs] ),
  461    member( Dir, [data|BimsDDs] ),
  462    directory_file_path( Dir, Data, Stem ),
  463    file_name_extension( Stem, pl, DataF ),
  464    debug( bims, 'Testing existance of data file: ~w', DataF ),
  465    exists_file( DataF ),
  466    debug( bims, 'Loading data file: ~w', DataF ),
  467    data:load_files( DataF, [silent(true)] ),
  468    % data:ensure_loaded( DataF ),
  469    bims_data_call( Model, Lkl, Args, PrepF, PrepG ),
  470    assert( data:data_file(DataF) ),
  471    assert( data:data_models(Model) ),
  472    assert( data:data_prep_file(PrepF) ),
  473    assert( data:data_prep_goal(PrepG) ),
  474    !.
  475bims_ensure_data_loaded( Model, Lkl, Data, _DataF ) :-
  476    throw( fixme(cannot_load_data_for(Model,Lkl,Data)) ).
  477
  478bims_ensure_likelihood_loaded( Model, Lkl, PlLkl ) :-
  479    Sub = models/Model/lklhoods/Lkl/Lkl,
  480    clean_module( bims_lkl ),
  481    absolute_file_name( bims(Sub), LklStem, [solutions(all)] ),
  482    file_name_extension( LklStem, pl, PlLkl ),
  483    debug( bims, 'Looking for likelihood in file: ~w', PlLkl ),
  484    exists_file( PlLkl ),
  485    debug( bims, 'Loading likelihood from file: ~w', PlLkl ),
  486    % ensure_loaded( bims:PlLkl ),
  487    bims_lkl:load_files( PlLkl, [silent(true),if(true)] ),
  488    !.
  489bims_ensure_likelihood_loaded( Model, Lkl, _ ) :-
  490    throw( fixme(cannot_find_likelihood_for(Lkl,Model)) ).
  491
  492bims_data_call( Model, Lkl, Args, DataMan, GoalCopy ) :-
  493    atom_concat( Lkl, '_data', BaseStem ),
  494    file_name_extension( BaseStem, pl, BaseName ),
  495    Sub = models/Model/lklhoods/Lkl,
  496    AbsOpts = [file_type(directory),solutions(all)],
  497    absolute_file_name( bims(Sub), LklD, AbsOpts ),
  498    directory_file_path( LklD, BaseName, DataMan ),
  499    debug( bims, 'Looking data preparation file in: ~w', DataMan ),
  500    exists_file( DataMan ),
  501    debug( bims, 'Loading data preparation file: ~w', DataMan ),
  502    bims_data:load_files( DataMan, [silent(true),if(true)] ),
  503    Goal =.. [BaseStem,Args],
  504    duplicate_term( Goal, GoalCopy ),
  505    call( bims_data:Goal ).
  506
  507list_element( List, Element ) :-
  508    memberchk( Element, List ).
  509
  510bims_backtrack_term( Term, Bck, P ) :-
  511    functor( Term, Bck, Arity ),
  512    bims_backtrack_arity_term( Arity, Term, P ).
  513    % fixme: add Arity > 1 error
  514
  515bims_backtrack_arity_term( 0, Atom, Atom ).
  516bims_backtrack_arity_term( 1, Term, Arg ) :-
  517    arg( 1, Term, Arg ).
  518
  519bims_locate_prior_file( Model, DlpStem, AbsDlp ) :-
  520    AbsOpts = [file_type(directory),solutions(all)],
  521    absolute_file_name( bims(models/Model/dlps), Bims, AbsOpts ),
  522    member( Dir, ['dlps',Bims] ),
  523    directory_file_path( Dir, DlpStem, DlpPathStem ),
  524    file_name_extension( DlpPathStem, dlp, AbsDlp ),
  525    debug( bims, 'Looking for prior in file: ~w', AbsDlp ),
  526    exists_file( AbsDlp ),
  527    debug( bims, 'Will be using prior in file: ~w', AbsDlp ),
  528    !.
  529bims_locate_prior_file( Model, DlpStem, _AbsDlp ) :-
  530    throw( fixme(cannot_locate_prior(Model,DlpStem)) ).
  531
  532atom_singular( Atom, Singular ) :-
  533    atom_concat( Singular, s, Atom ),
  534    !.
  535atom_singular( Atom, Atom ).
  536
  537bims_args_results_dir( Args, Dir ) :-
  538    memberchk( results_dir(ResDir), Args ),
  539    !,
  540    Dir = ResDir,
  541    bims_args_results_dir_given( ResDir, Args ).
  542bims_args_results_dir( Args, Dir ) :-
  543    bims_args_results_dir_constructed( Args, Dir ).
  544
  545bims_args_results_dir_given( ResDir, _Args ) :-
  546    ground( ResDir ),
  547    !.
  548bims_args_results_dir_given( ResDir, Args ) :-
  549    var( ResDir ),
  550    !,
  551    bims_args_results_dir_constructed( Args, ResDir ).
  552bims_args_results_dir_given( ResDir, _Args ) :-
  553    throw( partially_instantiated_results_dir(ResDir) ).
  554
  555bims_args_results_dir_constructed( Args, ResDir ) :-
  556    ( memberchk(dir_prefix(Pfx),Args) -> true; Pfx = res ),
  557    !,
  558    os_unique_by_date( Pfx, ResDir ).
  559
  560bims_write_abs_options( OptsFile, abs(Lkl,Data,Dlp) ) :-
  561    open( OptsFile, append, Out ),
  562    nl( Out ),
  563    write( Out, '% derived' ), nl( Out ),
  564    Terms = [ likelihood_file(Lkl),
  565              data_file(Data),
  566            prior_file(Dlp)
  567            ],
  568    maplist( mcmcms_write_fact(Out), Terms ),
  569    nl( Out ),
  570    write( Out, '% date/time stamps' ), nl( Out ),
  571    get_date_time( Now ),
  572    mcmcms_write_fact( Out, started_at(Now) ),
  573    close( Out ).
  574
  575bims_progress_reporter( Its, Pc, Stub ) :-
  576    bims_bb_remove( progress, _ ),
  577    number( Pc ), 
  578    0 < Pc, Pc < 100, 
  579    !,
  580    calc_percentiles( Pc, Pc, Its, [HPtl|TPtiles] ),
  581    bims_bb_put( progress, pts(Stub,HPtl,TPtiles) ).
  582bims_progress_reporter( _Its, _Pc, _Stub ).
  583
  584bims_write_options( BroF, UnqOpts ) :-
  585    open( BroF, write, Out ), 
  586    write( Out, '% options' ), nl( Out ),
  587    % write_terms_stream( Out, UnqOpts, [] ),
  588    maplist( mcmcms_write_fact(Out), UnqOpts ),
  589    close( Out ).
  590
  591calc_percentiles( Perc, _Step, _Repeats, Ptiles ) :-
  592    Perc > 100, 
  593    !,
  594    Ptiles = [].
  595calc_percentiles( Perc, Step, Repeats, [F|M] ) :-
  596    F is integer( Perc * Repeats / 100 ),
  597    NxP is Perc + Step,
  598    calc_percentiles( NxP, Step, Repeats, M )