An addition of new types in UFL triggered different FFC regression test code output on different buildbot platforms for optimized quadrature code.
I've tracked the problem to the following parts:
# In optimizedquadraturetransformer.py: def _math_function(self, operands, format_function): #print("Calling _math_function() of optimisedquadraturetransformer.") # TODO: Are these safety checks needed? ffc_assert(len(operands) == 1 and () in operands and len(operands) == 1, \ "MathFunctions expect one operand of function type: " + repr(operands)) # Use format function on value of operand. operand = operands for key, val in operand.items(): #new_val = create_symbol(format_function(str(val)), val.t) #new_val.base_expr = val #new_val.base_op = 1 # Add one operation for the math function. new_val = create_symbol(format_function, val.t, val, 1) # <----- HERE operand[key] = new_val return operand
- The above create_symbol call triggers construction of a Symbol with a lambda function as the variable instead of a string.
- In the repr construction in Symbol.__init__, the repr of the lambda function contains the address of the lambda function, which is arbitrary.
- In Expr.__lt__ (ffc, not ufl), the repr is used to compare two expressions.
- In Sum.expand(), variables are passed to sorted(), which in turn uses < for comparison.
The end result is that an arbitrary ordering is applied to terms in a sum when running with -O.
I have no idea how to fix this, but I'm pretty sure the proper solution involves not passing a function but a string to Symbol.