code: def test_raf_form_objective():
      """Tests ReconcileAdditiveForecasts _form_objective"""
      # variables
      levels = [[3], [2, 3, 3]]
      tree = HierarchicalRelationship(levels)
      m = tree.num_nodes
      n = 150
      transform_variable = cp.Variable((m, m))
      Ya = 100 * np.random.rand(m, n)
      Ya = tree.bottom_up_transform @ Ya  # makes values consistent
      Yf = Ya + np.random.rand(m, n)  # adds forecast error
      Yf[0] = Ya[0]  # makes one forecast have zero error
      transform_matrix = np.eye(m) + np.random.rand(m, m)
      # derived variables
      err = np.nanmedian(np.abs(Ya - Yf) / np.abs(Ya), axis=1)
      weight_err = np.diag(err)
      weight_err *= np.sqrt(m) / np.linalg.norm(weight_err)
  
      inv_err = err.copy()
      inv_err[np.where(inv_err == 0)] = np.min(
          inv_err[np.where(inv_err > 0)]
      )  # Sets zeros to minimum value above zero
      weight_inverr = np.diag(1 / inv_err)
      weight_inverr *= np.sqrt(m) / np.linalg.norm(weight_inverr)
  
      residuals = Ya - Yf
      cov = residuals @ residuals.T / residuals.shape[1]
  
      # covariance is None, default weights "MedAPE", "InverseMedAPE"
      raf = ReconcileAdditiveForecasts()
      raf.weight_adj = np.repeat(
          2, m
      )  # will be normalized, equivalent to np.repeat(1, m)
      raf.weight_bias = "InverseMedAPE"
      raf.weight_train = "MedAPE"
      raf.weight_var = "InverseMedAPE"
      obj = raf._form_objective(
          Yf=Yf,
          Ya=Ya,
          transform_variable=transform_variable,
          covariance=None,
      )
      assert_equal(
          raf.objective_weights,
          {
              "weight_adj": np.eye(m),
              "weight_bias": weight_inverr,
              "weight_train": weight_err,
              "weight_var": weight_inverr,
              "covariance": None,
          },
      )
      assert raf.objective_fn(None) is None
      assert (
          raf.objective_fn(transform_matrix)["var"] == 0.0
      )  # variance=0.0 when covariance is None
      assert obj.is_dcp()
      assert (
          len(obj.constants()) == 20
      )  # lams, weights, other constants
  
      # "identity" covariance
      raf = ReconcileAdditiveForecasts()
      raf.weight_adj = "MedAPE"
      obj = raf._form_objective(
          Yf=Yf,
          Ya=Ya,
          transform_variable=transform_variable,
          covariance="identity",
      )
      assert_equal(
          raf.objective_weights,
          {
              "weight_adj": weight_err,
              "weight_bias": np.eye(m),
              "weight_train": np.eye(m),
              "weight_var": np.eye(m),
              "covariance": np.eye(m),
          },
      )
      assert raf.objective_fn(transform_matrix) == {
          "adj": 0.0,  # all the self.lam_* are 0.0
          "bias": 0.0,
          "train": 0.0,
          "var": 0.0,
          "total": 0.0,
      }
      assert len(obj.constants()) == 23  # now includes covariance term
  
      # "sample" covariance
      raf = ReconcileAdditiveForecasts()
      raf.lam_adj = 1.1
      raf.lam_bias = 2.2
      raf.lam_train = 3.3
      raf.lam_var = 4.4
      obj = raf._form_objective(
          Yf=Yf,
          Ya=Ya,
          transform_variable=transform_variable,
          covariance="sample",
      )
      assert obj.is_dcp()
      assert len(obj.constants()) == 23
      assert obj.constants()[0].value == raf.lam_adj
      assert obj.constants()[1].value == raf.lam_bias
      assert obj.constants()[2].value == raf.lam_train
      assert obj.constants()[3].value == raf.lam_var
      assert_equal(
          obj.constants()[4].value, raf.objective_weights["weight_adj"]
      )
      assert_equal(obj.constants()[5].value, Yf)
      assert_equal(obj.constants()[6].value, Yf)
      assert_equal(
          raf.objective_weights,
          {
              "weight_adj": np.eye(m),
              "weight_bias": np.eye(m),
              "weight_train": np.eye(m),
              "weight_var": np.eye(m),
              "covariance": cov,
          },
      )
      # Tests objective_fn value
      expected_adj = (
          raf.lam_adj
          * np.linalg.norm(
              raf.objective_weights["weight_adj"]
              @ (transform_matrix @ Yf - Yf)
          )
          ** 2
          / np.size(Yf)
      )
      expected_bias = (
          raf.lam_bias
          * np.linalg.norm(
              raf.objective_weights["weight_bias"]
              @ (transform_matrix @ Ya - Ya)
          )
          ** 2
          / np.size(Ya)
      )
      expected_train = (
          raf.lam_train
          * np.linalg.norm(
              raf.objective_weights["weight_train"]
              @ (transform_matrix @ Yf - Ya)
          )
          ** 2
          / np.size(Yf)
      )
      expected_var = (
          raf.lam_var
          * np.linalg.norm(
              raf.objective_weights["weight_var"]
              @ transform_matrix
              @ sqrtm(cov)
          )
          ** 2
          / m
      )
      assert_equal(
          raf.objective_fn(transform_matrix),
          {
              "adj": expected_adj,
              "bias": expected_bias,
              "train": expected_train,
              "var": expected_var,
              "total": expected_adj
              + expected_bias
              + expected_train
              + expected_var,
          },
      )
      assert_equal(
          raf.objective_fn(
              transform_matrix,
              forecast_matrix=Yf * 2,
              actual_matrix=Ya * 2,
          ),
          {
              "adj": 4 * expected_adj,
              "bias": 4 * expected_bias,
              "train": 4 * expected_train,
              "var": expected_var,
              "total": 4 * expected_adj
              + 4 * expected_bias
              + 4 * expected_train
              + expected_var,
          },
      )
      # Tests equivalence of variance formula with trace
      var_alternative = (
          raf.lam_var
          * np.trace(transform_matrix @ cov @ transform_matrix.T)
          / m
      )
      assert_equal(
          var_alternative, raf.objective_fn(transform_matrix)["var"]
      )
      # Tests objective value
      constraints = [
          transform_variable >= -1.0,
          transform_variable <= 1.0,
          tree.constraint_matrix @ transform_variable == 0,
      ]
      prob = cp.Problem(obj, constraints=constraints)
      with warnings.catch_warnings():
          warnings.simplefilter(
              "ignore", category=UserWarning
          )  # sometimes there is a warning about solver accuracy
          prob.solve(
              feastol=1e-5, reltol=1e-8, abstol=1e-5, verbose=True
          )
      assert_equal(
          prob.objective.value,
          raf.objective_fn(transform_variable.value)["total"],
      )
  
      with pytest.raises(
          ValueError,
          match="`covariance` not recognized. Provide a valid string in \\['identity', 'sample'\\] or a matrix.",
      ):
          raf = ReconcileAdditiveForecasts()
          raf._form_objective(
              Yf=Yf,
              Ya=Ya,
              transform_variable=transform_variable,
              covariance="unknown-covariance",
          )
  
imports: import math
  import os
  import warnings
  import cvxpy
  import numpy
  import pandas
  import pytest
  from scipy.linalg import sqrtm
  from sklearn.exceptions import NotFittedError
  from greykite.algo.reconcile.convex.reconcile_forecasts import ReconcileAdditiveForecasts
  from greykite.algo.reconcile.convex.reconcile_forecasts import TraceInfo
  from greykite.algo.reconcile.convex.reconcile_forecasts import apply_method_defaults
  from greykite.algo.reconcile.convex.reconcile_forecasts import evaluation_plot
  from greykite.algo.reconcile.convex.reconcile_forecasts import get_fit_params
  from greykite.algo.reconcile.convex.reconcile_forecasts import get_weight_matrix
  from greykite.algo.reconcile.hierarchical_relationship import HierarchicalRelationship
  from greykite.common.constants import TIME_COL
  from greykite.common.data_loader import DataLoader
  from greykite.common.evaluation import mean_absolute_percent_error
  from greykite.common.evaluation import median_absolute_percent_error
  from greykite.common.evaluation import root_mean_squared_error
  from greykite.common.python_utils import assert_equal
  from greykite.common.python_utils import reorder_columns
label_desc: Use image node_id 9 for calling a global function with example usage: test_raf_form_objective() without return types