Initializes required objects to generate symbolic math datasets.

  Produces token set, ExprOp instances, solve_op dictionary, encoders, and
  decoders needed to generate the algebra inverse dataset.

  Args:
    alphabet_size: How many possible variables there are. Max 52.
    digits: How many numerical digits to encode as tokens, "0" through
        str(digits-1), or None to encode no digits.
    functions: Defines special functions. A dict mapping human readable string
        names, like "log", "exp", "sin", "cos", etc., to single chars. Each
        function gets a unique token, like "L" for "log".
        WARNING, Make sure these tokens do not conflict with the list of
        possible variable names.

  Returns:
    AlgebraConfig instance holding all the objects listed above.

  Raises:
    ValueError: If `alphabet_size` is not in range [2, 52].

def math_dataset_init(alphabet_size=26, digits=None, functions=None):
  """Initializes required objects to generate symbolic math datasets.

  Produces token set, ExprOp instances, solve_op dictionary, encoders, and
  decoders needed to generate the algebra inverse dataset.

  Args:
    alphabet_size: How many possible variables there are. Max 52.
    digits: How many numerical digits to encode as tokens, "0" through
        str(digits-1), or None to encode no digits.
    functions: Defines special functions. A dict mapping human readable string
        names, like "log", "exp", "sin", "cos", etc., to single chars. Each
        function gets a unique token, like "L" for "log".
        WARNING, Make sure these tokens do not conflict with the list of
        possible variable names.

  Returns:
    AlgebraConfig instance holding all the objects listed above.

  Raises:
    ValueError: If `alphabet_size` is not in range [2, 52].
  """
  ops_list = ["+", "-", "*", "/"]
  ops = {
      "+": ExprOp("+", 0, True),
      "-": ExprOp("-", 0, False),
      "*": ExprOp("*", 1, True),
      "/": ExprOp("/", 1, False)
  }
  solve_ops = {
      "+l": lambda l, r, to: (l, ExprNode(to, r, ops["-"])),
      "+r": lambda l, r, to: (r, ExprNode(to, l, ops["-"])),
      "-l": lambda l, r, to: (l, ExprNode(to, r, ops["+"])),
      "-r": lambda l, r, to: (r, ExprNode(l, to, ops["-"])),
      "*l": lambda l, r, to: (l, ExprNode(to, r, ops["/"])),
      "*r": lambda l, r, to: (r, ExprNode(to, l, ops["/"])),
      "/l": lambda l, r, to: (l, ExprNode(to, r, ops["*"])),
      "/r": lambda l, r, to: (r, ExprNode(l, to, ops["/"])),
  }
  alphabet = (
      [six.int2byte(ord("a") + c).decode("utf-8") for c in range(26)] +
      [six.int2byte(ord("A") + c).decode("utf-8") for c in range(26)])
  if alphabet_size > 52:
    raise ValueError(
        "alphabet_size cannot be greater than 52. Got %s." % alphabet_size)
  if alphabet_size < 2:
    raise ValueError(
        "alphabet_size cannot be less than 2. Got %s." % alphabet_size)
  if digits is not None and not 1 <= digits <= 10:
    raise ValueError("digits cannot must be between 1 and 10. Got %s." % digits)
  vlist = alphabet[:alphabet_size]
  if digits is not None:
    dlist = [str(d) for d in range(digits)]
  else:
    dlist = []
  if functions is None:
    functions = {}
  flist = sorted(functions.values())
  pad = "_"
  tokens = [pad] + [":", "(", ")", "="] + ops_list + vlist + dlist + flist
  if len(tokens) != len(set(tokens)):
    raise ValueError("Duplicate token. Tokens: %s" % tokens)
  token_map = dict([(t, i) for i, t in enumerate(tokens)])

  def int_encoder(sequence):
    return [token_map[s] for s in sequence]

  def int_decoder(tensor_1d):
    return "".join([tokens[i] for i in tensor_1d])

  return AlgebraConfig(
      vlist=vlist,
      dlist=dlist,
      flist=flist,
      functions=functions,
      ops=ops,
      solve_ops=solve_ops,
      int_encoder=int_encoder,
      int_decoder=int_decoder)