Ńň
)čJc        	   @   s%  d  d k  Z  d  d k Z d  d k Z d  d k Z d  d k l Z l Z l Z d  d k l	 Z	 d   Z
 e d  Z d   Z d   Z d   Z d	   Z d
   Z d   Z d   Z d   Z d f  d     YZ d   Z d   Z e d j o6 e e i  d j o e e i d  n e   n d S(   i˙˙˙˙N(   t   aranget   logt   logn(   t   rv_discretec         C   s   t  |   d t |   S(   Ng      đ?(   t   sumt   len(   t   L(    (    s
   sailing.pyt   mean#   s    c         C   s]   | d j o t |   } n t i t g  } |  D] } | | | d q1 ~  t |    S(   sW   The standard deviation of a set of values.
    Pass in the mean if you already know it.i   N(   t   NoneR   t   matht   sqrtR   R   (   t   valuest   meanvalt   _[1]t   x(    (    s
   sailing.pyt   stddev%   s     c         C   s   t  |   } t |   }  | d d j o |  | d S|  | d d | d d !} y t |  SWn t j
 o t i |  SXd S(   s  Return the middle value, when the values are sorted.
    If there are an odd number of elements, try to average the middle two.
    If they can't be averaged (e.g. they are strings), choose one at random.
    >>> median([10, 100, 11])
    11
    >>> median([1, 2, 3, 4])
    2.5
    i   i   N(   R   t   sortedR   t	   TypeErrort   randomt   choice(   R   t   nt   middle2(    (    s
   sailing.pyt   median-   s    
c         C   s   t  i d |  d  S(   s.   
    Return a random integer from [0, n).
    i    i   (   R   t   randint(   R   (    (    s
   sailing.pyt
   my_randintB   s    c         C   s   |  | d | | d f S(   s˘   
    Returns (x + v[0], y + v[1]).

    EXAMPLES::

        >>> add_vector(0, 0, (0, 1))
        (0, 1)
        >>> add_vector(0, 0, (-2, 1))
        (-2, 1)
    i    i   (    (   R   t   yt   v(    (    s
   sailing.pyt
   add_vectorI   s    c         C   sP   xI |  D]A } t  |  d j o t Sx  | D] } | d j  o t Sq, Wq Wt S(   są  
    Rows must sum to 1 and no entry can be negative.

    EXAMPLE::

        >>> wind_array = [ [0.4, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3],                            [0.4, 0.3, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0],                            [0.0, 0.4, 0.3, 0.3, 0.0, 0.0, 0.0, 0.0],                            [0.0, 0.0, 0.4, 0.3, 0.3, 0.0, 0.0, 0.0],                            [0.0, 0.0, 0.0, 0.4, 0.2, 0.4, 0.0, 0.0],                            [0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.4, 0.0],                            [0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.4],                            [0.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3] ]
        >>> check_probability_matrix(wind_array)
        True
    i   i    (   R   t   Falset   True(   t   PR   R   (    (    s
   sailing.pyt   check_probability_matrixV   s        c         C   s   |  d j p t   |  d j  p t   | d j p t   | d j  p t   t |  |  } | d | j  o | Sd | Sd S(   s  
    Absolute difference in directions.

    EXAMPLES::

        >>> abs_direction_difference(0, 1)
        1
        >>> abs_direction_difference(3, 2)
        1
        >>> abs_direction_difference(3, 5)
        2
        >>> abs_direction_difference(3, 7)
        4
    i    i   N(   t   AssertionErrort   abs(   t   d1t   d2R   (    (    s
   sailing.pyt   abs_direction_differencep   s     c         C   sĂ   |  d j p t   |  d j  p t   | d j p t   | d j  p t   t |  |  } | d j o d S| d j o d S| d j o d S| d j o d	 S| d
 j o d St  d S(   s9  
    The tack of the boat depends on the relative difference of
    the boat's direction and the wind.

    EXAMPLES::

        >>> tack(0, 0)
        'away'
        >>> tack(0, 7)
        'down'
        >>> tack(0, 2)
        'cross'
        >>> tack(0, 3)
        'up'
        >>> tack(0, 4)
        'into'
    i    i   t   awayi   t   downi   t   crossi   t   upi   t   intoN(   R    R$   t
   ValueError(   t   boat_directiont   wind_directiont   d(    (    s
   sailing.pyt   tack   s          c         C   s3   | |  } x | d j  o | d 7} q W| d j S(   sL   
    Relative to the boat, is the wind blowing to the left of the boat?
    i    i   i   i   i   (   i   i   i   (    (   t	   boat_dirnt	   wind_dirnt   w(    (    s
   sailing.pyt   wind_on_leftŽ   s
    
  c         C   sź   |  d j p t   |  d j  p t   |  d j o d S|  d j o d S|  d j o d S|  d j o d S|  d j o d S|  d j o d S|  d	 j o d S|  d
 j o d Sd S(   sÔ   
    The direction 0 is north so we move by (0, 1) in cartesian
    coordinates.

    EXAMPLES::

        >>> direction_vector(0) # north
        (0, 1)
        >>> direction_vector(6) # west
        (-1, 0)
    i    i   i   i   i   i˙˙˙˙i   i   i   i   N(   i    i   (   i   i   (   i   i    (   i   i˙˙˙˙(   i    i˙˙˙˙(   i˙˙˙˙i˙˙˙˙(   i˙˙˙˙i    (   i˙˙˙˙i   (   R    (   R-   (    (    s
   sailing.pyt   direction_vectorź   s$            t   Sailingc           B   s   e  Z d    Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z	 d   Z
 d	   Z d
   Z d   Z d   Z d   Z d   Z RS(   c         C   s¤  d |  _  | |  _ d d d d d d d d g d d d d d d d d g d d d d d d d d g d d d d d d d d g d d d d d d d d g d d d d d d d d g d d d d d d d d g d d d d d d d d g g |  _ | d |  _ | d |  _ h d d 6d	 d
 6d d 6d d 6|  _ g  |  _ xb t t |  i   D]K } t	 t |  i |   |  i | g } |  i i
 t d d d |   qQWd  S(   NgÍĚĚĚĚĚě?gŮ?g333333Ó?g        gÉ?i   i   R(   i   R'   i   R&   R%   t   namet   custmR   (   t   gammat	   lake_sizet
   wind_arrayt   end_xt   end_yt   costst   wind_distributiont   rangeR   R    t   appendR   (   t   selfR8   t   it   vals(    (    s
   sailing.pyt   __init__Ö   s&    		$%	 &c      
   c   s   x t  |  i  D]y } xp t  |  i  D]_ } xV t  d  D]H } x? t  d  D]1 } x( t  d  D] } | | | | | f Vq_ WqL Wq9 Wq& Wq Wd S(   sk   
        Instead of storing the states in a large list/dictionary, we
        provide an iterator.
        i   N(   R>   R8   (   R@   R   R   R-   t   w1t   w2(    (    s
   sailing.pyt   statesň   s         c         C   s$   | d | d f |  i  |  i f j S(   Ni    i   (   R:   R;   (   R@   t   state(    (    s
   sailing.pyt   is_terminal˙   s    c         C   s/   y |  i  | |  Wn t j
 o t SXt S(   N(   t   costt   KeyErrorR   R   (   R@   RG   t   action(    (    s
   sailing.pyt   is_into  s
    c         C   s    t  d  } x3 t o+ t  d  } t | |  d j o Pq q W|  i |  } xH t o@ t  |  i  t  |  i  | | | f } |  i |  p PqT qT W| S(   Ni   R)   (   R   R   R.   t   new_windR8   RH   (   R@   RD   R-   RE   RG   (    (    s
   sailing.pyt   random_state
  s      
 ' 
c         C   sh   | \ } } } } } t  | | t |   \ } } | t |  i  j o | t |  i  j o t St S(   N(   R   R3   R>   R8   R   R   (   R@   RG   RK   R   R   t   _t   x2t   y2(    (    s
   sailing.pyt   stays_in_lake  s
    ,c      	   C   s×   | \ } } } } } t  | | t |   \ } }	 |  i | |  p d  Sd }
 y |
 |  i | |  7}
 Wn t j
 o d  SXxN t d  D]@ } | |	 | | | f } |
 |  i |  i | |  | | 7}
 q W|
 S(   Ni    i   (	   R   R3   RR   R   RI   RJ   R>   R7   t   transition_probability(   R@   t   Vt   st   new_dR   R   RO   RE   RP   RQ   t	   this_costt   w3t   s_new(    (    s
   sailing.pyt   average_cost_of_transition!  s      )c         C   s   | \ } } } } } | \ } }	 }
 } } t  |
  \ } } | | | j o d S|	 | | j o d S| | j o d S|  i | | S(   sĹ  
        What is the probability of moving from state s1 to s2?

        s1 = (x1, y1, _, w1, w2)
        s2 = (x2, y2, d2, w2_2, w3)

        The boat was at (x1, y1) and travelled to (x2, y2). Then it must
        be the case that (x2, y2) = (x1, y1) + direction_vector(d2). If this
        does not hold then the probability is 0.

        If the previous wind direction of s2 does not match the new
        wind direction of s1 then the probability is 0 (so we need 
        w2_2 == w2).

        Finally, the probability of moving from s1 to s2 is just the
        probability of the wind changing from w2=w2_2 to w3, which is 
        stored in the global variable wind_array.

        >>> x1, y1 = 1, 1
        >>> x2, y2 = 2, 1
        >>> d1 = 0
        >>> d2 = 2 # the direction that we just travelled
        >>> w1 = 3
        >>> w2 = 2
        >>> w2_2 = w2

        >>> lake_size = 5

        >>> S = Sailing(lake_size)

        >>> S.transition_probability((x1, y1, d1, w1, w2),                                     (x2, y2, d2, w2_2, 1))
        0.40000000000000002
        >>> S.transition_probability((x1, y1, d1, w1, w2),                                     (x2, y2, d2, w2_2, 0))
        0.0
        i    (   R3   R9   (   R@   t   s1t   s2t   x1t   y1RO   RD   RE   RP   RQ   R#   t   w2_2RX   t   d_vec1t   d_vec2(    (    s
   sailing.pyRS   8  s    '   c         C   s   |  i  | i   S(   s´  
        The wind is currently blowing in direction w and it changes to a
        new direction according to the matrix wind_array, which is encoded
        by general probability distribution in wind_probability_space.

        EXAMPLES::

            >>> lake_size = 5
            >>> S = Sailing(lake_size)
            >>> S.new_wind(0) in range(8)
            True
            >>> S.new_wind(4) in range(8)
            True
        (   R=   t   rvs(   R@   R1   (    (    s
   sailing.pyRM   r  s    c         C   s   | d } |  i  t | |  S(   s+  
        If we are in state s and we decide to travel in direction d, how
        much will this cost? Note that the wind for this new leg is in the 
        last element of s.

        EXAMPLES::

            >>> x1, y1 = 1, 1
            >>> x2, y2 = 2, 1
            >>> d1 = 0
            >>> d2 = 2
            >>> w1 = 3
            >>> w2 = 2
            >>> s = (x1, y1, d1, w1, w2)

            >>> lake_size = 5
            >>> S = Sailing(lake_size)
            >>> S.cost(s, 0)
            3
            >>> S.cost(s, 1)
            2
        i˙˙˙˙(   R<   R.   (   R@   RU   R-   RM   (    (    s
   sailing.pyRI     s    
c         C   sş   | \ } } } } } |  i  |  o d Sd } d }	 xw t d  D]i }
 |  i | | |
  } | d j o qC n | d j o |
 } | }	 qC | |	 j  o |
 } | }	 qC qC W| |	 f S(   s   
        If we are in state s, use the value vector V to work out the
        best direction to travel in and its estimated cost.
        i˙˙˙˙i    i   (   i˙˙˙˙i    N(   RH   R   R>   RZ   (   R@   RU   RT   R   R   R-   RD   RE   t   min_dt
   min_d_costRV   t
   new_d_cost(    (    s
   sailing.pyt   best_action˘  s"       
c      
   C   s  h  } h  } h  } x^ |  i    D]P } d | | <d | | | <d | | <|  i |  o d | | <d | | <q q WxÎ t oĆ t g  } |  i    D] } | t | | | |  q ~  } d G| GHt i i   | | j  o Pn xK |  i    D]= } |  i |  o qń n |  i | |  \ | | <| | <qń W| | } } qv W| }	 t	 |	 i
    t |	  }
 t |	 i
   d |
 } |	 | |
 | f S(   Ni    i
   i˙˙˙˙s)   Top of value_iteration(), max difference:R   (   RF   RH   R   t   maxR!   t   syst   stdoutt   flushRf   R   R   R   R   (   R@   t   epsilont   V1t   V2t   policyRU   R   RA   t   max_diffRT   t   V_avgt   V_stddev(    (    s
   sailing.pyt   value_iterationŔ  s8     


 ?	   $c         C   s#  t  d  } x3 t o+ t  d  } t | |  d j o Pq q W|  i |  } t  |  i  t  |  i  | | | f } d } d } x |  i |  p | | } | | |  i | |  7} t | d | d t |   \ }	 }
 |  i | d  } |	 |
 | | d | f } | |  i	 9} q W| S(   Ni   R)   i    g      đ?i   i˙˙˙˙(
   R   R   R.   RM   R8   RH   RI   R   R3   R7   (   R@   Rn   RD   R-   RE   t   current_stateRW   t   factorRV   RP   RQ   RX   (    (    s
   sailing.pyt   simulateâ  s(      
' 
c         C   so   g  } x1 t  d | d  D] } | i |  i |   q Wt |  t |  } t | d | } | | | f S(   Ni   R   (   R>   R?   Ru   R   R   R   (   R@   Rn   t   nr_simst   simsRA   t   sims_avgt   sims_stddev(    (    s
   sailing.pyt   run_simulations˙  s     c         C   s   |  i  |  o d S|  i | |  } t | d | d t |   \ } } |  i | d  } | | | | d | f } | | f S(   s   
        Use the generative model of S to find the next state given that
        we are in state and take action action.
        i    i   i˙˙˙˙N(   RH   R   RI   R   R3   RM   (   R@   RG   RK   RI   RP   RQ   RX   t	   new_state(    (    s
   sailing.pyt   sample_next_state	  s    &(   t   __name__t
   __module__RC   RF   RH   RL   RN   RR   RZ   RS   RM   RI   Rf   Rr   Ru   Rz   R|   (    (    (    s
   sailing.pyR4   Ő   s   									:				"		
c          C   sA  d }  t  d |   } | i d d  \ } } } } d GHd } d GH| i | |  \ } } }	 Hd |  |  f GHHd	 GHd
 | GHd t | i    GHd | GHHd | GHd
 | GHd t |  GHd |	 GHHd }
 d } xK | i   D]= } | d | d f d j o | d 7} |
 | | 7}
 qŕ qŕ Wd | i | i |
 | f GHd  S(   Ni   R8   Rk   gš?s   Done with value iterationič  s   Running simulations...s   Lake size: %d x %ds   Value iteration:s       Mean cost: %.1fs       Median cost: %.1fs       Standard dev: %.1fs   Simulations (run %d times):g        i    i   s;   Mean cost to sail across lake from (1, 1) to (%d, %d): %.1f(   i   i   (   R4   Rr   Rz   R   R   t   keysR:   R;   (   R8   t   SRT   Rn   Rp   Rq   Rv   Rw   Rx   Ry   t   v_11t
   v_11_countRU   (    (    s
   sailing.pyt   value_iteration_example  s:    					 
c         C   s   t  |   } | i d  \ } } } } d t |   d } t | d  } t i | |  t i | |  t i | |  t i | |  | i   d  S(   Ng{ŽGáz?t   lake_s   .pklt   wb(   R4   Rr   t   strt   opent   picklet   dumpt   close(   R8   R   RT   Rn   Rp   Rq   t   lake_filenamet   output(    (    s
   sailing.pyt   save_optimal_solution>  s    t   __main__i   i   (   R	   R   R   Rh   t   scipyR    R   R   t   scipy.statsR   R   R   R   R   R   R   R   R$   R.   R2   R3   R4   R   R   R}   R   t   argvt   eval(    (    (    s
   sailing.pyt   <module>   s.   							#		˙ E	%	
