docs: def to_generics(instruments, weights):
      """
      Map tradeable instruments to generics given weights and tradeable
      instrument holdings. This is solving the equation Ax = b where A is the
      weights, and b is the instrument holdings. When Ax = b has no solution we
      solve for x' such that Ax' is closest to b in the least squares sense with
      the additional constraint that sum(x') = sum(instruments).
  
      Scenarios with exact solutions and non exact solutions are depicted below
  
      +------------+-----+-----+ Instruments
      | contract   | CL1 | CL2 | ------------------------------------
      |------------+-----+-----| Scenario 1 | Scenario 2 | Scenario 3
      | CLX16      | 0.5 | 0   | 10         | 10         | 10
      | CLZ16      | 0.5 | 0.5 | 20         | 20         | 25
      | CLF17      | 0   | 0.5 | 10         | 11         | 11
      +------------+-----+-----+
  
      In scenario 1 the solution is given by x = [20, 20], in scenario 2 the
      solution is given by x = [19.5, 21.5], and in scenario 3 the solution is
      given by x = [22, 24].
  
      NOTE: Integer solutions are not guruanteed, as demonstrated above. This is
      intended for use with contract numbers but can also be used with notional
      amounts of contracts.
  
      Parameters
      ----------
      instruments: pandas.Series
          Series of tradeable instrument holdings where the index is the name of
          the tradeable instrument and the value is the number of that instrument
          held.
      weights: pandas.DataFrame or dict
          A pandas.DataFrame of loadings of generic contracts on tradeable
          instruments for a given date. The columns are generic instruments
          and the index is strings representing instrument names. If dict is
          given keys should be root generic, e.g. 'CL', and values should be
          pandas.DataFrames of loadings. The union of all indexes should be a
          superset of the instruments.index
  
      Returns
      -------
      A pandas.Series where the index is the generic and the value is the number
      of contracts, sorted by index.
  
      Examples
      --------
      >>> import pandas as pd
      >>> import mapping.mappings as mappings
      >>> wts = pd.DataFrame([[0.5, 0], [0.5, 0.5], [0, 0.5]],
      ...                    index=["CLX16", "CLZ16", "CLF17"],
      ...                    columns=["CL1", "CL2"])
      >>> instrs = pd.Series([10, 20, 10], index=["CLX16", "CLZ16", "CLF17"])
      >>> generics = mappings.to_generics(instrs, wts)
      """
      if not isinstance(weights, dict):
          weights = {"": weights}
  
      allocations = []
      unmapped_instr = instruments.index
      for key in weights:
          w = weights[key]
          # may not always have instrument holdings for a set of weights so allow
          # weights to be a superset of instruments, drop values where no
          # holdings
          winstrs = instruments.reindex(w.index).dropna()
          w = w.loc[winstrs.index]
          # drop generics where all weights for instruments on the genric are 0.
          # This avoids numerical rounding issues where solution has epsilon
          # weight on a generic
          w = w.loc[:, ~(w == 0).all(axis=0)]
  
          unmapped_instr = unmapped_instr.difference(winstrs.index)
  
          A = w.values
          b = winstrs.values
          x = cvxpy.Variable(A.shape[1])
          constrs = [CVX_SUM(x) == np.sum(b)]
          obj = cvxpy.Minimize(cvxpy.sum_squares(A * x - b))
          prob = cvxpy.Problem(obj, constrs)
          prob.solve()
  
          vals = np.array(x.value).squeeze()
          idx = w.columns.tolist()
          allocations.append(pd.Series(vals, index=idx))
  
      if len(unmapped_instr) > 0:
          raise KeyError("Unmapped instruments %s. weights must be a superset of"
                         " instruments" % unmapped_instr.tolist())
  
      allocations = pd.concat(allocations, axis=0)
      allocations = allocations.sort_index()
      return allocations