refined the errors in the os module, translating scheme errors to python errors....
authorStefan Israelsson Tampe <stefan.itampe@gmail.com>
Sun, 2 Sep 2018 17:48:52 +0000 (19:48 +0200)
committerStefan Israelsson Tampe <stefan.itampe@gmail.com>
Sun, 2 Sep 2018 17:48:52 +0000 (19:48 +0200)
modules/language/python/compile.scm
modules/language/python/def.scm
modules/language/python/exceptions.scm
modules/language/python/module/_random.scm
modules/language/python/module/io.scm
modules/language/python/module/os.scm
modules/language/python/module/random.py
modules/language/python/module/threading.scm
modules/language/python/string.scm
modules/oop/pf-objects.scm

index 91c33c1..86b30dc 100644 (file)
         (let ((e (car x)))
           (if (pair? e)
               (let ((ee (car e)))
-                (if (equal? ee 'cons)
+                (if (equal? ee '(@ (guile) cons))
                     (append (lp (list (cadr  e)))
                             (lp (list (caddr e)))
                             (lp (cdr x)))
               (union
                s
                (fold (lambda (x s)
-                       (match x
+                       (match x                         
                          ((#:test (#:power v2 v1 () . _) . _)
                           (if v2
                               (union
 (define lr* (lr `((#:* . ,(mklr (G '*))) (#:/  . ,(mklr (N 'py-/)))
                  (#:% . ,f%)            (#:// . ,(mklr (N 'py-floordiv))))))
 
+(define lr-or (lr `((#:bor . ,(mklr (N 'py-logior))))))
+(define lr-and (lr `((#:band . ,(mklr (N 'py-logand))))))
+(define lr-xor (lr `((#:bxor . ,(mklr (N 'py-logxor))))))
            
 (define-syntax-rule (gen-table x vs (tag code ...) ...)
   (begin
    (list '+ (exp vs x))))
 
  (#:band
-  ((_ . l)
-   (cons (N 'py-logand) (map (g vs exp) l))))
-    
+  (x (lr-and vs x)))
  (#:bxor
-  ((_ . l)
-   (cons (N 'py-logxor) (map (g vs exp) l))))
+  (x (lr-xor vs x)))
  
  (#:bor
-  ((_ . l)
-   (cons (N 'py-logior) (map (g vs exp) l))))
+  (x (lr-or vs x)))
     
  (#:not
   ((_ x)
                     (,(D 'lam) ,aa
                      (,(C 'with-return) ,r
                       ,(mk `(,(G 'let) ,(map (lambda (x) (list x #f)) ls)
-                              (,(C 'with-self) ,c? ,aa
-                               ,(with-fluids ((return r))
-                                   (wth (exp ns code)))))))))))
+                             (,(C 'with-self) ,c? ,aa
+                              ,(with-fluids ((return r))
+                                 (wth (exp ns code)))))))))))
                
                `(set! ,f
                   (,(C 'def-decor) ,decor
                    (,(D 'lam) ,aa
                     (,(C 'with-return) ,r
                      ,(mk `(,(G 'let) ,(map (lambda (x) (list x #f)) ls)
-                             (,(C 'with-self) ,c? ,aa
-                              ,(with-fluids ((return r))
-                                 (wth (exp ns code)))))))))))
+                            (,(C 'with-self) ,c? ,aa
+                             ,(with-fluids ((return r))
+                                (wth (exp ns code)))))))))))
             
            (if y?
                `(set! ,f
                     (,(D 'lam) ,aa
                      (,(C 'with-return) ,r 
                       (,(G 'let) ,(map (lambda (x) (list x #f)) ls)
-                        (,(C 'with-self) ,c? ,aa
-                         ,(with-fluids ((return r))
-                            (mk
-                             (wth (exp ns code)))))))))))
+                       (,(C 'with-self) ,c? ,aa
+                        ,(with-fluids ((return r))
+                           (mk
+                            (wth (exp ns code)))))))))))
                `(set! ,f
                   (,(C 'def-decor) ,decor
                    (,(D 'lam) ,aa
                     (,(C 'with-return) ,r 
                      (,(G 'let) ,(map (lambda (x) (list x #f)) ls)
-                       (,(C 'with-self) ,c? ,aa
-                        ,(with-fluids ((return r))
-                           (wth (exp ns code)))))))))))))))
+                      (,(C 'with-self) ,c? ,aa
+                       ,(with-fluids ((return r))
+                          (wth (exp ns code)))))))))))))))
  
  (#:global
   ((_ . _)
             #:use-module ((guile) #:select
                           (@ @@ pk let* lambda call-with-values case-lambda
                                    set! = * + - < <= > >= / pair?
-                                   syntax-rules let-syntax))
+                                   syntax-rules let-syntax abort-to-prompt))
             #:use-module (language python module python)
             #:use-module ((language python compile) #:select (pks))
             #:use-module (language python exceptions))
                #:final l)))))
   
 (define-syntax qset!
-  (syntax-rules (cons quote)
-    ((_ (cons x y) v)
-     (let ((w v))
-       (qset! x (car w))
-       (qset! y (cdr w))))
-    ((_ '() v) (values))
-    ((_  x  v)
-     (set! x v))))
+  (lambda (x)
+    (syntax-case x ()
+      ((_ (cons x y) v)
+       (equal? (syntax->datum #'cons) '(@ (guile) cons))
+       #'(let ((w v))
+           (qset! x (car w))
+           (qset! y (cdr w))))
+      
+      ((_ '() v)
+       #'(if (not (null? v))
+             (raise (ValueError "too many values to unpack"))))
+      
+      ((_  x  v)
+       #'(set! x v)))))
 
 (define-syntax define-
   (syntax-rules (cons quote)
index b2a8de2..1f527e9 100644 (file)
 
 (define-syntax py-apply  
   (lambda (x)
-    (syntax-case x (*)
-      ((_ f a ... (* x))
-       (and-map (lambda (x) (symbol? (syntax->datum x))) #'(a ...))
-       #'(if (pair? x)
+    (syntax-case x ()
+      ((_ f a ... (op x))
+       (and (syntax-case #'op (*)
+              (* #t)
+              (_ #f))
+            (and-map (lambda (q)
+                       (syntax-case q (* ** =)
+                         ((=  _ _) #f)
+                         ((*  _  ) #f)
+                         ((** _  ) #f)
+                         (_    #t))) #'(a ...)))
+       #'(if (or (null? x) (pair? x))
              (apply f a ... x)
              (apply f a ... (to-list x))))
 
index 915c9ef..8bc812f 100644 (file)
                          ZeroDivisionError ArithmeticError
                          OverflowError RecursionError
                          Warning DeprecationWarning BytesWarning
+                          ResourceWarning
                           UnicodeDecodeError LookupError IndentationError
                           KeyboardInterrupt MemoryError NameError
-                          EOFError UnicodeError))
+                          EOFError UnicodeError
+                          FileExistsError FileNotFoundError IsADirectoryError ))
 
 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
 
@@ -67,7 +69,9 @@
 
 (define StopIteration           'StopIteration)
 (define GeneratorExit           'GeneratorExit)
-
+(define-er FileExistsError      'FileExistsError)
+(define-er FileNotFoundError    'FileNotFoundError)
+(define-er IsADirectoryError    'IsADirectoryError)
 (define-er UnicodeError         'UnicodeError)
 (define-er EOFError             'EOFError)
 (define-er MemoryError          'MemoryError)
 
 (define-wr BytesWarning       'BytesWarning)
 (define-wr DepricationWarning 'DeprecationWarning)
+(define-wr ResourceWarning    'ResourceWarning)
index 74b9492..95ff989 100644 (file)
 (define-module (language python module _random)
   #:use-module (oop pf-objects)
   #:use-module (language python string)
+  #:use-module ((language python module python) #:select (int))
+  #:use-module (language python def)
+  #:use-module (language python try)
+  #:use-module (language python exceptions)
   #:export (Random))
 
 (define-syntax-rule (aif it p . l) (let ((it p)) (if p . l)))
 
+(define PI    (* 4 (atan 1)))
+(define TWOPI (* 2 PI))
+(define LOG4  (log 4.0))
+(define _e    (exp 1))
+
+(define NV_MAGICCONST (/ (* 4 (exp -0.5)) (sqrt 2.0)))
+(define SG_MAGICCONST (+ 1.0 (log 4.5)))
+
 (define-python-class Random ()
   (define seed
     (lambda (self s)
-      (rawset self '_state (seed->random-state (format #f "~a" s)))))
+      (fastset self '_state (seed->random-state (format #f "~a" s)))))
 
   (define setstate
     (lambda (self s)
-      (rawset self '_state s)))
+      (fastset self '_state s)))
 
   (define getstate
     (lambda (self)
-      (aif it (rawref self '_state)
+      (aif it (fastref self '_state)
            it
            (let ((ret (random-state-from-platform)))
-             (set self '_state ret)
+             (fastset self '_state ret)
              ret))))
 
+  
   (define getrandbits '(no))
+  
   (define random
     (lambda (self)
+      (let lp ()
+        (set! *random-state* (getstate self))
+        (let ((x (random:uniform)))
+          (if (= x 1.0)
+              (lp)
+              (begin
+                (fastset self '_state *random-state*)
+                x))))))
+
+
+  (define randrange
+    (lambda* (self start #:optional (stop None) (step 1) (_int int))
+      (define (fallback)
+        ((rawref self '_randrange) self start stop step _int))
+      
+      (if (number? start)
+          (if (eq? stop None)
+              (_randbelow self start)
+              (if (number? stop)
+                  (begin
+                    (if (<= stop start)
+                        (raise (ValueError "zero range in randrange")))
+                    (if (equal? step 1)
+                        (+ start (_randbelow self (- stop start)))
+                        (if (number? step)
+                            (let* ((width (- stop start))
+                                   (n (cond
+                                       ((= step 0)
+                                        (raise
+                                         (ValueError
+                                          "step of 0 is invalĂ­d in randrange")))
+                                       ((> step 0)
+                                        (floor-quotient
+                                         (+ width  step - 1) step))
+                                       (else
+                                        (floor-quotient
+                                         (+ width  step + 1) step)))))
+                              (+ start (* step (_randbelow self n))))
+                            (fallback))))
+                  (fallback)))
+          (fallback))))
+  
+              
+  (define randint
+    (lambda (self a b)
+      "Return random integer in range [a, b], including both end points.
+      "
+      (randrange self a b)))
+  
+  (define _randbelow
+    (lambda (self n)
+      "Return random integer in range [a, b], including both end points.
+      "
       (set! *random-state* (getstate self))
-      (let ((x (random:uniform)))
-        (rawset self '_state *random-state*)
-        x))))
+      (let ((x ((@ (guile) random) n)))
+        (fastset self '_state *random-state*)
+        x)))
+      
+
+  ;; -------------------- triangular --------------------
+
+  (define triangular
+    (lambda* (self #:optional (low 0.0) (high 1.0) (mode None))
+        "Triangular distribution.
+
+        Continuous distribution bounded by given lower and upper limits,
+        and having a given mode value in-between.
+
+        http://en.wikipedia.org/wiki/Triangular_distribution
+
+        "
+        (let ((u   (random self))
+              (c   (if (eq? mode None)
+                       0.5
+                       (let ((den (- high low)))
+                         (if (= den 0)
+                             low
+                             (/ (- mode low) 1.0 den))))))
+              
+          (if (> u c)
+              (let* ((u    (- 1.0 u))
+                     (c    (- 1.0 c))
+                     (t    high)
+                     (high low)
+                     (low  high))
+                (+ low (* (- high low) (sqrt (* u c)))))
+              (+ low (* (- high low) (sqrt (* u c))))))))
+
+  ;; -------------------- normal distribution --------------------
+
+  (define normalvariate
+    (lambda (self mu sigma)
+      "Normal distribution.
+
+       mu is the mean, and sigma is the standard deviation.
+
+      "
+      ;; mu = mean, sigma = standard deviation
+
+      ;; Uses Kinderman and Monahan method. Reference: Kinderman,
+      ;; A.J. and Monahan, J.F., "Computer generation of random
+      ;; variables using the ratio of uniform deviates", ACM Trans
+      ;; Math Software, 3, (1977), pp257-260.
+
+      (let lp ()
+        (let* ((u1 (random self))
+               (u2 (- 1.0 (random self)))
+               (z  (/ (* NV_MAGICCONST (- u1 0.5)) u2))
+               (zz (/ (* z z) 4.0)))
+            (if (<= zz (- (log u2)))
+                (+ mu (* z sigma))
+                (lp))))))
+  
+  ;; -------------------- lognormal distribution --------------------
+
+  (define lognormvariate
+    (lambda (self mu sigma)
+      "Log normal distribution.
+
+       If you take the natural logarithm of this distribution, you'll get a
+       normal distribution with mean mu and standard deviation sigma.
+       mu can have any value, and sigma must be greater than zero.
+
+      "
+      (exp (normalvariate self mu sigma))))
+
+  ;;## -------------------- exponential distribution --------------------
+
+  (define expovariate
+    (lambda (self lambd)
+      "Exponential distribution.
+
+       lambd is 1.0 divided by the desired mean.  It should be
+       nonzero.  (The parameter would be called \"lambda\", but that is
+       a reserved word in Python.)  Returned values range from 0 to
+       positive infinity if lambd is positive, and from negative
+       infinity to 0 if lambd is negative.
+
+       "
+
+       ;; lambd: rate lambd = 1/mean
+       ;; ('lambda' is a Python reserved word)
+
+       ;; we use 1-random() instead of random() to preclude the
+       ;; possibility of taking the log of zero.
+       
+       (- (/ (log (- 1.0 (random self))) lambd))))
+
+  ;;## -------------------- gamma distribution --------------------
+
+  (define gammavariate
+    (lambda (self alpha beta)
+        "Gamma distribution.  Not the gamma function!
+
+        Conditions on the parameters are alpha > 0 and beta > 0.
+
+        The probability distribution function is:
+
+                    x ** (alpha - 1) * math.exp(-x / beta)
+          pdf(x) =  --------------------------------------
+                      math.gamma(alpha) * beta ** alpha
+
+        "
+
+        ;; alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2
+        ;; Warning: a few older sources define the gamma distribution in terms
+        ;; of alpha > -1.0
+        
+        (if (or (<= alpha 0.0) (<= beta 0.0))
+            (raise (ValueError "gammavariate: alpha and beta must be > 0.0")))
+
+        (cond
+         ((> alpha 1.0)
+            ;; Uses R.C.H. Cheng, "The generation of Gamma
+            ;; variables with non-integral shape parameters",
+            ;; Applied Statistics, (1977), 26, No. 1, p71-74
+
+            (let* ((ainv (sqrt (- (* 2.0 alpha) 1.0)))
+                   (bbb  (- alpha LOG4))
+                   (ccc  (+ alpha ainv)))
+
+              (let lp ()
+                (let ((u1 (random self)))
+                  (if (or (< u1 1e-7) (> u1 .9999999))
+                      (lp)
+                      (let* ((u2 (- 1.0 (random self)))
+                             (v  (/ (log (/ u1 (- 1.0 u1))) ainv))
+                             (x  (* alpha (exp v)))
+                             (z  (* u1 u1 u2))
+                             (r  (+ bbb (* ccc v) (- x))))
+                        (if (or (>= (+ r SG_MAGICCONST (- (* 4.5 z))) 0.0)
+                                (>= r (log z)))
+                            (* x beta)
+                            (lp))))))))
+
+         ((= alpha 1.0)
+          ;; expovariate(1)
+          (let lp ((u (random self)))
+            (if (<= u 1e-7)
+                (lp (random self))
+                (- (* (log u) beta)))))
+
+         (else
+          ;;alpha is between 0 and 1 (exclusive)
+          ;; Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
+          
+          (let lp ()
+            (let* ((u  (random self))
+                   (b  (/ (+ _e alpha) _e))
+                   (p  (* b u))
+                   (x  (if (<= p 1.0)
+                           (expt p (/ 1.0 alpha))
+                           (- (log (/ (- b p) alpha)))))
+                   (u1 (random self)))
+              (if (> p 1.0)
+                  (if (<= u1 (expt x (- alpha 1.0)))
+                      (* x beta)
+                      (lp))
+                  (if (<= u1 (exp (- x)))
+                      (* x beta)
+                      (lp)))))))))
+
+  ;; -------------------- beta --------------------
+  ;; See
+  ;; http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html
+  ;; for Ivan Frohne's insightful analysis of why the original implementation:
+  ;;
+  ;;    def betavariate(self, alpha, beta):
+  ;;        # Discrete Event Simulation in C, pp 87-88.
+  ;;
+  ;;        y = self.expovariate(alpha)
+  ;;        z = self.expovariate(1.0/beta)
+  ;;        return z/(y+z)
+  ;;
+  ;; was dead wrong, and how it probably got that way.
+
+  (define betavariate
+    (lambda (self alpha beta)
+      "Beta distribution.
+
+       Conditions on the parameters are alpha > 0 and beta > 0.
+       Returned values range between 0 and 1.
+
+      "
+      
+      ;; This version due to Janne Sinkkonen, and matches all the std
+      ;; texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").
+      (let ((y (gammavariate self alpha 1.0)))
+        (if (= y 0)
+            0.0
+            (/ y (+ y (gammavariate self beta 1.0)))))))
+
+  ;; -------------------- von Mises distribution --------------------
+
+  (define vonmisesvariate
+    (lambda (self mu kappa)
+      "Circular data distribution.
+
+      mu is the mean angle, expressed in radians between 0 and 2*pi, and
+      kappa is the concentration parameter, which must be greater than or
+      equal to zero.  If kappa is equal to zero, this distribution reduces
+      to a uniform random angle over the range 0 to 2*pi.
+
+      "
+      ;; mu:    mean angle (in radians between 0 and 2*pi)
+      ;; kappa: concentration parameter kappa (>= 0)
+      ;; if kappa = 0 generate uniform random angle
+
+      ;; Based upon an algorithm published in: Fisher, N.I.,
+      ;; "Statistical Analysis of Circular Data", Cambridge
+      ;; University Press, 1993.
+
+      ;; Thanks to Magnus Kessler for a correction to the
+      ;; implementation of step 4.
+      
+      (if (<= kappa 1e-6)
+          (* TWOPI (random self))
+          (let* ((s (/ 0.5 kappa))
+                 (r (+ s (sqrt (+ 1.0 (* s s))))))
+            (let lp ()
+              (let* ((u1 (random self))
+                     (z  (cos (* PI u1)))
+                     (d  (/ z (+ r z)))
+                     (u2 (random self)))
+                (if (or (<  u2 (- 1.0 (* d d)))
+                        (<= u2 (* (- 1.0 d) (exp d))))
+                    (let* ((q  (/ 1.0  r))
+                           (f  (/ (+ q  z) (+ 1.0 (* q z))))
+                           (u3 (random self)))
+                      (if (> u3 0.5)
+                          (floor-remainder (+ mu (acos f)) TWOPI)
+                          (floor-remainder (- mu (acos f)) TWOPI)))
+                    (lp))))))))
+
+  (define uniform
+    (lambda (self a b)
+      "Get a random number in the range [a, b) or [a, b] depending on rounding."
+      (+ a (* (- b a) (random self)))))
+
+  
+  ;; -------------------- Pareto --------------------
+  (define paretovariate
+    (lambda (self alpha)
+      "Pareto distribution.  alpha is the shape parameter."
+      ;; Jain, pg. 495
+
+      (let ((u (- 1.0 (random self))))
+        (/ 1.0 (expt u (/ 1.0 alpha))))))
+
+  ;; -------------------- Weibull --------------------
+  (define weibullvariate
+    (lambda (self alpha beta)
+      "Weibull distribution.
+
+      alpha is the scale parameter and beta is the shape parameter.
+
+      "
+      ;; Jain, pg. 499; bug fix courtesy Bill Arms
+
+      (let ((u (- 1.0 (random self))))
+        (* alpha (expt (- (log u)) (/ 1.0 beta))))))
+
+
+  (define gauss
+    (lambda (self mu sigma)
+      "Gaussian distribution.
+
+        mu is the mean, and sigma is the standard deviation.  This is
+        slightly faster than the normalvariate() function.
+
+        Not thread-safe without a lock around calls.
+
+        "
+
+        ;; When x and y are two variables from [0, 1), uniformly
+        ;; distributed, then
+        ;;
+        ;;    cos(2*pi*x)*sqrt(-2*log(1-y))
+        ;;   sin(2*pi*x)*sqrt(-2*log(1-y))
+        ;;
+        ;; are two *independent* variables with normal distribution
+        ;; (mu = 0, sigma = 1).
+        ;; (Lambert Meertens)
+        ;; (corrected version; bug discovered by Mike Miller, fixed by LM)
+
+        ;; Multithreading note: When two threads call this function
+        ;; simultaneously, it is possible that they will receive the
+        ;; same return value.  The window is very small though.  To
+        ;; avoid this, you have to use a lock around all calls.  (I
+        ;; didn't want to slow this down in the serial case by using a
+        ;; lock here.)
+
+        (let ((z (fastref self 'gauss_next)))
+          (fastset self 'gauss_next #f)
+          (if (not z)
+              (let ((x2pi  (* (random self) TWOPI))
+                    (g2rad (sqrt (* -2.0 (log (- 1.0 (random self)))))))
+                (set! z (* (cos x2pi) g2rad))
+                (fastset self 'gauss_next (* (sin x2pi) g2rad))))
+
+          (+ mu (* z sigma))))))
 
   
index 058e62d..3c7809c 100644 (file)
                             newline closefd opener)
                      path)
                     mode)))
-       (if (member #\b (string->list mode))
-           F
-           (TextIOWrapper F encoding errors))))
+       (let ((r (if (member #\b (string->list mode))
+                    F
+                    (TextIOWrapper F encoding errors))))
+         (set r '_closefd closefd)
+         r)))
                    
 
 (define-syntax check
index e4dc72c..764c701 100644 (file)
                   RTLD_NOLOAD RTLD_DEEPBIND
 
                   getrandom urandom GRND_NONBLOCK GRND_RANDOM
+
+                  sys
                   ))
 
 (define supports_dir_fd
 (define-syntax-rule (ca code)
   (catch #t
     (lambda () code)
-    (lambda x (raise error x))))
+    (lambda x
+      (match x
+        (('system-error x _ _ (17))
+         (raise (FileExistsError x)))
+        (('system-error x _ _ (2))
+         (raise (FileNotFoundError x)))
+        (x (raise error x))))))
+
 (define-syntax-rule (rm code)
   (let ((r (ca code)))
     (if (< r 0)
 
 (define close
   (lambda (fd)
-    (ca ((@ (guile) close-fdes) fd))))
+    (ca ((@ (guile) close) fd))))
 
 (define (closerange fd_low fd_high)
   (for ((i : (range fd_low fd_high))) ()
      p)
     (py-list l)))
 
+(define-python-class sys ()
+  (define platform "posix"))
index 4c24977..be8f9ef 100644 (file)
@@ -92,8 +92,8 @@ class Random (_random.Random):
         """
 
         self.seed(x)
-        self.gauss_next = None
-
+        self.gauss_next = False
+        
     def seed(self, a=None, version=2):
         """Initialize internal state from hashable object.
 
@@ -124,7 +124,7 @@ class Random (_random.Random):
             a = int.from_bytes(a, 'big')
 
         super().seed(a)
-        self.gauss_next = None
+        self.gauss_next = False
 
     def getstate(self):
         """Return internal state; can be passed to setstate() later."""
@@ -169,9 +169,9 @@ class Random (_random.Random):
     def __reduce__(self):
         return self.__class__, (), self.getstate()
 
-## -------------------- integer methods  -------------------
+    ## -------------------- integer methods  -------------------
 
-    def randrange(self, start, stop=None, step=1, _int=int):
+    def _randrange_(self, start, stop, step, _int):
         """Choose a random item from range(start, stop[, step]).
 
         This fixes the problem with randint() which includes the
@@ -182,7 +182,6 @@ class Random (_random.Random):
         # This code is a bit messy to make it fast for the
         # common case while still doing adequate error checking.
         istart = _int(start)
-
         if istart != start:
             raise ValueError("non-integer arg 1 for randrange()")
         if stop is None:
@@ -192,11 +191,9 @@ class Random (_random.Random):
 
         # stop argument supplied.
         istop = _int(stop)
-
         if istop != stop:
             raise ValueError("non-integer stop for randrange()")
         width = istop - istart
-
         if step == 1 and width > 0:
             return istart + self._randbelow(width)
         if step == 1:
@@ -218,45 +215,6 @@ class Random (_random.Random):
 
         return istart + istep*self._randbelow(n)
 
-    def randint(self, a, b):
-        """Return random integer in range [a, b], including both end points.
-        """
-
-        return self.randrange(a, b+1)
-
-    def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type,
-                   Method=_MethodType, BuiltinMethod=_BuiltinMethodType):
-        "Return a random int in the range [0,n).  Raises ValueError if n==0."
-
-        random = self.random
-        getrandbits = self.getrandbits
-
-        # Only call self.getrandbits if the original random() builtin method
-        # has not been overridden or if a new getrandbits() was supplied.
-        if type(random) is BuiltinMethod or type(getrandbits) is Method:
-            k = n.bit_length()  # don't use (n-1) here because n can be 1
-            r = getrandbits(k)          # 0 <= r < 2**k
-            while r >= n:
-                r = getrandbits(k)
-            return r
-
-        # There's an overridden random() method but no new getrandbits() method,
-        # so we can only use random() from here.
-        if n >= maxsize:
-            _warn("Underlying random() generator does not supply \n"
-                "enough bits to choose from a population range this large.\n"
-                "To remove the range limitation, add a getrandbits() method.")
-            return int(random() * n)
-
-        rem = maxsize % n
-        limit = (maxsize - rem) / maxsize   # int(limit * maxsize) % n == 0
-
-        r = random()
-        while r >= limit:
-            r = random()
-
-        return int(r*maxsize) % n
-
 ## -------------------- sequence methods  -------------------
 
     def choice(self, seq):
@@ -373,300 +331,7 @@ class Random (_random.Random):
 
 ## -------------------- uniform distribution -------------------
 
-    def uniform(self, a, b):
-        "Get a random number in the range [a, b) or [a, b] depending on rounding."
-        return a + (b-a) * self.random()
-
-## -------------------- triangular --------------------
-
-    def triangular(self, low=0.0, high=1.0, mode=None):
-        """Triangular distribution.
-
-        Continuous distribution bounded by given lower and upper limits,
-        and having a given mode value in-between.
-
-        http://en.wikipedia.org/wiki/Triangular_distribution
-
-        """
-        u = self.random()
-        try:
-            c = 0.5 if mode is None else (mode - low) / (high - low)
-        except ZeroDivisionError:
-            return low
-        if u > c:
-            u = 1.0 - u
-            c = 1.0 - c
-            low, high = high, low
-        return low + (high - low) * (u * c) ** 0.5
-
-## -------------------- normal distribution --------------------
-
-    def normalvariate(self, mu, sigma):
-        """Normal distribution.
-
-        mu is the mean, and sigma is the standard deviation.
-
-        """
-        # mu = mean, sigma = standard deviation
-
-        # Uses Kinderman and Monahan method. Reference: Kinderman,
-        # A.J. and Monahan, J.F., "Computer generation of random
-        # variables using the ratio of uniform deviates", ACM Trans
-        # Math Software, 3, (1977), pp257-260.
-
-        random = self.random
-        while 1:
-            u1 = random()
-            u2 = 1.0 - random()
-            z = NV_MAGICCONST*(u1-0.5)/u2
-            zz = z*z/4.0
-            if zz <= -_log(u2):
-                break
-        return mu + z*sigma
-
-## -------------------- lognormal distribution --------------------
-
-    def lognormvariate(self, mu, sigma):
-        """Log normal distribution.
-
-        If you take the natural logarithm of this distribution, you'll get a
-        normal distribution with mean mu and standard deviation sigma.
-        mu can have any value, and sigma must be greater than zero.
-
-        """
-        return _exp(self.normalvariate(mu, sigma))
-
-## -------------------- exponential distribution --------------------
-
-    def expovariate(self, lambd):
-        """Exponential distribution.
-
-        lambd is 1.0 divided by the desired mean.  It should be
-        nonzero.  (The parameter would be called "lambda", but that is
-        a reserved word in Python.)  Returned values range from 0 to
-        positive infinity if lambd is positive, and from negative
-        infinity to 0 if lambd is negative.
-
-        """
-        # lambd: rate lambd = 1/mean
-        # ('lambda' is a Python reserved word)
-
-        # we use 1-random() instead of random() to preclude the
-        # possibility of taking the log of zero.
-        return -_log(1.0 - self.random())/lambd
-
-## -------------------- von Mises distribution --------------------
-
-    def vonmisesvariate(self, mu, kappa):
-        """Circular data distribution.
-
-        mu is the mean angle, expressed in radians between 0 and 2*pi, and
-        kappa is the concentration parameter, which must be greater than or
-        equal to zero.  If kappa is equal to zero, this distribution reduces
-        to a uniform random angle over the range 0 to 2*pi.
-
-        """
-        # mu:    mean angle (in radians between 0 and 2*pi)
-        # kappa: concentration parameter kappa (>= 0)
-        # if kappa = 0 generate uniform random angle
-
-        # Based upon an algorithm published in: Fisher, N.I.,
-        # "Statistical Analysis of Circular Data", Cambridge
-        # University Press, 1993.
-
-        # Thanks to Magnus Kessler for a correction to the
-        # implementation of step 4.
-
-        random = self.random
-        if kappa <= 1e-6:
-            return TWOPI * random()
-
-        s = 0.5 / kappa
-        r = s + _sqrt(1.0 + s * s)
-
-        while 1:
-            u1 = random()
-            z = _cos(_pi * u1)
-
-            d = z / (r + z)
-            u2 = random()
-            if u2 < 1.0 - d * d or u2 <= (1.0 - d) * _exp(d):
-                break
-
-        q = 1.0 / r
-        f = (q + z) / (1.0 + q * z)
-        u3 = random()
-        if u3 > 0.5:
-            theta = (mu + _acos(f)) % TWOPI
-        else:
-            theta = (mu - _acos(f)) % TWOPI
-
-        return theta
-
-## -------------------- gamma distribution --------------------
-
-    def gammavariate(self, alpha, beta):
-        """Gamma distribution.  Not the gamma function!
-
-        Conditions on the parameters are alpha > 0 and beta > 0.
-
-        The probability distribution function is:
-
-                    x ** (alpha - 1) * math.exp(-x / beta)
-          pdf(x) =  --------------------------------------
-                      math.gamma(alpha) * beta ** alpha
-
-        """
-
-        # alpha > 0, beta > 0, mean is alpha*beta, variance is alpha*beta**2
-
-        # Warning: a few older sources define the gamma distribution in terms
-        # of alpha > -1.0
-        if alpha <= 0.0 or beta <= 0.0:
-            raise ValueError('gammavariate: alpha and beta must be > 0.0')
-
-        random = self.random
-        if alpha > 1.0:
-
-            # Uses R.C.H. Cheng, "The generation of Gamma
-            # variables with non-integral shape parameters",
-            # Applied Statistics, (1977), 26, No. 1, p71-74
-
-            ainv = _sqrt(2.0 * alpha - 1.0)
-            bbb = alpha - LOG4
-            ccc = alpha + ainv
-
-            while 1:
-                u1 = random()
-                if not 1e-7 < u1 < .9999999:
-                    continue
-                u2 = 1.0 - random()
-                v = _log(u1/(1.0-u1))/ainv
-                x = alpha*_exp(v)
-                z = u1*u1*u2
-                r = bbb+ccc*v-x
-                if r + SG_MAGICCONST - 4.5*z >= 0.0 or r >= _log(z):
-                    return x * beta
-
-        elif alpha == 1.0:
-            # expovariate(1)
-            u = random()
-            while u <= 1e-7:
-                u = random()
-            return -_log(u) * beta
-
-        else:   # alpha is between 0 and 1 (exclusive)
-
-            # Uses ALGORITHM GS of Statistical Computing - Kennedy & Gentle
-
-            while 1:
-                u = random()
-                b = (_e + alpha)/_e
-                p = b*u
-                if p <= 1.0:
-                    x = p ** (1.0/alpha)
-                else:
-                    x = -_log((b-p)/alpha)
-                u1 = random()
-                if p > 1.0:
-                    if u1 <= x ** (alpha - 1.0):
-                        break
-                elif u1 <= _exp(-x):
-                    break
-            return x * beta
-
-## -------------------- Gauss (faster alternative) --------------------
-
-    def gauss(self, mu, sigma):
-        """Gaussian distribution.
-
-        mu is the mean, and sigma is the standard deviation.  This is
-        slightly faster than the normalvariate() function.
-
-        Not thread-safe without a lock around calls.
-
-        """
-
-        # When x and y are two variables from [0, 1), uniformly
-        # distributed, then
-        #
-        #    cos(2*pi*x)*sqrt(-2*log(1-y))
-        #    sin(2*pi*x)*sqrt(-2*log(1-y))
-        #
-        # are two *independent* variables with normal distribution
-        # (mu = 0, sigma = 1).
-        # (Lambert Meertens)
-        # (corrected version; bug discovered by Mike Miller, fixed by LM)
-
-        # Multithreading note: When two threads call this function
-        # simultaneously, it is possible that they will receive the
-        # same return value.  The window is very small though.  To
-        # avoid this, you have to use a lock around all calls.  (I
-        # didn't want to slow this down in the serial case by using a
-        # lock here.)
-
-        random = self.random
-        z = self.gauss_next
-        self.gauss_next = None
-        if z is None:
-            x2pi = random() * TWOPI
-            g2rad = _sqrt(-2.0 * _log(1.0 - random()))
-            z = _cos(x2pi) * g2rad
-            self.gauss_next = _sin(x2pi) * g2rad
-
-        return mu + z*sigma
-
-## -------------------- beta --------------------
-## See
-## http://mail.python.org/pipermail/python-bugs-list/2001-January/003752.html
-## for Ivan Frohne's insightful analysis of why the original implementation:
-##
-##    def betavariate(self, alpha, beta):
-##        # Discrete Event Simulation in C, pp 87-88.
-##
-##        y = self.expovariate(alpha)
-##        z = self.expovariate(1.0/beta)
-##        return z/(y+z)
-##
-## was dead wrong, and how it probably got that way.
-
-    def betavariate(self, alpha, beta):
-        """Beta distribution.
-
-        Conditions on the parameters are alpha > 0 and beta > 0.
-        Returned values range between 0 and 1.
-
-        """
-
-        # This version due to Janne Sinkkonen, and matches all the std
-        # texts (e.g., Knuth Vol 2 Ed 3 pg 134 "the beta distribution").
-        y = self.gammavariate(alpha, 1.0)
-        if y == 0:
-            return 0.0
-        else:
-            return y / (y + self.gammavariate(beta, 1.0))
-
-## -------------------- Pareto --------------------
-
-    def paretovariate(self, alpha):
-        """Pareto distribution.  alpha is the shape parameter."""
-        # Jain, pg. 495
-
-        u = 1.0 - self.random()
-        return 1.0 / u ** (1.0/alpha)
-
-## -------------------- Weibull --------------------
-
-    def weibullvariate(self, alpha, beta):
-        """Weibull distribution.
-
-        alpha is the scale parameter and beta is the shape parameter.
-
-        """
-        # Jain, pg. 499; bug fix courtesy Bill Arms
 
-        u = 1.0 - self.random()
-        return alpha * (-_log(u)) ** (1.0/beta)
 
 ## --------------- Operating System Random Source  ------------------
 
@@ -750,10 +415,14 @@ def _test_generator0(n, func):
     print('avg %g, stddev %g, min %g, max %g\n' % \
               (avg, stddev, smallest, largest))
 
+x    = _random.Random()
+rand = x.random
 
 def _test(N=2000):
+    _test_generator(N, randint, (10, 20))
     _test_generator(N, random, ())
     _test_generator0(N, random)
+    _test_generator0(N, rand)
     _test_generator(N, normalvariate, (0.0, 1.0))
     _test_generator(N, lognormvariate, (0.0, 1.0))
     _test_generator(N, vonmisesvariate, (0.0, 1.0))
index c2dd77c..73d6cba 100644 (file)
@@ -32,4 +32,5 @@
   
   (define release __leave__))
     
-
+(define allocate_lock
+  (lambda () (RLock)))
index a189d84..ad80a87 100644 (file)
 (define-python-class string (<py-string>)
   (define __init__
     (case-lambda
-     ((self s . l)  
-      (cond
-       ((is-a? s <py-string>)
-        (slot-ref s 'str))
-       ((is-a? s <string>)
-        s)
-       ((b? s)
-        (apply b-decode s l))
-       (else
-        (aif it (ref s '__str__)
-             (it)
-             (__init__ self ((@ (guile) format) #f "~a" s))))))))
+      ((self)
+       "")
+      ((self s . l)  
+       (cond
+        ((is-a? s <py-string>)
+         (slot-ref s 'str))
+        ((is-a? s <string>)
+         s)
+        ((b? s)
+         (apply b-decode s l))
+        (else
+         (aif it (ref s '__str__)
+              (it)
+              (__init__ self ((@ (guile) format) #f "~a" s))))))))
        
   
   (define __new__
index 0e2f1d9..47dea90 100644 (file)
@@ -18,7 +18,7 @@
                 *class* *self* pyobject? pytype?
                 type object pylist-set! pylist-ref tr
                resolve-method-g rawref rawset py-dict
-                ref-class
+                ref-class fastref fastset
                 ))
 
 #|
@@ -35,6 +35,7 @@ The datastructure is functional but the objects mutate. So one need to
 explicitly tell it to not update etc.
 |#
 
+  
 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
 
 ;; this is mutated by the dict class
@@ -144,6 +145,20 @@ explicitly tell it to not update etc.
 (name-object <pyf>)
 (name-object <property>)
 
+(define (fastref o k . e)
+  (define r (if (pair? e) (car e) #f))
+  (let ((h (slot-ref o 'h)))
+    (if (hash-table? h)
+        (hash-ref (slot-ref o 'h) k r)
+        (aif it (vhash-assoc k (slot-ref o 'h)) (cdr it) r))))
+
+(define (fastset o k v)
+  (let ((h (slot-ref o 'h)))
+    (if (hash-table? h)
+        (hash-set! (slot-ref o 'h) k v)
+        (slot-set! o 'h
+                   (vhash-cons k v (slot-ref o 'h))))))
+
 (define-method (pylist-set! (o <p>) key val)
   (aif it (ref o '__setitem__)
        (it key val)
@@ -247,7 +262,7 @@ explicitly tell it to not update etc.
             (if (pytype? cls)                
                 (lambda x (apply f obj x))
                 f)
-            (if (pyclass? cls)
+            (if (pyclass? cls)                
                 (lambda x (apply f obj x))
                 f)))))
 
@@ -730,7 +745,7 @@ explicitly tell it to not update etc.
     #f)))
 
 (define-syntax-rule (mox o x)
-  (if (procedure? x)
+  (if (and (procedure? x) (not (is-a? x <p>)))
       (aif it (procedure-property- x '__get__)
            (it x o (fluid-ref *location*))
            x)))