diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/language/python/compile.scm | 68 | ||||
-rw-r--r-- | modules/language/python/def.scm | 16 | ||||
-rw-r--r-- | modules/language/python/exceptions.scm | 9 | ||||
-rw-r--r-- | modules/language/python/module/_random.scm | 385 | ||||
-rw-r--r-- | modules/language/python/module/io.scm | 8 | ||||
-rw-r--r-- | modules/language/python/module/os.scm | 15 | ||||
-rw-r--r-- | modules/language/python/module/random.py | 349 | ||||
-rw-r--r-- | modules/language/python/module/threading.scm | 3 | ||||
-rw-r--r-- | modules/language/python/string.scm | 26 | ||||
-rw-r--r-- | modules/oop/pf-objects.scm | 21 |
10 files changed, 495 insertions, 405 deletions
diff --git a/modules/language/python/compile.scm b/modules/language/python/compile.scm index 91c33c1..86b30dc 100644 --- a/modules/language/python/compile.scm +++ b/modules/language/python/compile.scm @@ -188,7 +188,7 @@ (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))) @@ -377,7 +377,7 @@ (union s (fold (lambda (x s) - (match x + (match x ((#:test (#:power v2 v1 () . _) . _) (if v2 (union @@ -907,6 +907,9 @@ (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 @@ -1016,16 +1019,13 @@ (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) @@ -1555,18 +1555,18 @@ (,(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 @@ -1575,18 +1575,18 @@ (,(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 ((_ . _) @@ -1871,7 +1871,7 @@ #: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)) @@ -2716,14 +2716,20 @@ #: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) diff --git a/modules/language/python/def.scm b/modules/language/python/def.scm index b2a8de2..1f527e9 100644 --- a/modules/language/python/def.scm +++ b/modules/language/python/def.scm @@ -143,10 +143,18 @@ (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)))) diff --git a/modules/language/python/exceptions.scm b/modules/language/python/exceptions.scm index 915c9ef..8bc812f 100644 --- a/modules/language/python/exceptions.scm +++ b/modules/language/python/exceptions.scm @@ -13,9 +13,11 @@ 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) @@ -119,3 +123,4 @@ (define-wr BytesWarning 'BytesWarning) (define-wr DepricationWarning 'DeprecationWarning) +(define-wr ResourceWarning 'ResourceWarning) diff --git a/modules/language/python/module/_random.scm b/modules/language/python/module/_random.scm index 74b9492..95ff989 100644 --- a/modules/language/python/module/_random.scm +++ b/modules/language/python/module/_random.scm @@ -1,33 +1,404 @@ (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)))))) diff --git a/modules/language/python/module/io.scm b/modules/language/python/module/io.scm index 058e62d..3c7809c 100644 --- a/modules/language/python/module/io.scm +++ b/modules/language/python/module/io.scm @@ -158,9 +158,11 @@ 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 diff --git a/modules/language/python/module/os.scm b/modules/language/python/module/os.scm index e4dc72c..764c701 100644 --- a/modules/language/python/module/os.scm +++ b/modules/language/python/module/os.scm @@ -114,6 +114,8 @@ RTLD_NOLOAD RTLD_DEEPBIND getrandom urandom GRND_NONBLOCK GRND_RANDOM + + sys )) (define supports_dir_fd @@ -135,7 +137,14 @@ (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) @@ -442,7 +451,7 @@ (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))) () @@ -2363,3 +2372,5 @@ p) (py-list l))) +(define-python-class sys () + (define platform "posix")) diff --git a/modules/language/python/module/random.py b/modules/language/python/module/random.py index 4c24977..be8f9ef 100644 --- a/modules/language/python/module/random.py +++ b/modules/language/python/module/random.py @@ -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)) diff --git a/modules/language/python/module/threading.scm b/modules/language/python/module/threading.scm index c2dd77c..73d6cba 100644 --- a/modules/language/python/module/threading.scm +++ b/modules/language/python/module/threading.scm @@ -32,4 +32,5 @@ (define release __leave__)) - +(define allocate_lock + (lambda () (RLock))) diff --git a/modules/language/python/string.scm b/modules/language/python/string.scm index a189d84..ad80a87 100644 --- a/modules/language/python/string.scm +++ b/modules/language/python/string.scm @@ -601,18 +601,20 @@ (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__ diff --git a/modules/oop/pf-objects.scm b/modules/oop/pf-objects.scm index 0e2f1d9..47dea90 100644 --- a/modules/oop/pf-objects.scm +++ b/modules/oop/pf-objects.scm @@ -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))) |