def single_op_to_python_command(op_name, num_args):
  """An implementation of the most popular ops from the MathQA dataset."""
  # See https://gitlab.cs.washington.edu/amini91/mathqa-categorization/
  # and specfically line 142 and following in new_DataStructure.py
  # for an implementation which covers more details.
  if op_name == 'add':
    return '{} + {}'.format(num_args[0], num_args[1])
  elif op_name == 'circle_arc':
    return '{} / 360 * math.pi * 2 * {}'.format(num_args[0], num_args[1])
  elif op_name == 'circle_area':
    return 'math.pi * {}**2'.format(num_args[0])
  elif op_name == 'circle_sector_area':
    return '{} / 360 * math.pi * ({}**2)'.format(num_args[1], num_args[0])
  elif op_name == 'circumface':
    return '2 * math.pi * {}'.format(num_args[0])
  elif op_name == 'choose':
    return 'scipy.special.comb({}, {})'.format(num_args[0], num_args[1])
  elif op_name == 'cosine':
    return 'math.cos({})'.format(num_args[0])
  elif op_name == 'cube_edge_by_volume':
    return '{}**(1 / 3)'.format(num_args[0])
  elif op_name == 'combined_work':
    return '1 / (min({}, 1 / {}) + min({}, 1 / {}))'.format(
        num_args[0], num_args[0], num_args[1], num_args[1])
  elif op_name == 'count_interval':
    return '{} - {} + 1'.format(num_args[0], num_args[1])
  elif op_name == 'diagonal':
    return 'math.sqrt({}**2 + {}**2)'.format(num_args[0], num_args[1])
  elif op_name == 'divide' or op_name == 'speed':
    # safe divide
    if num_args[1] != 0:
      return '{} / {}'.format(num_args[0], num_args[1])
    else:
      return '0'
  elif op_name == 'factorial':
    return 'math.factorial(min(15, int({})))'.format(num_args[0])
  elif op_name == 'floor':
    return 'math.floor({})'.format(num_args[0])
  elif op_name == 'find_work':
    return ('1 / (max(min({}, 1 / {}), min({}, 1 / {})) - min(min({}, 1 / {}), '
            'min({}, 1 / {})))').format(num_args[0], num_args[0], num_args[1],
                                        num_args[1], num_args[0], num_args[0],
                                        num_args[1], num_args[1])
  elif op_name == 'from_percent':
    return '{} / 100'.format(num_args[0])
  elif op_name == 'gain_percent':
    return '100 + {}'.format(num_args[0])
  elif op_name == 'gcd':
    return 'np.gcd(int({}), int({}))'.format(num_args[0], num_args[1])
  elif op_name == 'inverse':
    # safe inverse
    if num_args[0] != 0:
      return '1 / {}'.format(num_args[0])
    else:
      return '0'
  elif op_name == 'lcm':
    return 'scipy.lcm(int({}), int({}))'.format(num_args[0], num_args[1])
  elif op_name == 'log':
    return 'math.log(max(1e-5, {}), 2)'.format(num_args[0])
  elif op_name == 'loss_percent':
    return '100 - {}'.format(num_args[0])
  elif op_name == 'max':
    return 'max({},{})'.format(num_args[0], num_args[1])
  elif op_name == 'multiply':
    return '{} * {}'.format(num_args[0], num_args[1])
  elif op_name == 'negate_percent':
    return '100 - {}'.format(num_args[0])
  elif op_name == 'negate':
    return '-{}'.format(num_args[0])
  elif op_name == 'original_price_before_loss':
    return '{} * 100 / (100 + 1e-5 - {})  # original price before loss'.format(
        num_args[1], num_args[0])
  elif op_name == 'original_price_before_gain':
    return '{} * 100 / (100 + {})  # original_price_before gain'.format(
        num_args[1], num_args[0])
  elif op_name == 'permutation':
    return ('math.factorial(int(max({}, {}))) / math.factorial(int(max({}, {}) '
            '- min({}, {})))  # find all permutations').format(
                num_args[0], num_args[1], num_args[0], num_args[1], num_args[0],
                num_args[1])
  elif op_name == 'power':
    return '{}**min({}, 5)'.format(num_args[0], num_args[1])
  elif op_name == 'percent':
    return '{} / 100 * {}'.format(num_args[0], num_args[1])
  elif op_name == 'price_after_gain' or op_name == 'p_after_gain':
    return '(1 + {} / 100) * {}'.format(num_args[0], num_args[1])
  elif op_name == 'price_after_loss' or op_name == 'price_after_loss':
    return '(1 - {} / 100) * {}'.format(num_args[0], num_args[1])
  elif op_name == 'quadrilateral_area':
    return '{} * ({} + {}) / 2  # quadrilateral area'.format(
        num_args[0], num_args[1], num_args[2])
  elif op_name == 'reminder':
    return '{} % {}'.format(num_args[0], num_args[1])
  elif op_name == 'rectangle_area':
    return '{} * {}  # area of rectangle'.format(num_args[0], num_args[1])
  elif op_name == 'rectangle_perimeter':
    return '2 * ({} + {})  # perimetere of rectangle'.format(
        num_args[0], num_args[1])
  elif op_name == 'rhombus_area':
    return '{} * {} / 2'.format(num_args[0], num_args[1])
  elif op_name == 'sine':
    return 'math.sin({})'.format(num_args[0])
  elif op_name == 'sqrt':
    return 'math.sqrt(max(0, {}))'.format(num_args[0])
  elif op_name == 'subtract':
    return '{} - {}'.format(num_args[0], num_args[1])
  elif op_name == 'square_edge_by_perimeter':
    return '{} / 4. # square edge given perimeter'.format(num_args[0])
  elif op_name == 'square_edge_by_area':
    return 'math.sqrt({})  # square edge given area'.format(num_args[0])
  elif op_name == 'square_area':
    return '{}**2'.format(num_args[0])
  elif op_name == 'surface_cube':
    return '6 * {}**2  # surface of a cube'.format(num_args[0])
  elif op_name == 'surface_rectangular_prism':
    return '2 * ({} * {} + {} * {} + {} * {})  # surface of a rectangular prism'.format(
        num_args[0], num_args[1], num_args[0], num_args[2], num_args[1],
        num_args[2])
  elif op_name == 'semi_circle_perimiter':
    return 'math.pi * {} + 2 * {}  # perimeter of a semi-circle'.format(
        num_args[0], num_args[0])
  elif op_name == 'square_perimeter' or op_name == 'rhombus_perimeter':
    return '4 * {}'.format(num_args[0])
  elif op_name == 'surface_sphere':
    return '4 * math.pi * {}**2'.format(num_args[0])
  elif op_name == 'speed_ratio_steel_to_stream':
    return '({} + {}) / ({} - {})'.format(num_args[0], num_args[1], num_args[0],
                                          num_args[1])
  elif op_name == 'speed_in_still_water':
    return '{} + {} / 2'.format(num_args[0], num_args[1])
  elif op_name == 'stream_speed':
    return '{} - {} / 2'.format(num_args[0], num_args[1])
  elif op_name == 'trapezium_area':
    return '{} * ({} + {}) / 2'.format(num_args[0], num_args[1], num_args[2])
  elif op_name == 'triangle_area':
    return '{} * {} / 2'.format(num_args[0], num_args[1])
  elif op_name == 'triangle_perimeter':
    return '{} + {} + {}  # perimeter of a triangle'.format(
        num_args[0], num_args[1], num_args[2])
  elif op_name == 'triangle_area_three_edges':
    return ("(lambda s, a, b, c: math.sqrt(max(0, s * (s - a) * (s - b) * (s - "
            "c))))(({} + {} + {}) / 2, {}, {}, {})  # Heron's formula").format(
                num_args[0], num_args[1], num_args[2], num_args[0], num_args[1],
                num_args[2])
  elif op_name == 'union_prob':
    return '{} + {} - {}'.format(num_args[0], num_args[1], num_args[2])
  elif op_name == 'negate_prob':
    return '1 - {}'.format(num_args[0])
  elif op_name == 'volume_cube':
    return '{}**3'.format(num_args[0])
  elif op_name == 'volume_cone':
    return 'math.pi * {}**2 * {} / 3'.format(num_args[0], num_args[1])
  elif op_name == 'volume_cylinder':
    return 'math.pi * {}**2 * {}'.format(num_args[0], num_args[1])
  elif op_name == 'volume_rectangular_prism':
    return '{} * {} * {}'.format(num_args[0], num_args[1], num_args[2])
  elif op_name == 'volume_sphere':
    return '4 / 3 * math.pi * {}**3'.format(num_args[0])
An implementation of the most popular ops from the MathQA dataset.
trax/data/tf_inputs.py