code: def solve(f, *symbols, **flags):
      r"""
      Algebraically solves equations and systems of equations.
  
      Explanation
      ===========
  
      Currently supported:
          - polynomial
          - transcendental
          - piecewise combinations of the above
          - systems of linear and polynomial equations
          - systems containing relational expressions
          - systems implied by undetermined coefficients
  
      Examples
      ========
  
      The default output varies according to the input and might
      be a list (possibly empty), a dictionary, a list of
      dictionaries or tuples, or an expression involving relationals.
      For specifics regarding different forms of output that may appear, see :ref:`solve_output`.
      Let it suffice here to say that to obtain a uniform output from
      `solve` use ``dict=True`` or ``set=True`` (see below).
  
          >>> from sympy import solve, Poly, Eq, Matrix, Symbol
          >>> from sympy.abc import x, y, z, a, b
  
      The expressions that are passed can be Expr, Equality, or Poly
      classes (or lists of the same); a Matrix is considered to be a
      list of all the elements of the matrix:
  
          >>> solve(x - 3, x)
          [3]
          >>> solve(Eq(x, 3), x)
          [3]
          >>> solve(Poly(x - 3), x)
          [3]
          >>> solve(Matrix([[x, x + y]]), x, y) == solve([x, x + y], x, y)
          True
  
      If no symbols are indicated to be of interest and the equation is
      univariate, a list of values is returned; otherwise, the keys in
      a dictionary will indicate which (of all the variables used in
      the expression(s)) variables and solutions were found:
  
          >>> solve(x**2 - 4)
          [-2, 2]
          >>> solve((x - a)*(y - b))
          [{a: x}, {b: y}]
          >>> solve([x - 3, y - 1])
          {x: 3, y: 1}
          >>> solve([x - 3, y**2 - 1])
          [{x: 3, y: -1}, {x: 3, y: 1}]
  
      If you pass symbols for which solutions are sought, the output will vary
      depending on the number of symbols you passed, whether you are passing
      a list of expressions or not, and whether a linear system was solved.
      Uniform output is attained by using ``dict=True`` or ``set=True``.
  
          >>> #### *** feel free to skip to the stars below *** ####
          >>> from sympy import TableForm
          >>> h = [None, ';|;'.join(['e', 's', 'solve(e, s)', 'solve(e, s, dict=True)',
          ... 'solve(e, s, set=True)']).split(';')]
          >>> t = []
          >>> for e, s in [
          ...         (x - y, y),
          ...         (x - y, [x, y]),
          ...         (x**2 - y, [x, y]),
          ...         ([x - 3, y -1], [x, y]),
          ...         ]:
          ...     how = [{}, dict(dict=True), dict(set=True)]
          ...     res = [solve(e, s, **f) for f in how]
          ...     t.append([e, '|', s, '|'] + [res[0], '|', res[1], '|', res[2]])
          ...
          >>> # ******************************************************* #
          >>> TableForm(t, headings=h, alignments="<")
          e              | s      | solve(e, s)  | solve(e, s, dict=True) | solve(e, s, set=True)
          ---------------------------------------------------------------------------------------
          x - y          | y      | [x]          | [{y: x}]               | ([y], {(x,)})
          x - y          | [x, y] | [(y, y)]     | [{x: y}]               | ([x, y], {(y, y)})
          x**2 - y       | [x, y] | [(x, x**2)]  | [{y: x**2}]            | ([x, y], {(x, x**2)})
          [x - 3, y - 1] | [x, y] | {x: 3, y: 1} | [{x: 3, y: 1}]         | ([x, y], {(3, 1)})
  
          * If any equation does not depend on the symbol(s) given, it will be
            eliminated from the equation set and an answer may be given
            implicitly in terms of variables that were not of interest:
  
              >>> solve([x - y, y - 3], x)
              {x: y}
  
      When you pass all but one of the free symbols, an attempt
      is made to find a single solution based on the method of
      undetermined coefficients. If it succeeds, a dictionary of values
      is returned. If you want an algebraic solutions for one
      or more of the symbols, pass the expression to be solved in a list:
  
          >>> e = a*x + b - 2*x - 3
          >>> solve(e, [a, b])
          {a: 2, b: 3}
          >>> solve([e], [a, b])
          {a: -b/x + (2*x + 3)/x}
  
      When there is no solution for any given symbol which will make all
      expressions zero, the empty list is returned (or an empty set in
      the tuple when ``set=True``):
  
          >>> from sympy import sqrt
          >>> solve(3, x)
          []
          >>> solve(x - 3, y)
          []
          >>> solve(sqrt(x) + 1, x, set=True)
          ([x], set())
  
      When an object other than a Symbol is given as a symbol, it is
      isolated algebraically and an implicit solution may be obtained.
      This is mostly provided as a convenience to save you from replacing
      the object with a Symbol and solving for that Symbol. It will only
      work if the specified object can be replaced with a Symbol using the
      subs method:
  
          >>> from sympy import exp, Function
          >>> f = Function('f')
  
          >>> solve(f(x) - x, f(x))
          [x]
          >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
          [x + f(x)]
          >>> solve(f(x).diff(x) - f(x) - x, f(x))
          [-x + Derivative(f(x), x)]
          >>> solve(x + exp(x)**2, exp(x), set=True)
          ([exp(x)], {(-sqrt(-x),), (sqrt(-x),)})
  
          >>> from sympy import Indexed, IndexedBase, Tuple
          >>> A = IndexedBase('A')
          >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1)
          >>> solve(eqs, eqs.atoms(Indexed))
          {A[1]: 1, A[2]: 2}
  
          * To solve for a function within a derivative, use :func:`~.dsolve`.
  
      To solve for a symbol implicitly, use implicit=True:
  
          >>> solve(x + exp(x), x)
          [-LambertW(1)]
          >>> solve(x + exp(x), x, implicit=True)
          [-exp(x)]
  
      It is possible to solve for anything in an expression that can be
      replaced with a symbol using :obj:`~sympy.core.basic.Basic.subs`:
  
          >>> solve(x + 2 + sqrt(3), x + 2)
          [-sqrt(3)]
          >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2)
          {y: -2 + sqrt(3), x + 2: -sqrt(3)}
  
          * Nothing heroic is done in this implicit solving so you may end up
            with a symbol still in the solution:
  
              >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y)
              >>> solve(eqs, y, x + 2)
              {y: -sqrt(3)/(x + 3), x + 2: -2*x/(x + 3) - 6/(x + 3) + sqrt(3)/(x + 3)}
              >>> solve(eqs, y*x, x)
              {x: -y - 4, x*y: -3*y - sqrt(3)}
  
          * If you attempt to solve for a number, remember that the number
            you have obtained does not necessarily mean that the value is
            equivalent to the expression obtained:
  
              >>> solve(sqrt(2) - 1, 1)
              [sqrt(2)]
              >>> solve(x - y + 1, 1)  # /!\ -1 is targeted, too
              [x/(y - 1)]
              >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)]
              [-x + y]
  
      **Additional Examples**
  
      ``solve()`` with check=True (default) will run through the symbol tags to
      eliminate unwanted solutions. If no assumptions are included, all possible
      solutions will be returned:
  
          >>> x = Symbol("x")
          >>> solve(x**2 - 1)
          [-1, 1]
  
      By setting the ``positive`` flag, only one solution will be returned:
  
          >>> pos = Symbol("pos", positive=True)
          >>> solve(pos**2 - 1)
          [1]
  
      When the solutions are checked, those that make any denominator zero
      are automatically excluded. If you do not want to exclude such solutions,
      then use the check=False option:
  
          >>> from sympy import sin, limit
          >>> solve(sin(x)/x)  # 0 is excluded
          [pi]
  
      If ``check=False``, then a solution to the numerator being zero is found
      but the value of $x = 0$ is a spurious solution since $\sin(x)/x$ has the well
      known limit (without discontinuity) of 1 at $x = 0$:
  
          >>> solve(sin(x)/x, check=False)
          [0, pi]
  
      In the following case, however, the limit exists and is equal to the
      value of $x = 0$ that is excluded when check=True:
  
          >>> eq = x**2*(1/x - z**2/x)
          >>> solve(eq, x)
          []
          >>> solve(eq, x, check=False)
          [0]
          >>> limit(eq, x, 0, '-')
          0
          >>> limit(eq, x, 0, '+')
          0
  
      **Solving Relationships**
  
      When one or more expressions passed to ``solve`` is a relational,
      a relational result is returned (and the ``dict`` and ``set`` flags
      are ignored):
  
          >>> solve(x < 3)
          (-oo < x) & (x < 3)
          >>> solve([x < 3, x**2 > 4], x)
          ((-oo < x) & (x < -2)) | ((2 < x) & (x < 3))
          >>> solve([x + y - 3, x > 3], x)
          (3 < x) & (x < oo) & Eq(x, 3 - y)
  
      Although checking of assumptions on symbols in relationals
      is not done, setting assumptions will affect how certain
      relationals might automatically simplify:
  
          >>> solve(x**2 > 4)
          ((-oo < x) & (x < -2)) | ((2 < x) & (x < oo))
  
          >>> r = Symbol('r', real=True)
          >>> solve(r**2 > 4)
          (2 < r) | (r < -2)
  
      There is currently no algorithm in SymPy that allows you to use
      relationships to resolve more than one variable. So the following
      does not determine that ``q < 0`` (and trying to solve for ``r``
      and ``q`` will raise an error):
  
          >>> from sympy import symbols
          >>> r, q = symbols('r, q', real=True)
          >>> solve([r + q - 3, r > 3], r)
          (3 < r) & Eq(r, 3 - q)
  
      You can directly call the routine that ``solve`` calls
      when it encounters a relational: :func:`~.reduce_inequalities`.
      It treats Expr like Equality.
  
          >>> from sympy import reduce_inequalities
          >>> reduce_inequalities([x**2 - 4])
          Eq(x, -2) | Eq(x, 2)
  
      If each relationship contains only one symbol of interest,
      the expressions can be processed for multiple symbols:
  
          >>> reduce_inequalities([0 <= x  - 1, y < 3], [x, y])
          (-oo < y) & (1 <= x) & (x < oo) & (y < 3)
  
      But an error is raised if any relationship has more than one
      symbol of interest:
  
          >>> reduce_inequalities([0 <= x*y  - 1, y < 3], [x, y])
          Traceback (most recent call last):
          ...
          NotImplementedError:
          inequality has more than one symbol of interest.
  
      **Disabling High-Order Explicit Solutions**
  
      When solving polynomial expressions, you might not want explicit solutions
      (which can be quite long). If the expression is univariate, ``CRootOf``
      instances will be returned instead:
  
          >>> solve(x**3 - x + 1)
          [-1/((-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)) -
          (-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3,
          -(-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3 -
          1/((-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)),
          -(3*sqrt(69)/2 + 27/2)**(1/3)/3 -
          1/(3*sqrt(69)/2 + 27/2)**(1/3)]
          >>> solve(x**3 - x + 1, cubics=False)
          [CRootOf(x**3 - x + 1, 0),
           CRootOf(x**3 - x + 1, 1),
           CRootOf(x**3 - x + 1, 2)]
  
      If the expression is multivariate, no solution might be returned:
  
          >>> solve(x**3 - x + a, x, cubics=False)
          []
  
      Sometimes solutions will be obtained even when a flag is False because the
      expression could be factored. In the following example, the equation can
      be factored as the product of a linear and a quadratic factor so explicit
      solutions (which did not require solving a cubic expression) are obtained:
  
          >>> eq = x**3 + 3*x**2 + x - 1
          >>> solve(eq, cubics=False)
          [-1, -1 + sqrt(2), -sqrt(2) - 1]
  
      **Solving Equations Involving Radicals**
  
      Because of SymPy's use of the principle root, some solutions
      to radical equations will be missed unless check=False:
  
          >>> from sympy import root
          >>> eq = root(x**3 - 3*x**2, 3) + 1 - x
          >>> solve(eq)
          []
          >>> solve(eq, check=False)
          [1/3]
  
      In the above example, there is only a single solution to the
      equation. Other expressions will yield spurious roots which
      must be checked manually; roots which give a negative argument
      to odd-powered radicals will also need special checking:
  
          >>> from sympy import real_root, S
          >>> eq = root(x, 3) - root(x, 5) + S(1)/7
          >>> solve(eq)  # this gives 2 solutions but misses a 3rd
          [CRootOf(7*x**5 - 7*x**3 + 1, 1)**15,
          CRootOf(7*x**5 - 7*x**3 + 1, 2)**15]
          >>> sol = solve(eq, check=False)
          >>> [abs(eq.subs(x,i).n(2)) for i in sol]
          [0.48, 0.e-110, 0.e-110, 0.052, 0.052]
  
      The first solution is negative so ``real_root`` must be used to see that it
      satisfies the expression:
  
          >>> abs(real_root(eq.subs(x, sol[0])).n(2))
          0.e-110
  
      If the roots of the equation are not real then more care will be
      necessary to find the roots, especially for higher order equations.
      Consider the following expression:
  
          >>> expr = root(x, 3) - root(x, 5)
  
      We will construct a known value for this expression at x = 3 by selecting
      the 1-th root for each radical:
  
          >>> expr1 = root(x, 3, 1) - root(x, 5, 1)
          >>> v = expr1.subs(x, -3)
  
      The ``solve`` function is unable to find any exact roots to this equation:
  
          >>> eq = Eq(expr, v); eq1 = Eq(expr1, v)
          >>> solve(eq, check=False), solve(eq1, check=False)
          ([], [])
  
      The function ``unrad``, however, can be used to get a form of the equation
      for which numerical roots can be found:
  
          >>> from sympy.solvers.solvers import unrad
          >>> from sympy import nroots
          >>> e, (p, cov) = unrad(eq)
          >>> pvals = nroots(e)
          >>> inversion = solve(cov, x)[0]
          >>> xvals = [inversion.subs(p, i) for i in pvals]
  
      Although ``eq`` or ``eq1`` could have been used to find ``xvals``, the
      solution can only be verified with ``expr1``:
  
          >>> z = expr - v
          >>> [xi.n(chop=1e-9) for xi in xvals if abs(z.subs(x, xi).n()) < 1e-9]
          []
          >>> z1 = expr1 - v
          >>> [xi.n(chop=1e-9) for xi in xvals if abs(z1.subs(x, xi).n()) < 1e-9]
          [-3.0]
  
      Parameters
      ==========
  
      f :
          - a single Expr or Poly that must be zero
          - an Equality
          - a Relational expression
          - a Boolean
          - iterable of one or more of the above
  
      symbols : (object(s) to solve for) specified as
          - none given (other non-numeric objects will be used)
          - single symbol
          - denested list of symbols
            (e.g., ``solve(f, x, y)``)
          - ordered iterable of symbols
            (e.g., ``solve(f, [x, y])``)
  
      flags :
          dict=True (default is False)
              Return list (perhaps empty) of solution mappings.
          set=True (default is False)
              Return list of symbols and set of tuple(s) of solution(s).
          exclude=[] (default)
              Do not try to solve for any of the free symbols in exclude;
              if expressions are given, the free symbols in them will
              be extracted automatically.
          check=True (default)
              If False, do not do any testing of solutions. This can be
              useful if you want to include solutions that make any
              denominator zero.
          numerical=True (default)
              Do a fast numerical check if *f* has only one symbol.
          minimal=True (default is False)
              A very fast, minimal testing.
          warn=True (default is False)
              Show a warning if ``checksol()`` could not conclude.
          simplify=True (default)
              Simplify all but polynomials of order 3 or greater before
              returning them and (if check is not False) use the
              general simplify function on the solutions and the
              expression obtained when they are substituted into the
              function which should be zero.
          force=True (default is False)
              Make positive all symbols without assumptions regarding sign.
          rational=True (default)
              Recast Floats as Rational; if this option is not used, the
              system containing Floats may fail to solve because of issues
              with polys. If rational=None, Floats will be recast as
              rationals but the answer will be recast as Floats. If the
              flag is False then nothing will be done to the Floats.
          manual=True (default is False)
              Do not use the polys/matrix method to solve a system of
              equations, solve them one at a time as you might "manually."
          implicit=True (default is False)
              Allows ``solve`` to return a solution for a pattern in terms of
              other functions that contain that pattern; this is only
              needed if the pattern is inside of some invertible function
              like cos, exp, ect.
          particular=True (default is False)
              Instructs ``solve`` to try to find a particular solution to
              a linear system with as many zeros as possible; this is very
              expensive.
          quick=True (default is False; ``particular`` must be True)
              Selects a fast heuristic to find a solution with many zeros
              whereas a value of False uses the very slow method guaranteed
              to find the largest number of zeros possible.
          cubics=True (default)
              Return explicit solutions when cubic expressions are encountered.
              When False, quartics and quintics are disabled, too.
          quartics=True (default)
              Return explicit solutions when quartic expressions are encountered.
              When False, quintics are disabled, too.
          quintics=True (default)
              Return explicit solutions (if possible) when quintic expressions
              are encountered.
  
      See Also
      ========
  
      rsolve: For solving recurrence relationships
      dsolve: For solving differential equations
  
      """
      from .inequalities import reduce_inequalities
  
      # checking/recording flags
      ###########################################################################
  
      # set solver types explicitly; as soon as one is False
      # all the rest will be False
      hints = ("cubics", "quartics", "quintics")
      default = True
      for k in hints:
          default = flags.setdefault(k, bool(flags.get(k, default)))
  
      # allow solution to contain symbol if True:
      implicit = flags.get("implicit", False)
  
      # record desire to see warnings
      warn = flags.get("warn", False)
  
      # this flag will be needed for quick exits below, so record
      # now -- but don't record `dict` yet since it might change
      as_set = flags.get("set", False)
  
      # keeping track of how f was passed
      bare_f = not iterable(f)
  
      # check flag usage for particular/quick which should only be used
      # with systems of equations
      if flags.get("quick", None) is not None:
          if not flags.get("particular", None):
              raise ValueError(
                  "when using `quick`, `particular` should be True"
              )
      if flags.get("particular", False) and bare_f:
          raise ValueError(
              filldedent(
                  """
              The 'particular/quick' flag is usually used with systems of
              equations. Either pass your equation in a list or
              consider using a solver like `diophantine` if you are
              looking for a solution in integers."""
              )
          )
  
      # sympify everything, creating list of expressions and list of symbols
      ###########################################################################
  
      def _sympified_list(w):
          return list(map(sympify, w if iterable(w) else [w]))
  
      f, symbols = (_sympified_list(w) for w in [f, symbols])
  
      # preprocess symbol(s)
      ###########################################################################
  
      ordered_symbols = (
          None  # were the symbols in a well defined order?
      )
      if not symbols:
          # get symbols from equations
          symbols = set().union(*[fi.free_symbols for fi in f])
          if len(symbols) < len(f):
              for fi in f:
                  pot = preorder_traversal(fi)
                  for p in pot:
                      if isinstance(p, AppliedUndef):
                          if not as_set:
                              flags[
                                  "dict"
                              ] = True  # better show symbols
                          symbols.add(p)
                          pot.skip()  # don't go any deeper
          ordered_symbols = False
          symbols = list(ordered(symbols))  # to make it canonical
      else:
          if len(symbols) == 1 and iterable(symbols[0]):
              symbols = symbols[0]
          ordered_symbols = symbols and is_sequence(
              symbols, include=GeneratorType
          )
          _symbols = list(uniq(symbols))
          if len(_symbols) != len(symbols):
              ordered_symbols = False
              symbols = list(ordered(symbols))
          else:
              symbols = _symbols
  
      # check for duplicates
      if len(symbols) != len(set(symbols)):
          raise ValueError("duplicate symbols given")
      # remove those not of interest
      exclude = flags.pop("exclude", set())
      if exclude:
          if isinstance(exclude, Expr):
              exclude = [exclude]
          exclude = set().union(
              *[e.free_symbols for e in sympify(exclude)]
          )
          symbols = [s for s in symbols if s not in exclude]
  
      # preprocess equation(s)
      ###########################################################################
  
      # automatically ignore True values
      if isinstance(f, list):
          f = [s for s in f if s is not S.true]
  
      # handle canonicalization of equation types
      for i, fi in enumerate(f):
          if isinstance(fi, (Eq, Ne)):
              if "ImmutableDenseMatrix" in [
                  type(a).__name__ for a in fi.args
              ]:
                  fi = fi.lhs - fi.rhs
              else:
                  L, R = fi.args
                  if isinstance(R, BooleanAtom):
                      L, R = R, L
                  if isinstance(L, BooleanAtom):
                      if isinstance(fi, Ne):
                          L = ~L
                      if R.is_Relational:
                          fi = ~R if L is S.false else R
                      elif R.is_Symbol:
                          return L
                      elif R.is_Boolean and (~R).is_Symbol:
                          return ~L
                      else:
                          raise NotImplementedError(
                              filldedent(
                                  """
                              Unanticipated argument of Eq when other arg
                              is True or False.
                          """
                              )
                          )
                  elif isinstance(fi, Eq):
                      fi = Add(fi.lhs, -fi.rhs, evaluate=False)
              f[i] = fi
  
          # *** dispatch and handle as a system of relationals
          # **************************************************
          if fi.is_Relational:
              if len(symbols) != 1:
                  raise ValueError(
                      "can only solve for one symbol at a time"
                  )
              if warn and symbols[0].assumptions0:
                  warnings.warn(
                      filldedent(
                          """
                      \tWarning: assumptions about variable '%s' are
                      not handled currently."""
                          % symbols[0]
                      )
                  )
              return reduce_inequalities(f, symbols=symbols)
  
          # convert Poly to expression
          if isinstance(fi, Poly):
              f[i] = fi.as_expr()
  
          # rewrite hyperbolics in terms of exp if they have symbols of
          # interest
          f[i] = f[i].replace(
              lambda w: isinstance(w, HyperbolicFunction)
              and w.has_free(*symbols),
              lambda w: w.rewrite(exp),
          )
  
          # if we have a Matrix, we need to iterate over its elements again
          if f[i].is_Matrix:
              bare_f = False
              f.extend(list(f[i]))
              f[i] = S.Zero
  
          # if we can split it into real and imaginary parts then do so
          freei = f[i].free_symbols
          if freei and all(
              s.is_extended_real or s.is_imaginary for s in freei
          ):
              fr, fi = f[i].as_real_imag()
              # accept as long as new re, im, arg or atan2 are not introduced
              had = f[i].atoms(re, im, arg, atan2)
              if (
                  fr
                  and fi
                  and fr != fi
                  and not any(
                      i.atoms(re, im, arg, atan2) - had
                      for i in (fr, fi)
                  )
              ):
                  if bare_f:
                      bare_f = False
                  f[i : i + 1] = [fr, fi]
  
      # real/imag handling -----------------------------
      if any(isinstance(fi, (bool, BooleanAtom)) for fi in f):
          if as_set:
              return [], set()
          return []
  
      for i, fi in enumerate(f):
          # Abs
          while True:
              was = fi
              fi = fi.replace(
                  Abs,
                  lambda arg: separatevars(Abs(arg)).rewrite(Piecewise)
                  if arg.has(*symbols)
                  else Abs(arg),
              )
              if was == fi:
                  break
  
          for e in fi.find(Abs):
              if e.has(*symbols):
                  raise NotImplementedError(
                      "solving %s when the argument "
                      "is not real or imaginary." % e
                  )
  
          # arg
          fi = fi.replace(
              arg, lambda a: arg(a).rewrite(atan2).rewrite(atan)
          )
  
          # save changes
          f[i] = fi
  
      # see if re(s) or im(s) appear
      freim = [fi for fi in f if fi.has(re, im)]
      if freim:
          irf = []
          for s in symbols:
              if s.is_real or s.is_imaginary:
                  continue  # neither re(x) nor im(x) will appear
              # if re(s) or im(s) appear, the auxiliary equation must be present
              if any(fi.has(re(s), im(s)) for fi in freim):
                  irf.append((s, re(s) + S.ImaginaryUnit * im(s)))
          if irf:
              for s, rhs in irf:
                  f = [fi.xreplace({s: rhs}) for fi in f] + [s - rhs]
                  symbols.extend([re(s), im(s)])
              if bare_f:
                  bare_f = False
              flags["dict"] = True
      # end of real/imag handling  -----------------------------
  
      # we can solve for non-symbol entities by replacing them with Dummy symbols
      f, symbols, swap_sym = recast_to_symbols(f, symbols)
      # this set of symbols (perhaps recast) is needed below
      symset = set(symbols)
  
      # get rid of equations that have no symbols of interest; we don't
      # try to solve them because the user didn't ask and they might be
      # hard to solve; this means that solutions may be given in terms
      # of the eliminated equations e.g. solve((x-y, y-3), x) -> {x: y}
      newf = []
      for fi in f:
          # let the solver handle equations that..
          # - have no symbols but are expressions
          # - have symbols of interest
          # - have no symbols of interest but are constant
          # but when an expression is not constant and has no symbols of
          # interest, it can't change what we obtain for a solution from
          # the remaining equations so we don't include it; and if it's
          # zero it can be removed and if it's not zero, there is no
          # solution for the equation set as a whole
          #
          # The reason for doing this filtering is to allow an answer
          # to be obtained to queries like solve((x - y, y), x); without
          # this mod the return value is []
          ok = False
          if fi.free_symbols & symset:
              ok = True
          else:
              if fi.is_number:
                  if fi.is_Number:
                      if fi.is_zero:
                          continue
                      return []
                  ok = True
              else:
                  if fi.is_constant():
                      ok = True
          if ok:
              newf.append(fi)
      if not newf:
          if as_set:
              return symbols, set()
          return []
      f = newf
      del newf
  
      # mask off any Object that we aren't going to invert: Derivative,
      # Integral, etc... so that solving for anything that they contain will
      # give an implicit solution
      seen = set()
      non_inverts = set()
      for fi in f:
          pot = preorder_traversal(fi)
          for p in pot:
              if not isinstance(p, Expr) or isinstance(p, Piecewise):
                  pass
              elif (
                  isinstance(p, bool)
                  or not p.args
                  or p in symset
                  or p.is_Add
                  or p.is_Mul
                  or p.is_Pow
                  and not implicit
                  or p.is_Function
                  and not implicit
              ) and p.func not in (re, im):
                  continue
              elif p not in seen:
                  seen.add(p)
                  if p.free_symbols & symset:
                      non_inverts.add(p)
                  else:
                      continue
              pot.skip()
      del seen
      non_inverts = dict(
          list(zip(non_inverts, [Dummy() for _ in non_inverts]))
      )
      f = [fi.subs(non_inverts) for fi in f]
  
      # Both xreplace and subs are needed below: xreplace to force substitution
      # inside Derivative, subs to handle non-straightforward substitutions
      non_inverts = [
          (v, k.xreplace(swap_sym).subs(swap_sym))
          for k, v in non_inverts.items()
      ]
  
      # rationalize Floats
      floats = False
      if flags.get("rational", True) is not False:
          for i, fi in enumerate(f):
              if fi.has(Float):
                  floats = True
                  f[i] = nsimplify(fi, rational=True)
  
      # capture any denominators before rewriting since
      # they may disappear after the rewrite, e.g. issue 14779
      flags["_denominators"] = _simple_dens(f[0], symbols)
  
      # Any embedded piecewise functions need to be brought out to the
      # top level so that the appropriate strategy gets selected.
      # However, this is necessary only if one of the piecewise
      # functions depends on one of the symbols we are solving for.
      def _has_piecewise(e):
          if e.is_Piecewise:
              return e.has(*symbols)
          return any(_has_piecewise(a) for a in e.args)
  
      for i, fi in enumerate(f):
          if _has_piecewise(fi):
              f[i] = piecewise_fold(fi)
  
      # expand angles of sums; in general, expand_trig will allow
      # more roots to be found but this is not a great solultion
      # to not returning a parametric solution, otherwise
      # many values can be returned that have a simple
      # relationship between values
      targs = {t for fi in f for t in fi.atoms(TrigonometricFunction)}
      if len(targs) > 1:
          add, other = sift(
              targs, lambda x: x.args[0].is_Add, binary=True
          )
          add, other = [
              [i for i in l if i.has_free(*symbols)]
              for l in (add, other)
          ]
          trep = {}
          for t in add:
              a = t.args[0]
              ind, dep = a.as_independent(*symbols)
              if dep in symbols or -dep in symbols:
                  # don't let expansion expand wrt anything in ind
                  n = Dummy() if not ind.is_Number else ind
                  trep[t] = TR10(t.func(dep + n)).xreplace({n: ind})
          if other and len(other) <= 2:
              base = (
                  gcd(*[i.args[0] for i in other])
                  if len(other) > 1
                  else other[0].args[0]
              )
              for i in other:
                  trep[i] = TR11(i, base)
          f = [fi.xreplace(trep) for fi in f]
  
      #
      # try to get a solution
      ###########################################################################
      if bare_f:
          solution = None
          if len(symbols) != 1:
              solution = _solve_undetermined(f[0], symbols, flags)
          if not solution:
              solution = _solve(f[0], *symbols, **flags)
      else:
          linear, solution = _solve_system(f, symbols, **flags)
      assert type(solution) is list
      assert not solution or type(solution[0]) is dict, solution
      #
      # postprocessing
      ###########################################################################
      # capture as_dict flag now (as_set already captured)
      as_dict = flags.get("dict", False)
  
      # define how solution will get unpacked
      tuple_format = lambda s: [
          tuple([i.get(x, x) for x in symbols]) for i in s
      ]
      if as_dict or as_set:
          unpack = None
      elif bare_f:
          if len(symbols) == 1:
              unpack = lambda s: [i[symbols[0]] for i in s]
          elif len(solution) == 1 and len(solution[0]) == len(symbols):
              # undetermined linear coeffs solution
              unpack = lambda s: s[0]
          elif ordered_symbols:
              unpack = tuple_format
          else:
              unpack = lambda s: s
      else:
          if solution:
              if linear and len(solution) == 1:
                  # if you want the tuple solution for the linear
                  # case, use `set=True`
                  unpack = lambda s: s[0]
              elif ordered_symbols:
                  unpack = tuple_format
              else:
                  unpack = lambda s: s
          else:
              unpack = None
  
      # Restore masked-off objects
      if non_inverts and type(solution) is list:
          solution = [
              {k: v.subs(non_inverts) for k, v in s.items()}
              for s in solution
          ]
  
      # Restore original "symbols" if a dictionary is returned.
      # This is not necessary for
      #   - the single univariate equation case
      #     since the symbol will have been removed from the solution;
      #   - the nonlinear poly_system since that only supports zero-dimensional
      #     systems and those results come back as a list
      #
      # ** unless there were Derivatives with the symbols, but those were handled
      #    above.
      if swap_sym:
          symbols = [swap_sym.get(k, k) for k in symbols]
          for i, sol in enumerate(solution):
              solution[i] = {
                  swap_sym.get(k, k): v.subs(swap_sym)
                  for k, v in sol.items()
              }
  
      # Get assumptions about symbols, to filter solutions.
      # Note that if assumptions about a solution can't be verified, it is still
      # returned.
      check = flags.get("check", True)
  
      # restore floats
      if floats and solution and flags.get("rational", None) is None:
          solution = nfloat(solution, exponent=False)
          # nfloat might reveal more duplicates
          solution = _remove_duplicate_solutions(solution)
  
      if check and solution:  # assumption checking
          warn = flags.get("warn", False)
          got_None = (
              []
          )  # solutions for which one or more symbols gave None
          no_False = []  # solutions for which no symbols gave False
          for sol in solution:
              a_None = False
              for symb, val in sol.items():
                  test = check_assumptions(val, **symb.assumptions0)
                  if test:
                      continue
                  if test is False:
                      break
                  a_None = True
              else:
                  no_False.append(sol)
                  if a_None:
                      got_None.append(sol)
  
          solution = no_False
          if warn and got_None:
              warnings.warn(
                  filldedent(
                      """
                  \tWarning: assumptions concerning following solution(s)
                  cannot be checked:"""
                      + "\n\t"
                      + ", ".join(str(s) for s in got_None)
                  )
              )
  
      #
      # done
      ###########################################################################
  
      if not solution:
          if as_set:
              return symbols, set()
          return []
  
      # make orderings canonical for list of dictionaries
      if not as_set:  # for set, no point in ordering
          solution = [{k: s[k] for k in ordered(s)} for s in solution]
          solution.sort(key=default_sort_key)
  
      if not (as_set or as_dict):
          return unpack(solution)
  
      if as_dict:
          return solution
  
      # set output: (symbols, {t1, t2, ...}) from list of dictionaries;
      # include all symbols for those that like a verbose solution
      # and to resolve any differences in dictionary keys.
      #
      # The set results can easily be used to make a verbose dict as
      #   k, v = solve(eqs, syms, set=True)
      #   sol = [dict(zip(k,i)) for i in v]
      #
      if ordered_symbols:
          k = symbols  # keep preferred order
      else:
          # just unify the symbols for which solutions were found
          k = list(
              ordered(set(flatten(tuple(i.keys()) for i in solution)))
          )
      return k, {tuple([s.get(ki, ki) for ki in k]) for s in solution}
  
imports: from __future__ import annotations
  from sympy.core import S, Add, Symbol, Dummy, Expr, Mul
  from sympy.core.assumptions import check_assumptions
  from sympy.core.exprtools import factor_terms
  from sympy.core.function import expand_mul, expand_log, Derivative, AppliedUndef, UndefinedFunction, nfloat, Function, expand_power_exp, _mexpand, expand, expand_func
  from sympy.core.logic import fuzzy_not
  from sympy.core.numbers import Float, Rational, _illegal
  from sympy.core.intfunc import integer_log, ilcm
  from sympy.core.power import Pow
  from sympy.core.relational import Eq, Ne
  from sympy.core.sorting import ordered, default_sort_key
  from sympy.core.sympify import sympify, _sympify
  from sympy.core.traversal import preorder_traversal
  from sympy.logic.boolalg import And, BooleanAtom
  from sympy.functions import log, exp, LambertW, cos, sin, tan, acos, asin, atan, Abs, re, im, arg, sqrt, atan2
  from sympy.functions.combinatorial.factorials import binomial
  from sympy.functions.elementary.hyperbolic import HyperbolicFunction
  from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise
  from sympy.functions.elementary.trigonometric import TrigonometricFunction
  from sympy.integrals.integrals import Integral
  from sympy.ntheory.factor_ import divisors
  from sympy.simplify import simplify, collect, powsimp, posify, powdenest, nsimplify, denom, logcombine, sqrtdenest, fraction, separatevars
  from sympy.simplify.sqrtdenest import sqrt_depth
  from sympy.simplify.fu import TR1, TR2i, TR10, TR11
  from sympy.strategies.rl import rebuild
  from sympy.matrices.exceptions import NonInvertibleMatrixError
  from sympy.matrices import Matrix, zeros
  from sympy.polys import roots, cancel, factor, Poly
  from sympy.polys.solvers import sympy_eqs_to_ring, solve_lin_sys
  from sympy.polys.polyerrors import GeneratorsNeeded, PolynomialError
  from sympy.polys.polytools import gcd
  from sympy.utilities.lambdify import lambdify
  from sympy.utilities.misc import filldedent, debugf
  from sympy.utilities.iterables import connected_components, generate_bell, uniq, iterable, is_sequence, subsets, flatten, sift
  from sympy.utilities.decorator import conserve_mpmath_dps
  from mpmath import findroot
  from sympy.solvers.polysys import solve_poly_system
  from types import GeneratorType
  from collections import defaultdict
  from itertools import combinations, product
  import warnings
  from sympy.solvers.bivariate import bivariate_type, _solve_lambert, _filtered_gens
label_desc: Use image node_id 6 for calling a global function with example usage: solve(f) and returns: k,  unknown, list, list, list, any, list, unpack, solution, reduce_inequalities, list,  set, symbols,  set, e, symbols,  set, list, L, unknown