code: def computeOptimalCombination(self, iForecast_DF):
      lBaseNames = []
      for level in sorted(self.mStructure.keys()):
          for col in sorted(self.mStructure[level].keys()):
              lBaseNames.append(col)
      lBaseForecastNames = [
          str(col) + "_Forecast" for col in lBaseNames
      ]
      lBaseForecasts = iForecast_DF[lBaseForecastNames]
      # TODO : use linalg.solve here
      S = self.mSummingMatrix
      # print(S.shape);
      lInv = np.linalg.inv(S.T.dot(S))
      lOptimalForecasts = (
          S.dot(lInv).dot(S.T).dot(lBaseForecasts.values.T)
      )
      # print(lBaseForecasts.shape);
      # print(lOptimalForecasts.shape);
      lOptimalNames = [
          (str(col) + "_OC_Forecast") for col in lBaseNames
      ]
      df = pd.DataFrame(lOptimalForecasts.T)
      df.columns = lOptimalNames
      lForecast_DF_OC = pd.concat([iForecast_DF, df], axis=1)
  
      # print(lForecast_DF_OC.head());
      # print(lForecast_DF_OC.tail());
      return lForecast_DF_OC
  
imports: import pandas
  import numpy
  from ..None import ForecastEngine
  from .None import Options
  from .None import Perf
  from .None import Utils
  from .None import Plots
  import time
label_desc: Use image node_id 25 for calling the cSignalHierarchy obj's underlying member method code with example usage: obj.computeOptimalCombination(iForecast_DF) and returns: lForecast_DF_OC