switch manager

4 views
Skip to first unread message

smichr

unread,
Jul 12, 2009, 5:02:43 AM7/12/09
to sympy
I am wondering if the attached switch manager might be a way to get
rid of having to maintain a lot of wrappers for at least expand() and
maybe for other methods. The idea is this (using expand as an
example):

expr.expand() uses all default expansion methods

expr.expand(log=False) uses all default expansions EXCEPT log (can
also use log=0 instead of log=False)

expr.expand(log=True) uses ONLY the log expansion (can also use log=1
instead of log=True)

expr.expand(mul=True,multinomial=True) uses ONLY the mul and
multinomial expansion

The change that would make this possible requires only that the
default values for the different expansion methods be set to None and
then a couple lines of code are added in the expand, so

this...
def expand(self, deep=True, power_base=True, power_exp=True,
mul=True, \
log=True, multinomial=True, basic=True, **hints):
hints['power_base'] = power_base
hints['power_exp'] = power_exp
hints['mul'] = mul
hints['log'] = log
hints['multinomial'] = multinomial
hints['basic'] = basic

becomes this...
def expand(self, deep=True, power_base=None, power_exp=None,
mul=None, \
log=None, multinomial=None, basic=None, **hints):
dhints={} #<--- additional line
dhints['power_base'] = power_base
dhints['power_exp'] = power_exp
dhints['mul'] = mul
dhints['log'] = log
dhints['multinomial'] = multinomial
dhints['basic'] = basic
switch_manager(dhints, default=True) {} #<--- additional line
hints.update(dhints) {} #<--- additional line

It's not mandatory to create a new dictionary if the hints has only
True or False values in it. It's only necessary if hints has other
values in it. In that case, the first and last additional lines marked
above are not necessary, and dhints is changed to hints.

######## attachment
"""
demonstration of managing multiple switches for a function
"""

def switch_manager(opt_dict, default=True):
"""Given a dictionary of switch values (True, False, or None)
return the dictionary with switches True or False according to
the following logic:

-if all swtiches have been set and there are no None values,
change nothing;
-if all switches are neutral (value = None) set them all to the
default value;
-if some switches are True and some are False then set the rest to
the default value;
-if one or more switches have been set to True then set the rest
to False;
-if one or more switches have been set to False then set the rest
to True.
"""
vals = set(filter(lambda x: x != None, opt_dict.values()))
if len(vals) == len(opt_dict):
return #there are no switches in neutral (None) position

if not all(tmp in [True, False, None] for tmp in vals):
#actually, 1 or 0 will pass as True or False, too
raise ValueError('Expecting only True, False, or None
options.')

#make default opposite of what was given
if not vals or len(vals) > 1:
pass #don't change the default
elif vals.pop() == True:
default = False
else:
default = True

#set None values to default
for k in opt_dict:
if opt_dict[k] == None:
opt_dict[k] = default

def demo(a=None, b=None, c=None, **opts):
default_opts={} #these are the options which must take on a value
default_opts['a'] = a
default_opts['b'] = b
default_opts['c'] = c
switch_manager(default_opts, default=True)
opts.update(default_opts)

#do whatever you are going to do with the options
for k in sorted(opts):
print k,opts[k]

print 'demo()=all true by default'
demo()
print 'demo(a=True) only a true'
demo(a=True)
print 'demo(a=True,b=True) only a and b true; equivalent to demo
(c=False)'
demo(a=True,b=True)
print 'demo(a=True,b=False) c is true by default; equivalent to demo
(b=False)'
demo(a=True,b=False)
print 'demo(b=False) only b false'
demo(b=False)
print 'demo(d=42) a,b,c have default True and d is 42'
demo(d=42)
print 'demo(a=False,d=42) b,c have default True and d is 42'
demo(a=False,d=42)
print 'demo(b=True,d=42) a,c False and d is 42'
demo(b=True,d=42)

## output
'''
demo()=all true by default
a True
b True
c True
demo(a=True) only a true
a True
b False
c False
demo(a=True,b=True) only a and b true; equivalent to demo(c=False)
a True
b True
c False
demo(a=True,b=False) c is true by default; equivalent to demo(b=False)
a True
b False
c True
demo(b=False) only b false
a True
b False
c True
demo(d=42) a,b,c have default True and d is 42
a True
b True
c True
d 42
demo(a=False,d=42) b,c have default True and d is 42
a False
b True
c True
d 42
demo(b=True,d=42) a,c False and d is 42
a False
b True
c False
d 42
'''

Aaron S. Meurer

unread,
Jul 12, 2009, 6:30:38 PM7/12/09
to sy...@googlegroups.com
I like this. It is basically what I couldn't figure out how to
reasonably do when I refactored expand. It would remove the need for
the dummy functions expand_log, expand_mul, and so on. Also, do you
think that powsimp() could benefit from this? When I rewrote it
several weeks ago, I added a switch "combine" to control the two
different combining methods (see the docstring for more info). So
basically, you can do combine='exp' to only combine exponentials,
combine='base' to only combine bases, and combine='all' (the default)
to do both. I think we could probably use your function to do
exp=True and base=True. Also, I think my dsolve hints function that I
am writing could benefit from this.

If we do this, we will have to change documentation, as well as usage
of several expand() functions in code and tests because currently,
doing <log, mul, power_exp, ...>=True is a no-op, so it needs to be
made clear that it isn't any longer.

Also, see my comments below.

Aaron Meurer
Maybe you should also add a default_dict=True that takes in a
dictionary of default options, incase there is a function that uses
**kwargs instead of default arguments. It would also allow default
options to be False instead of True, though I don't know how much that
would complicate the rules that you have outlined below.
> """Given a dictionary of switch values (True, False, or None)
> return the dictionary with switches True or False according to
> the following logic:
>
> -if all swtiches have been set and there are no None values,
> change nothing;
> -if all switches are neutral (value = None) set them all to the
> default value;
> -if some switches are True and some are False then set the rest to
> the default value;
On the two lines below, I assume you mean "if one or more switches
have been set to True and none are set to False". It is a little
ambiguous the way you have it.

smichr

unread,
Jul 15, 2009, 6:58:13 AM7/15/09
to sympy


On Jul 13, 3:30 am, "Aaron S. Meurer" <asmeu...@gmail.com> wrote:
> think that powsimp() could benefit from this? When I rewrote it
> several weeks ago, I added a switch "combine" to control the two
> different combining methods (see the docstring for more info). So
> basically, you can do combine='exp' to only combine exponentials,
> combine='base' to only combine bases, and combine='all' (the default)
> to do both. I think we could probably use your function to do
> exp=True and base=True. Also, I think my dsolve hints function that I

or you could add the option 'power' which does both base and exp.


> Maybe you should also add a default_dict=True that takes in a
> dictionary of default options, incase there is a function that uses
> **kwargs instead of default arguments.

I hardly use these sorts of things so I would have to defer to those
with more experience.

> It would also allow default
> options to be False instead of True, though I don't know how much that
> would complicate the rules that you have outlined below.

You have the option in the switch manager of giving it a default of
False; maybe I am misunderstanding what you mean.

>
> On the two lines below, I assume you mean "if one or more switches
> have been set to True and none are set to False". It is a little
> ambiguous the way you have it.

Yes, I could have said "If all given switches are True then the rest
will be set to False and if all given are False then those that have
not been given will be set to True."
>
> > -if one or more switches have been set to True then set the rest
> > to False;
> > -if one or more switches have been set to False then set the rest
> > to True.
> > """

One thing I was thinking about along the lines of "explicit is better
than implicit" is that this becomes a little more implicit in terms of
what is on and what is off and a clear method of indicating switches
logic is important. e.g. in the docstring we might put something like:

Hint options:
- basic
- log
- mul
- multinomial
- power_exp
- power_base
F complex
F func
F trig

key:
(-) indicates options to select as being True or False and those that
are unselected will have the opposite sense (e.g. if log=True then
ONLY log will be True)
(F) indicates options that are off unless explicitly set to True (i.e.
expand(log=False) will only turn on the (-) hints, not the (F) hints.

Something like that...one issue that isn't resolved for me is how to
handle the (F) args: if you do expand(func=True) should that turn all
the (-) ones off? The way the routine works right now, those that are
not in the (F) set do not affect the (-) set. I guess to only use the
func expansion you would have to do: expand(default=off, func=True)

Open to ideas,
/c

Aaron S. Meurer

unread,
Jul 15, 2009, 12:54:55 PM7/15/09
to sy...@googlegroups.com
This is what I was talking about with complications with default False
arguments. I think having an additional default argument would work,
like you describe.

Aaron Meurer
> Open to ideas,
> /c
>
> >

Reply all
Reply to author
Forward
0 new messages