
General principles:

(1) GraphModel & its inheritors are containers for collections of factors (funtions over a few variables each)
(2) Variables are assumed to be X0...Xn, although some may be unused.  When the dimension of Xi is known/not required,
    the index itself can be used instead.
(3) Configurations (x0...xn) can be represented in different ways, depending on the circumstances:
    * A map {0:x0, 1:x1, ...}, with unspecified values of a partial configuration left out
    * An nparray, tuple, or list [x0,x1,...xn], with missing values (if allowed) set to NaN
    * A collection of data X=[xa,xb,xc...] with xa=[xa0,...xan], so that X[i] is the ith data point
      * This can be a list of lists or tuples, or a 2D numpy array
    * We can detect whether a single data point or multiple are specified using try: next(iter(next(iter(X))))
    * Some functions only accept single data (should check & error), others expect multiple, or can take either.
(4) All data are expected to take values 0...d-1, for discrete variables with d states, even e.g. "Ising" models.
(5) "isLog" indicates whether the model consists of log-factors: G(x) = \sum_a g_a(x_a), 
    or exp-factors: F(x) = \sum_a f_a(x_a).  Functions which make use of the joint value (log-likelihood, etc.)
    or multiple factors in combination (e.g., variable elimination) use this in computing their quantities.
    The model representation may be switched using "toLog" and "toExp".
(6) Sampling functions should return config-value pairs:  x,lnq where x \sim q(X) and lnq = log(q(x)).
(7) Training functions take the form "fit_method" for methods that estimate graph structure, and "refit_method"
    for methods that preserve the current factors/cliques and simply update the parameters.
(8) By default, GraphModel makes a copy of each factor during construction.  This is because some functions
    (such as refit or reparameterization inference) may change the values of the factor tables.  If this is not
    desired, "gm = GraphModel(factors, copy=False)" will use references to the factors (useful for memory sharing,
    for example), but set gm.lock = True to indicate that functions should not alter these factors.
    The function "gm.copy()" returns a new copy of the model with non-const factors.
(9) Some functions (conditioning, manual factor additions, etc.) may alter the structure / cliques of the model as
    well. Iterative methods (message passing inference, etc.) can check "gm.sig" to make sure the structure has
    not changed between iterations to ensure validity, and may raise an exception if it does.
    (TODO: add another lock flag for structure; functions should check before altering structure.)









===============================================================================

*** Version that can use torch tensors?
   * Allow for "direct" optimization of various quantities?


*** Data representation !!! 
   * Want x[i] to be data point i?
   * Want to be able to pass lists of tuples, or a single tuple?  (No single tuples?) (Convert to arrays?)
     * If "not 2D" convert before operation?  (Note: some operations can only take single tuples)
   * Also want to be able to access X[:,j] = {x_j for all data}
   * Want consistent with standard torch forms



*** Exact inference
    * Sensitivity analysis?
      * Exp family form: dLogZ/dTheta = E[X]
      * "BN" form: specify p(A=a|E=e) and x=p(Xi=xi|Xpai=xpai) ?
         * all-to-one version requires BN form and bnOrder, and "one" p(A=a|E=e)
         * one-to-all version requires p(Xi=xi|Xpai=xpai); BN can be unnormalized
    * BN specialized functions?  Evidence pruning?
    * CSP specialized functions?


*** Sampling
    * sampling function returns  config, logP = sample( [partial?] )
    * MCMC returns config, logP = sample( startcfg )
    *** Maybe make a generator object? "yield"? 
    * Method to "aggregate" samples? ("Query" object...)  => generic "estimate marginal" f'ns, etc?
      * Useful for repeated / cts improvement inference  (save state)
      * QueryMarginals (list cliques); QueryExpectations (list f'ns); QueryHistory (log all)
    
      * Basic Gibbs (two versions)   
      ** Structured gibbs? Sets to sample; generate conditioned sub-models; VE-sample? (In-place slices: efficient?)
      * MH: any common proposals?
    TODO?
      * Importance sampling (several? WMB, Tree BP, MF?)
      * Annealed IS
      * Estimators? Discriminance sampling?

*** Search
    * Pseudo-tree object
    * Heuristic f'n: takes partial config, returns cost-to-go of internal PTree given config
    * Next variable f'n: given partial config, what are the next vars to condition on?
    * Node priority f'n: when adding node, when should we re-examine?
    * Nodes link to heuristic, priority f'n so they can modify / be dynamic?  PFunc can use heuristic?
    * Search algos:
        * Basic DFS
          * A/O DFS? (Rotating?)
        * Best-First / A*
          * A/O A*? Mem limited A*?



*** Variational
    * Various forms of DD?  (SoftArc done/easy; others?)
    * Basic BP algo?  Fancier (scheduling, etc)?  Region models?
    * NMF done; structured MF? 
    * WMB: 
       * Basic incremental MB: build; msg pass, merge; msg pass, merge; ...
       * Sholeh algorithm?  

??? Iterative algorithms, use yield or other structures to run iterations?
    * Can verify no structural changes, etc;
    * Reparameterization vs message forms
    ** "General" outer loop that checks for timeout, various convergence conditions?  Or make for each algo?


*** Learning
    *CRF representation? (More general factor representations? ?) 
    * EM? Stochastic EM?


*** Structure learning
   * Several Ising methods (clean up)
   * Independence tests
   * Non-ising group lasso, etc.
   * BN stochastic search
   * BN ILP method
   * ...


*** Special models: Ising models (clean?), RBM/CRBM, 

*** Other people's algorithms?
    * Vibhav's: sample, assemble sparse JTree until memory limit, solve
      * Need to "decompose" proposal along graph structure?
    * Maua's: solve preserving lists of factors / configs?
    * Model conversions? Binary, pairwise, etc?

