15
15
from Container import Container
16
16
from InstantiationDecorators import deterministic , check_special_methods
17
17
import numpy as np
18
- from numpy import sum , shape ,size , ravel , sign , zeros , ones , broadcast , newaxis
19
- import inspect , types
20
- from utils import safe_len , stukel_logit , stukel_invlogit , logit , invlogit , value , find_element
18
+ import inspect
19
+ from utils import safe_len , stukel_logit , stukel_invlogit , logit , invlogit , value
21
20
from types import UnboundMethodType
22
21
from copy import copy
23
22
import sys
24
- import operator , __builtin__
25
23
26
24
__all__ = ['CompletedDirichlet' , 'LinearCombination' , 'Index' , 'Lambda' , 'lambda_deterministic' , 'lam_dtrm' ,
27
25
'logit' , 'invlogit' , 'stukel_logit' , 'stukel_invlogit' , 'Logit' , 'InvLogit' , 'StukelLogit' , 'StukelInvLogit' ,
@@ -319,7 +317,7 @@ def eval_fun(x, y):
319
317
stochastic_elem = x [i ]
320
318
self .sides [stochastic_elem ].append ('L' )
321
319
this_coef = Lambda ('%s_coef' % stochastic_elem , lambda c = y [i ]: np .asarray (c ))
322
- self .coefs [stochastic_elem ].append (this_coef )
320
+ self .coefs [stochastic_elem ].append (this_coef )
323
321
324
322
if isinstance (y [i ], pm .Stochastic ):
325
323
@@ -486,36 +484,25 @@ def wrapper(**wkwds_in):
486
484
# = Add special methods to variables to support FBC syntax =
487
485
# ==========================================================
488
486
489
- def create_uni_method (op_name , klass , jacobians = None ):
487
+ def create_uni_method (op_name , klass ):
490
488
"""
491
489
Creates a new univariate special method, such as A.__neg__() <=> -A,
492
490
for target class. The method is called __op_name__.
493
491
"""
494
492
# This function will become the actual method.
495
- op_modules = [operator , __builtin__ ]
496
- op_names = [ op_name , op_name + '_' ]
497
-
498
- op_function_base = find_element ( op_names ,op_modules , error_on_fail = True )
499
- #many such functions do not take keyword arguments, so we need to wrap them
500
- def op_function (self ):
501
- return op_function_base (self )
502
-
503
493
def new_method (self ):
504
494
# This code creates a Deterministic object.
505
- if not check_special_methods ( ):
506
- raise NotImplementedError , 'Special method %s called on %s, but special methods have been disabled. Set pymc.special_methods_available to True to enable them.' % ( op_name , str ( self ))
507
-
508
- jacobian_formats = { 'self' : 'transformation_operation' }
509
- return pm .Deterministic (op_function ,
495
+ def eval_fun ( self , op = op ):
496
+ if not check_special_methods ():
497
+ raise NotImplementedError , 'Special method %s called on %s, but special methods have been disabled. Set pymc.special_methods_available to True to enable them.' % ( op_name , str ( self ))
498
+ return getattr ( self , op )()
499
+ return pm .Deterministic (eval_fun ,
510
500
'A Deterministic returning the value of %s(%s)' % (op_name , self .__name__ ),
511
501
'(' + op_name + '_' + self .__name__ + ')' ,
512
- parents = {'self' :self },
502
+ {'self' :self , 'op' : '__' + op_name + '__' },
513
503
trace = False ,
514
- plot = False ,
515
- jacobians = jacobians ,
516
- jacobian_formats = jacobian_formats )
517
- # Make the function into a method for klass.
518
-
504
+ plot = False )
505
+ # Make the function into a method for klass.
519
506
new_method .__name__ = '__' + op_name + '__'
520
507
setattr (klass , new_method .__name__ , UnboundMethodType (new_method , None , klass ))
521
508
@@ -533,11 +520,7 @@ def new_method(self, op=op):
533
520
new_method .__name__ = '__' + op .__name__ + '__'
534
521
setattr (klass , new_method .__name__ , UnboundMethodType (new_method , None , klass ))
535
522
536
-
537
-
538
-
539
-
540
- def create_rl_bin_method (op_name , klass , jacobians = {}):
523
+ def create_rl_bin_method (op_name , klass ):
541
524
"""
542
525
Creates a new binary special method with left and right versions, such as
543
526
A.__mul__(B) <=> A*B,
@@ -547,33 +530,34 @@ def create_rl_bin_method(op_name, klass, jacobians = {}):
547
530
# Make left and right versions.
548
531
for prefix in ['r' ,'' ]:
549
532
# This function will became the methods.
550
- op_modules = [operator , __builtin__ ]
551
- op_names = [ op_name , op_name + '_' ]
552
-
553
- op_function_base = find_element ( op_names , op_modules , error_on_fail = True )
554
- #many such functions do not take keyword arguments, so we need to wrap them
555
- def op_function (a , b ):
556
- return op_function_base (a , b )
557
-
558
533
def new_method (self , other , prefix = prefix ):
559
534
if not check_special_methods ():
560
535
raise NotImplementedError , 'Special method %s called on %s, but special methods have been disabled. Set pymc.special_methods_available to True to enable them.' % (op_name , str (self ))
561
536
# This code will create one of two Deterministic objects.
562
537
if prefix == 'r' :
563
- parents = {'a' :other , 'b' :self }
564
-
538
+ # Right version: raises error on failure.
539
+ parents = {'self' :self , 'other' :other , 'op' :'__r' + op_name + '__' }
540
+ def eval_fun (self ,other ,op ):
541
+ out = getattr (self , op )(other )
542
+ if out is NotImplemented :
543
+ # the rt version has failed, meainng the lft version has failed as well.
544
+ raise TypeError , "unsupported operand type(s) for %s: '%s' and '%s'" % (op .replace ('_' ,'' ), self .__class__ .__name__ , other .__class__ .__name__ )
545
+ return out
565
546
else :
566
- parents = {'a' :self , 'b' :other }
567
- jacobian_formats = {'a' : 'broadcast_operation' ,
568
- 'b' : 'broadcast_operation' }
569
- return pm .Deterministic (op_function ,
547
+ # Left version: tries right version on failure.
548
+ parents = {'self' :self , 'other' :other , 'op' :'__' + op_name + '__' , 'rt_op' : '__r' + op_name + '__' }
549
+ def eval_fun (self , other , op , rt_op ):
550
+ out = getattr (self , op )(other )
551
+ if out is NotImplemented :
552
+ # if try the rt version.
553
+ out = getattr (other , rt_op )(self )
554
+ return out
555
+ return pm .Deterministic (eval_fun ,
570
556
'A Deterministic returning the value of %s(%s,%s)' % (prefix + op_name ,self .__name__ , str (other )),
571
557
'(' + '_' .join ([self .__name__ ,prefix + op_name ,str (other )])+ ')' ,
572
558
parents ,
573
559
trace = False ,
574
- plot = False ,
575
- jacobians = jacobians ,
576
- jacobian_formats = jacobian_formats )
560
+ plot = False )
577
561
# Convert the functions into methods for klass.
578
562
new_method .__name__ = '__' + prefix + op_name + '__'
579
563
setattr (klass , new_method .__name__ , UnboundMethodType (new_method , None , klass ))
@@ -644,62 +628,20 @@ def new_method(self, *args):
644
628
new_method .__name__ = '__' + op_name + '__'
645
629
setattr (klass , new_method .__name__ , UnboundMethodType (new_method , None , klass ))
646
630
647
- def op_to_jacobians (op , module ):
648
- if type (module ) is types .ModuleType :
649
- module = copy (module .__dict__ )
650
- elif type (module ) is dict :
651
- module = copy (module )
652
- else :
653
- raise AttributeError
654
-
655
- name = op + "_jacobians"
656
- try :
657
- jacobians = module [name ]
658
- except :
659
- jacobians = {}
660
-
661
- return jacobians
662
-
663
631
# Left/right binary operators
664
-
665
-
666
- truediv_jacobians = {'a' : lambda a , b : ones (shape (a ))/ b ,
667
- 'b' : lambda a , b : - a / b ** 2 }
668
-
669
- div_jacobians = truediv_jacobians
670
-
671
- pow_jacobians = {'a' : lambda a , b : b * a ** (b - 1.0 ),
672
- 'b' : lambda a , b : np .log (a ) * a ** b }
673
-
674
-
675
632
for op in ['div' , 'truediv' , 'floordiv' , 'mod' , 'divmod' , 'pow' , 'lshift' , 'rshift' , 'and' , 'xor' , 'or' ]:
676
- create_rl_bin_method (op , Variable , jacobians = op_to_jacobians (op , locals ()))
677
-
678
- # Binary operators eq not part of this set because it messes up having stochastics in lists
679
- for op in ['lt' , 'le' , 'ne' , 'gt' , 'ge' ]:
680
- create_bin_method (op ,Variable )
681
-
682
- def equal (s1 , s2 ): #makes up for deficiency of __eq__
683
- return pm .Deterministic (lambda x1 , x2 : x1 == x2 ,
684
- 'A Deterministic returning the value of x1 == x2' ,
685
- '(' + '_' .join ([s1 .__name__ ,'=' ,str (s2 )])+ ')' ,
686
- {'x1' :s1 , 'x2' :s2 },
687
- trace = False ,
688
- plot = False )
633
+ create_rl_bin_method (op , Variable )
689
634
635
+ # # Binary operators
636
+ # for op in ['lt', 'le', 'eq', 'ne', 'gt', 'ge']:
637
+ # create_bin_method(op ,Variable)
690
638
691
639
# Unary operators
692
- neg_jacobians = {'self' : lambda self : - ones (shape (self ))}
693
-
694
- pos_jacobians = {'self' : lambda self : np .ones (shape (self ))}
695
-
696
- abs_jacobians = {'self' : lambda self : np .sign (self )}
697
-
698
- for op in ['neg' ,'abs' ,'invert' ]: # no need for pos and __index__ seems to cause a lot of problems
699
- create_uni_method (op , Variable , jacobians = op_to_jacobians (op , locals ()))
640
+ for op in ['neg' ,'pos' ,'abs' ,'invert' ,'index' ]:
641
+ create_uni_method (op , Variable )
700
642
701
643
# Casting operators
702
- for op in [iter ,complex ,int ,long ,float ,oct ,hex ]:
644
+ for op in [iter ,complex ,int ,long ,float ,oct ,hex , len ]:
703
645
create_casting_method (op , Variable )
704
646
705
647
# Addition, subtraction, multiplication
@@ -712,50 +654,31 @@ def equal(s1, s2): #makes up for deficiency of __eq__
712
654
# create_rl_lin_comb_method('rmul', Variable, ['self'],['other'])
713
655
714
656
#TODO: Comment once LinearCombination issues are ironed out.
715
-
716
- add_jacobians = {'a' : lambda a , b : ones (broadcast (a ,b ).shape ),
717
- 'b' : lambda a , b : ones (broadcast (a ,b ).shape )}
718
-
719
- mul_jacobians = {'a' : lambda a , b : ones (shape (a )) * b ,
720
- 'b' : lambda a , b : ones (shape (b )) * a }
721
-
722
- sub_jacobians = {'a' : lambda a , b : ones (broadcast (a ,b ).shape ),
723
- 'b' : lambda a , b : - ones (broadcast (a ,b ).shape )}
724
-
725
657
for op in ['add' , 'mul' , 'sub' ]:
726
- create_rl_bin_method (op , Variable , jacobians = op_to_jacobians ( op , locals ()) )
658
+ create_rl_bin_method (op , Variable )
727
659
728
660
for op in ['iadd' ,'isub' ,'imul' ,'idiv' ,'itruediv' ,'ifloordiv' ,'imod' ,'ipow' ,'ilshift' ,'irshift' ,'iand' ,'ixor' ,'ior' ,'unicode' ]:
729
661
create_nonimplemented_method (op , Variable )
730
662
731
663
732
- def getitem_jacobian (self , index ):
733
- return index
734
-
735
-
736
664
# Create __getitem__ method.
737
665
def __getitem__ (self , index ):
738
666
if not check_special_methods ():
739
667
raise NotImplementedError , 'Special method __index__ called on %s, but special methods have been disabled. Set pymc.special_methods_available to True to enable them.' % str (self )
740
668
# If index is number or number-valued variable, make an Index object
741
669
name = '%s[%s]' % (self .__name__ , str (index ))
742
- if np .isscalar (value (index )) and len ( np . shape ( self . value )) < 2 :
670
+ if np .isscalar (value (index )):
743
671
if np .isreal (value (index )):
744
672
return Index (name , self , index , trace = False , plot = False )
745
673
# Otherwise make a standard Deterministic.
746
674
def eval_fun (self , index ):
747
675
return self [index ]
748
-
749
- jacobians = {'self' : getitem_jacobian }
750
- jacobian_formats = {'self' : 'index_operation' }
751
676
return pm .Deterministic (eval_fun ,
752
677
'A Deterministic returning the value of %s[%s]' % (self .__name__ , str (index )),
753
678
name ,
754
679
{'self' :self , 'index' :index },
755
680
trace = False ,
756
- plot = False ,
757
- jacobians = jacobians ,
758
- jacobian_formats = jacobian_formats )
681
+ plot = False )
759
682
Variable .__getitem__ = UnboundMethodType (__getitem__ , None , Variable )
760
683
761
684
# Create __call__ method for Variable.
0 commit comments