
    eE                        d dl Z d dlmZ d dlmZ d dlZddlmZ	  G d de
      Zedk(  r\ G d	 d
e      Z e       Zde_        d e_        de_        de_        d e_        ej)                           eej-                                yy)    N)OrderedDict)log2   )	functionsc                   t    e Zd ZdZ e       Zd Zd Zd Zd Z	d Z
d Zdd	Zd
 Zd Zd Zd Zd Zd Zd Zy)SystemSolvera  
    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 
    c                     t               | j                  d<   t               | j                  d<   | j                          y N_vars_currentGets)r   __dict__setreset)selfs    F/usr/lib/python3/dist-packages/pyqtgraph/parametertree/SystemSolver.py__init__zSystemSolver.__init__N   s+    !,g(+n%

    c                      t        |              }t        j                  | j                  d         |j                  d<   t        j                  | j                  d         |j                  d<   |S r
   )typecopydeepcopyr   )r   syss     r   r   zSystemSolver.copyS   sT    d4jl $dmmG.D EW'+}}T]]>5R'S^$
r   c                     | j                   j                          | j                  D ]!  }| j                  |   dd | j                  |<   # y)zK
        Reset all variables in the solver to their default state.
        N)r   cleardefaultStater   r   ks     r   r   zSystemSolver.resetY   sH     	!"" 	4A --a03DJJqM	4r   c                 V    || j                   v r| j                  |      S t        |      N)r   getAttributeError)r   names     r   __getattr__zSystemSolver.__getattr__a   s'    4::88D>!T""r   c                 \   || j                   v rp|| j                  ||d       yt        |t              r6| j                   |   d   t        j
                  ur| j                  |d|       y| j                  ||d       yt        | |      rt        j                  | ||       yt        |      )a=  
        Set the value of a state variable. 
        If None is given for the value, then the constraint will also be set to None.
        If a tuple is given for a scalar variable, then the tuple is used as a range constraint instead of a value.
        Otherwise, the constraint is set to 'fixed'.
        
        N   fixed)
r   r   
isinstancetuplenpndarrayhasattrobject__setattr__r!   )r   r"   values      r   r-   zSystemSolver.__setattr__f   s     4::}ud+E5)djj.>q.A.StU+ug. tT"""4u5$T**r   c                    || j                   v rt        d|z        | j                   j                  |       	 | j                  |   d   }|>t	        | d|z   d      }|d}n |       }|t        d|z        | j                  ||      }| j                   j                  |       |S # | j                   j                  |       w xY w)z
        Return the value for parameter *name*. 
        
        If the value has not been specified, then attempt to compute it from
        other interacting parameters.
        
        If no value can be determined, then raise RuntimeError.
        z)Cyclic dependency while calculating '%s'.r   N_z Parameter '%s' is not specified.)r   RuntimeErroraddr   getattrr   remove)r   r"   vcfuncs       r   r    zSystemSolver.get}   s     4$$$"#NQU#UVVd#	+

4 #AycDj$7=AA9&'ID'PQQHHT1%$$T* $$T*s   AB( (CNc           	      v   | j                   |   }|d|d   vrt        d|z        ||d<   nm|dk(  rd|d   vrt        d|z        ||d<   nMt        |t              r+d|d   vrt        d	|z        t	        |      dk(  sJ ||d<   n|d
urt        d|z        |d   t
        j                  u r|t        j                  |t              }n#|d   t        t        t        fv r| |d   |      }|d
u r)| j                  ||      st        d|d|d|d         |d   || j                          ||d<   |S )a  
        Set a variable *name* to *value*. The actual set value is returned (in
        some cases, the value may be cast into another type).
        
        If *value* is None, then the value is left to be determined in the 
        future. At any time, the value may be re-assigned arbitrarily unless
        a constraint is given.
        
        If *constraint* is True (the default), then supplying a value that 
        violates a previously specified constraint will raise an exception.
        
        If *constraint* is 'fixed', then the value is set (if provided) and
        the variable will not be updated automatically in the future.

        If *constraint* is a tuple, then the value is constrained to be within the 
        given (min, max). Either constraint may be None to disable 
        it. In some cases, a constraint cannot be satisfied automatically,
        and the user will be forced to resolve the constraint manually.
        
        If *constraint* is None, then any constraints are removed for the variable.
        n   z&Empty constraints not allowed for '%s'r   r&   fz&Fixed constraints not allowed for '%s'rz&Range constraints not allowed for '%s'Tz:constraint must be None, True, 'fixed', or tuple. (got %s)r%   )dtypezSetting z = z violates constraint r   )r   	TypeErrorr'   r(   lenr)   r*   arrayfloatintcheck_constraint
ValueErrorresetUnfixed)r   r"   r.   
constraintvars        r   r   zSystemSolver.set   sv   , jj#a&  H4 OPPCF7"#a&  H4 OPP  CF
E*#a&  H4 OPPz?a'''CFt#X[eeff q6RZZE$5HHU%0EVUE**u/@CF5ME d&;&;D%&HuVYZ[V\]^^ q6
 Ar   c                     | j                   |   d   }||yt        |t              r$|d   d u xs |d   |k  xr |d   d u xs |d   |k\  S ||k(  S )Nr   Tr   r%   )r   r'   r(   )r   r"   r.   cs       r   rB   zSystemSolver.check_constraint   sq    JJtQ9aqTT\2QqTU] 4qTT\2QqTU]5 A:r   c                 x    t               }| j                  j                         D ]  \  }}|d   |d   f||<    |S )zR
        Return a serializable description of the solver's current state.
        r   r   )r   r   itemsr   stater"   rF   s       r   	saveStatezSystemSolver.saveState   sF     ))+ 	+ID#q63q6*E$K	+r   c                     | j                          |j                         D ]  \  }}| j                  ||d   |d            y)zP
        Restore the state of all values and constraints in the solver.
        r   r%   N)r   rJ   r   rK   s       r   restoreStatezSystemSolver.restoreState   s>     	

 	+ID#HHT3q63q6*	+r   c                 ^    | j                   j                         D ]  }|d   dk7  sd|d<    y)ze
        For any variable that does not have a fixed value, reset
        its value to None.
        r   r&   Nr   )r   values)r   rF   s     r   rD   zSystemSolver.resetUnfixed   s5    
 ::$$& 	C1v A	r   c                 >    | j                   D ]  }t        | |        y r   )r   r3   r   s     r   solvezSystemSolver.solve  s     	AD!	r   c                 J   | j                   j                         D ]R  \  }}|d   dk(  sd|d   v s|dd }| j                  |dd       	 | j                  |       ||| j                   |<   c S  y# t        $ r Y nw xY w	 || j                   |<   v# || j                   |<   w xY w)aU  Check whether the system is overconstrained. If so, return the name of
        the first overconstrained parameter.

        Overconstraints occur when any fixed parameter can be successfully computed by the system.
        (Ideally, all parameters are either fixed by the user or constrained by the
        system, but never both).
        r   r&   r8   r9   NF)r   rJ   r   r    r1   )r   r   r5   oldvals       r   checkOverconstraintz SystemSolver.checkOverconstraint  s     ::##% 
	+CAatw3!A$;1D$'+HHQK %+DJJqM
	+  $ $*DJJqMFDJJqMs$   A11	A=:B<A==BB"c           	      0   t               }| j                  j                         D ]  \  }}|d   dk(  s|d   ||<    dj                  |j                         D cg c]  \  }}|d| c}}      }d| j                  j
                  d|dS c c}}w )	Nr   r&   r   z, =< >)r   r   rJ   join	__class____name__)r   rL   r"   rF   r8   r5   s         r   __repr__zSystemSolver.__repr__   s    ))+ 	%ID#1v !!fd	% 		u{{}E!a+EF NN33U;; Fs   B
)NT)r^   
__module____qualname____doc__r   r   r   r   r   r#   r-   r    r   rB   rM   rO   rD   rS   rV   r_    r   r   r   r   
   sY    ?B =L
4#
+.8DL+2<r   r   __main__c                       e Zd ZdZ eddeddgfddeddgfddeddgfddeddgfddedd	gfd
dedd	gfddeddgfg      Zd Zd Z	y)Cameraaf
  
        Consider a simple SLR camera. The variables we will consider that 
        affect the camera's behavior while acquiring a photo are aperture, shutter speed,
        ISO, and flash (of course there are many more, but let's keep the example simple).

        In rare cases, the user wants to manually specify each of these variables and
        no more work needs to be done to take the photo. More often, the user wants to
        specify more interesting constraints like depth of field, overall exposure, 
        or maximum allowed ISO value.

        If we add a simple light meter measurement into this system and an 'exposure'
        variable that indicates the desired exposure (0 is "perfect", -1 is one stop 
        darker, etc), then the system of equations governing the camera behavior would
        have the following variables:

            aperture, shutter, iso, flash, exposure, light meter

        The first four variables are the "outputs" of the system (they directly drive 
        the camera), the last is a constant (the camera itself cannot affect the 
        reading on the light meter), and 'exposure' specifies a desired relationship 
        between other variables in the system.

        So the question is: how can I formalize a system like this as a user interface?
        Typical cameras have a fairly limited approach: provide the user with a list
        of modes, each of which defines a particular set of constraints. For example:

            manual: user provides aperture, shutter, iso, and flash
            aperture priority: user provides aperture and exposure, camera selects
                            iso, shutter, and flash automatically
            shutter priority: user provides shutter and exposure, camera selects
                            iso, aperture, and flash
            program: user specifies exposure, camera selects all other variables
                    automatically
            action: camera selects all variables while attempting to maximize 
                    shutter speed
            portrait: camera selects all variables while attempting to minimize 
                    aperture

        A more general approach might allow the user to provide more explicit 
        constraints on each variable (for example: I want a shutter speed of 1/30 or 
        slower, an ISO no greater than 400, an exposure between -1 and 1, and the 
        smallest aperture possible given all other constraints) and have the camera 
        solve the system of equations, with a warning if no solution is found. This
        is exactly what we will implement in this example class.
        apertureNnfshutterisoflashexposurer:   
lightMeterbalancer8   c                     | j                   }| j                  }| j                  }	 | j                  }d|dz  z  |dz  z  d|z  z  d|z  z  }t	        j
                  |dd      }|S # t        $ r d} w xY w)zY
            Determine aperture automatically under a variety of conditions.
                  @?      Y@r   g       @g      0@)rj   rl   rm   ri   fnclip_scalarr1   )r   rj   explightshaps         r   	_aperturezCamera._aperture  s     ((C--COOE
\\B&M*cDj9Q#XF!u*U^^BT2 I    	s   =A% %A2c                     | j                   }| j                  }| j                  }| j                  }d|z  |dz  z  |dz  z  d|z  z  }t	        |      S )Nrp   rq   rr   r   )rj   rm   ri   rg   r   )r   rj   rv   rw   rx   bals         r   _balancezCamera._balance  sT    ((COOEBB8f.#*=eLC9r   )
r^   r`   ra   rb   r   r@   rA   r   ry   r|   rc   r   r   rf   rf   .  s    ,	\ #$tT23udD12T3d+, tUD$/0
 $tS12 D%s34
 udC01C"$ "H	*	r   rf   d   rq   )r   collectionsr   mathr   numpyr)    r   rs   r,   r   r^   rf   camerarj   rl   rm   ri   rk   rS   printrM   rc   r   r   <module>r      s     #   \<6 \<D	 zn n` XFFJFOFFNFL
LLN	&


w r   