def canonicalize(u1, u2, operator, &locator) # :yields: u11, u12, op1
      # nothing to do if u2 is already a non-composite unit
      return u1, u2, operator unless CompositeUnit === u2
      # canonicalize u2
      cu21, cu22, cop2 = canonicalize(u2.axes.first, u2.axes.last, u2.operator, &locator)
      # redistribute u1 with the canonicalized u2 axes cu21 and cu22 using the redistributed operators rop1 and rop2
      rop1, rop2 = redistribute_operators(operator, cop2)
      # yield canonicalize(u1, cu21, rop1, &locator)
      # the maximally reduced canonical form
      return u1.send(rop1, cu21), cu22, rop2
    end
def canonicalize(u1, u2, operator, &locator) # :yields: u11, u12, op1
      # nothing to do if u2 is already a non-composite unit
      return u1, u2, operator unless CompositeUnit === u2
      # canonicalize u2
      cu21, cu22, cop2 = canonicalize(u2.axes.first, u2.axes.last, u2.operator, &locator)
      # redistribute u1 with the canonicalized u2 axes cu21 and cu22 using the redistributed operators rop1 and rop2
      rop1, rop2 = redistribute_operators(operator, cop2)
      # yield canonicalize(u1, cu21, rop1, &locator)
      # the maximally reduced canonical form
      return u1.send(rop1, cu21), cu22, rop2
    end
Returns the canonical form of the given units u1 and u2 and operator +:*+ or +:/+ as an array consisting
 of a CompositeUnit, non-composite Unit and operator, e.g.:
   canonicalize(METER, SECOND * SECOND, :*) #=> [METER * SECOND, SECOND, :*]
   canonicalize(METER, SECOND / SECOND, :*) #=> [METER * SECOND, SECOND, :/]
   canonicalize(METER, SECOND * SECOND, :/) #=> [METER / SECOND, SECOND, :/]
   canonicalize(METER, SECOND / SECOND, :/) #=> [METER / SECOND, SECOND, :*]

 The locator block given to this method matches a CompositeUnit with arguments u11, u12 and op1.

 See also canonicalize_operators.