Skip to content

Commit

Permalink
Refs #4333. Fix a bug in boolean binary ops, e.g. less than.
Browse files Browse the repository at this point in the history
Also adds the single unary operation that we have.
  • Loading branch information
martyngigg committed Dec 19, 2011
1 parent a3cb44a commit 82ea85a
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# Attach operators to workspaces
###############################################################################
import workspaceops as _ops
_ops.attach_binary_operators_to_workspace()
_ops.add_operators_to_workspace()

###############################################################################
# Make the singleton objects available as named variables
Expand Down
132 changes: 103 additions & 29 deletions Code/Mantid/Framework/PythonInterface/mantid/api/workspaceops.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,57 @@
It is intended for internal use.
"""
from mantid.api import Workspace, AnalysisDataService
from mantid.api import performBinaryOp as _perform_binary_op
from mantid.api import Workspace, AnalysisDataService, FrameworkManager
from mantid.api import performBinaryOp as _performBinaryOp
from mantid.kernel.funcreturns import lhs_info

_ads = AnalysisDataService.Instance()

def add_operators_to_workspace():
attach_binary_operators_to_workspace()
attach_unary_operators_to_workspace()

#------------------------------------------------------------------------------
# Binary Ops
#------------------------------------------------------------------------------
def attach_binary_operators_to_workspace():
"""
Attaches the common binary operators
to the Workspace class
"""
def add_operator_func(attr, algorithm, inplace, reverse):
# Wrapper for the function call
def op_wrapper(self, other):
# Get the result variable to know what to call the output
result_info = lhs_info()
# Pass off to helper
return _do_binary_operation(algorithm, self, other, result_info,
inplace, reverse)
op_wrapper.__name__ = attr
setattr(Workspace, attr, op_wrapper)
# Binary operations that workspaces are aware of
operations = {
"Plus":("__add__", "__radd__","_iadd__"),
"Minus":("__sub__", "__rsub__","_isub__"),
"Multiply":("__mul__", "__rmul__","_imul__"),
"Divide":("__div__", "__div__","_idiv__"),
"LessThan":("__lt__"),
"GreaterThan":("__gt__"),
"Or":("__or__"),
"And":("__and__"),
"Xor":("__xor__")
"LessThan":"__lt__",
"GreaterThan":"__gt__",
"Or":"__or__",
"And":"__and__",
"Xor":"__xor__"
}
# Loop through and add each one in turn
for alg, attributes in operations.iteritems():
if type(attributes) == str: attributes = [attributes]
for attr in attributes:
add_operator_func(attr, alg, attr.startswith('__i'), attr.startswith('__r'))

def add_operator_func(attr, algorithm, inplace, reverse):
# Wrapper for the function call
def op_wrapper(self, other):
# Get the result variable to know what to call the output
result_info = lhs_info()
# Pass off to helper
return _do_operation(algorithm, self, other, result_info,
inplace, reverse)
op_wrapper.__name__ = attr
setattr(Workspace, attr, op_wrapper)

# Prefix for temporary objects within workspace binary operations
_binary_op_prefix = '__binary_tmp'
# Prefix for temporary objects within workspace operations
_workspace_op_prefix = '__python_op_tmp'
# A list of temporary workspaces created by algebraic operations
_binary_op_tmps = []
_workspace_op_tmps = []

def _do_operation(op, self, rhs, lhs_vars, inplace, reverse):
def _do_binary_operation(op, self, rhs, lhs_vars, inplace, reverse):
"""
Perform the given binary operation
Expand All @@ -59,7 +67,7 @@ def _do_operation(op, self, rhs, lhs_vars, inplace, reverse):
@param reverse True if the reverse operator was called, i.e. 3 + a calls __radd__
"""
global _binary_op_tmps
global _workspace_op_tmps
#
if lhs_vars[0] > 0:
# Assume the first and clear the temporaries as this
Expand All @@ -72,19 +80,85 @@ def _do_operation(op, self, rhs, lhs_vars, inplace, reverse):
else:
# Give it a temporary name and keep track of it
clear_tmps = False
output_name = _binary_op_prefix + str(len(_binary_op_tmps))
_binary_op_tmps.append(output_name)
output_name = _workspace_op_prefix + str(len(_workspace_op_tmps))
_workspace_op_tmps.append(output_name)

# Do the operation
resultws = _perform_binary_op(self,rhs, op, output_name, inplace, reverse)
resultws = _performBinaryOp(self,rhs, op, output_name, inplace, reverse)

if clear_tmps:
for name in _binary_op_tmps:
for name in _workspace_op_tmps:
if name in _ads and output_name != name:
del _ads[name]
_binary_op_tmps = []
_workspace_op_tmps = []

if inplace:
return self
else:
return resultws

#------------------------------------------------------------------------------
# Unary Ops
#------------------------------------------------------------------------------
def attach_unary_operators_to_workspace():
"""
Attaches the common unary operators
to the Workspace class
"""
def add_operator_func(attr, algorithm):
# Wrapper for the function call
def op_wrapper(self):
# Get the result variable to know what to call the output
result_info = lhs_info()
# Pass off to helper
return _do_unary_operation(algorithm, self, result_info)
op_wrapper.__name__ = attr
setattr(Workspace, attr, op_wrapper)
# Binary operations that workspaces are aware of
operations = {
'NotMD':'__invert__'
}
# Loop through and add each one in turn
for alg, attributes in operations.iteritems():
if type(attributes) == str: attributes = [attributes]
for attr in attributes:
add_operator_func(attr, alg)


def _do_unary_operation(op, self, lhs_vars):
"""
Perform the unary operation
@param op :: name of the algorithm to run
@param self :: The object that this operation was called on
@param lhs_vars :: is expected to be a tuple containing the number of lhs variables and
their names as the first and second element respectively
"""
global _workspace_op_tmps

if lhs_vars[0] > 0:
# Assume the first and clear the temporaries as this
# must be the final assignment
output_name = lhs_vars[1][0]
clear_tmps = True
else:
# Give it a temporary name and keep track of it
clear_tmps = False
output_name = _workspace_op_prefix + str(len(_workspace_op_tmps))
_workspace_op_tmps.append(output_name)

# Do the operation
alg = FrameworkManager.Instance().createAlgorithm(op)
alg.setPropertyValue("InputWorkspace", self.name())
alg.setPropertyValue("OutputWorkspace", output_name)
alg.execute()
resultws = _ads[output_name]

if clear_tmps:
for name in _workspace_op_tmps:
if name in _ads and output_name != name:
_ads.remove(name)
_workspace_op_tmps = []

return resultws

0 comments on commit 82ea85a

Please sign in to comment.