class_docstr: This abstract class is used to formalize and manage user interaction with a 
  complex system of equations (related to "constraint satisfaction problems").
  It is often the case that devices must be controlled
  through a large number of free variables, and interactions between these 
  variables make the system difficult to manage and conceptualize as a user
  interface. This class does _not_ attempt to numerically solve the system
  of equations. Rather, it provides a framework for subdividing the system
  into manageable pieces and specifying closed-form solutions to these small 
  pieces.
  
  For an example, see the simple Camera class below.
  
  Theory of operation: Conceptualize the system as 1) a set of variables
  whose values may be either user-specified or automatically generated, and 
  2) a set of functions that define *how* each variable should be generated. 
  When a variable is accessed (as an instance attribute), the solver first
  checks to see if it already has a value (either user-supplied, or cached
  from a previous calculation). If it does not, then the solver calls a 
  method on itself (the method must be named `_variableName`) that will
  either return the calculated value (which usually involves acccessing
  other variables in the system), or raise RuntimeError if it is unable to
  calculate the value (usually because the user has not provided sufficient
  input to fully constrain the system). 
  
  Each method that calculates a variable value may include multiple 
  try/except blocks, so that if one method generates a RuntimeError, it may 
  fall back on others. 
  In this way, the system may be solved by recursively searching the tree of 
  possible relationships between variables. This allows the user flexibility
  in deciding which variables are the most important to specify, while 
  avoiding the apparent combinatorial explosion of calculation pathways
  that must be considered by the developer.
  
  Solved values are cached for efficiency, and automatically cleared when 
  a state change invalidates the cache. The rules for this are simple: any
  time a value is set, it invalidates the cache *unless* the previous value
  was None (which indicates that no other variable has yet requested that 
  value). More complex cache management may be defined in subclasses.
  
  
  Subclasses must define:
  
  1) The *defaultState* class attribute: This is a dict containing a 
     description of the variables in the system--their default values,
     data types, and the ways they can be constrained. The format is::
  
         { name: [value, type, constraint, allowed_constraints], ...}
  
     Where:
       * *value* is the default value. May be None if it has not been specified
         yet.
       * *type* may be float, int, bool, np.ndarray, ...
       * *constraint* may be None, single value, or (min, max)
            * None indicates that the value is not constrained--it may be
              automatically generated if the value is requested.
       * *allowed_constraints* is a string composed of (n)one, (f)ixed, and (r)ange.
     
     Note: do not put mutable objects inside defaultState!
     
  2) For each variable that may be automatically determined, a method must 
     be defined with the name `_variableName`. This method may either return
     the 
class_docstr_tok: ["This","abstract","class","is","used","to","formalize","and","manage","user","interaction","with","a","complex","system","of","equations","(","related","to","``","constraint","satisfaction","problems","''",")",".","It","is","often","the","case","that","devices","must","be","controlled","through","a","large","number","of","free","variables",",","and","interactions","between","these","variables","make","the","system","difficult","to","manage","and","conceptualize","as","a","user","interface",".","This","class","does","_not_","attempt","to","numerically","solve","the","system","of","equations",".","Rather",",","it","provides","a","framework","for","subdividing","the","system","into","manageable","pieces","and","specifying","closed-form","solutions","to","these","small","pieces",".","For","an","example",",","see","the","simple","Camera","class","below",".","Theory","of","operation",":","Conceptualize","the","system","as","1",")","a","set","of","variables","whose","values","may","be","either","user-specified","or","automatically","generated",",","and","2",")","a","set","of","functions","that","define","*","how","*","each","variable","should","be","generated",".","When","a","variable","is","accessed","(","as","an","instance","attribute",")",",","the","solver","first","checks","to","see","if","it","already","has","a","value","(","either","user-supplied",",","or","cached","from","a","previous","calculation",")",".","If","it","does","not",",","then","the","solver","calls","a","method","on","itself","(","the","method","must","be","named","`","_variableName","`",")","that","will","either","return","the","calculated","value","(","which","usually","involves","acccessing","other","variables","in","the","system",")",",","or","raise","RuntimeError","if","it","is","unable","to","calculate","the","value","(","usually","because","the","user","has","not","provided","sufficient","input","to","fully","constrain","the","system",")",".","Each","method","that","calculates","a","variable","value","may","include","multiple","try\/except","blocks",",","so","that","if","one","method","generates","a","RuntimeError",",","it","may","fall","back","on","others",".","In","this","way",",","the","system","may","be","solved","by","recursively","searching","the","tree","of","possible","relationships","between","variables",".","This","allows","the","user","flexibility","in","deciding","which","variables","are","the","most","important","to","specify",",","while","avoiding","the","apparent","combinatorial","explosion","of","calculation","pathways","that","must","be","considered","by","the","developer",".","Solved","values","are","cached","for","efficiency",",","and","automatically","cleared","when","a","state","change","invalidates","the","cache",".","The","rules","for","this","are","simple",":","any","time","a","value","is","set",",","it","invalidates","the","cache","*","unless","*","the","previous","value","was","None","(","which","indicates","that","no","other","variable","has","yet","requested","that","value",")",".","More","complex","cache","management","may","be","defined","in","subclasses",".","Subclasses","must","define",":","1",")","The","*","defaultState","*","class","attribute",":","This","is","a","dict","containing","a","description","of","the","variables","in","the","system","--","their","default","values",",","data","types",",","and","the","ways","they","can","be","constrained",".","The","format","is",":",":","{","name",":","[","value",",","type",",","constraint",",","allowed_constraints","]",",","...","}","Where",":","*","*","value","*","is","the","default","value",".","May","be","None","if","it","has","not","been","specified","yet",".","*","*","type","*","may","be","float",",","int",",","bool",",","np.ndarray",",","...","*","*","constraint","*","may","be","None",",","single","value",",","or","(","min",",","max",")","*","None","indicates","that","the","value","is","not","constrained","--","it","may","be","automatically","generated","if","the","value","is","requested",".","*","*","allowed_constraints","*","is","a","string","composed","of","(","n",")","one",",","(","f",")","ixed",",","and","(","r",")","ange",".","Note",":","do","not","put","mutable","objects","inside","defaultState","!","2",")","For","each","variable","that","may","be","automatically","determined",",","a","method","must","be","defined","with","the","name","`","_variableName","`",".","This","method","may","either","return","the"]
code: def __getattr__(self, name):
      if name in self._vars:
          return self.get(name)
      raise AttributeError(name)
  
imports: import copy
  from collections import OrderedDict
  from math import log2
  import numpy
  from ..None import functions
label_desc: Use image node_id 4 for calling the SystemSolver obj's underlying member method code with example usage: obj.__getattr__(name) and returns: self