//  [python]
def optimize_map(self, old_c_dict, ca_dict, cb_dict):
        """
        Optimize for the best C that satisfies C* = argmin sum |ca @ c - cb| + |c @ hl - hk|
        :param old_c_dict: (k, l) --> (MxM) Fmap dict
        :param ca_dict: data dictionary for each (k, l) pair
        :param cb_dict: data dictionary for each (k, l) pair
        :return: optimized Fmap dict.
        """
        all_keys = sorted(list(old_c_dict.keys()))
        num_frames = max(*[max(t) for t in all_keys]) + 1

        view_sizes = {}
        for fid in range(num_frames - 1):
            view_sizes[fid] = old_c_dict[(fid, fid + 1)].size(0)
            view_sizes[fid + 1] = old_c_dict[(fid, fid + 1)].size(1)
        var_sizes_T = np.cumsum([0] + [view_sizes[i] for i in range(num_frames)])

        cur_device = old_c_dict[all_keys[0]].device
        num_universe = max(view_sizes.values()) - self.hparams.num_v_sub
        consistent_weight = self.hparams.cycle_weight

        C_star = {k: v for k, v in old_c_dict.items()}
        C_init_scale = {k: torch.norm(v.flatten()) for k, v in C_star.items()}

        robust_kernel, _ = self.basis_net.get_robust_kernel()
        for iter_i in range(self.hparams.sync_iter):

            """
            1. Solve for {H} matrices, fixing {C}
            """

            h_rows = []
            for fid_i in range(num_frames):
                h_cols = []
                for fid_j in range(num_frames):
                    sum_matrices = [torch.zeros((view_sizes[fid_i], view_sizes[fid_j]), device=cur_device)]

                    if fid_i < fid_j:
                        if (fid_i, fid_j) in all_keys:
                            sum_matrices.append(-C_star[(fid_i, fid_j)])
                        if (fid_j, fid_i) in all_keys:
                            sum_matrices.append(-C_star[(fid_j, fid_i)].transpose(-1, -2))
                    elif fid_i == fid_j:
                        for fid_k in range(num_frames):
                            if (fid_i, fid_k) in all_keys:
                                sum_matrices.append(torch.eye(view_sizes[fid_i], device=cur_device))
                            if (fid_k, fid_i) in all_keys:
                                X_ji = C_star[(fid_k, fid_i)]
                                sum_matrices.append(X_ji.transpose(-1, -2) @ X_ji)

                    h_cols.append(sum(sum_matrices))
                h_rows.append(torch.cat(h_cols, dim=-1))

            full_h_matrix = torch.cat(h_rows, dim=0)

            # eigh will be in descending order.
            _, h_star = torch.linalg.eigh(full_h_matrix, UPLO='U')
            h_star = h_star[..., :num_universe]

            """
            2. Solve for {C} matrices, fixing {H}
            """
            change_scales = []
            for (mid, nid) in all_keys:
                C_ij_star = self.basis_net.solve_optimal_maps(
                    ca_dict[(mid, nid)], cb_dict[(mid, nid)],
                    robust_kernel=robust_kernel,
                    k_i=h_star[var_sizes_T[mid]: var_sizes_T[mid + 1]],
                    k_j=h_star[var_sizes_T[nid]: var_sizes_T[nid + 1]],
                    sqrt_mu=np.sqrt(consistent_weight),
                    c_init=C_star[(mid, nid)],
                )
                change_scale = torch.norm((C_ij_star - C_star[(mid, nid)]).flatten()) / C_init_scale[(mid, nid)]
                change_scales.append(change_scale.item())
                C_star[(mid, nid)] = C_ij_star

            rel_change = np.mean(change_scales)
            if rel_change < self.hparams.sync_converge_rel:
                break

        return C_star