Source code for pwrs.core.i2e_data

# Copyright (c) 1996-2016, Power Systems Engineering Research Center (PSERC) by Ray Zimmerman, PSERC Cornell
# Modifications Copyright (c) 2026, Liangyu Zhang
# SPDX-License-Identifier: BSD-3-Clause

from typing import Any

import numpy as np
from scipy import sparse

from .get_reorder import get_reorder
from .set_reorder import set_reorder


def _state(value: Any) -> str:
    if isinstance(value, str):
        return value
    arr = np.asarray(value)
    if arr.size == 0:
        return ""
    return str(arr.reshape(-1)[0])


def _dim_size(value: Any, dim: int) -> int:
    axis = dim - 1
    if sparse.issparse(value):
        if axis > 1:
            raise ValueError("i2e_data: sparse matrices only support dimensions 1 and 2")
        return value.shape[axis]
    arr = np.asarray(value, dtype=object if isinstance(value, list) else None)
    if arr.ndim == 0:
        return 1
    if axis >= arr.ndim:
        return 1
    return arr.shape[axis]


def _concat(parts: list[Any], dim: int) -> Any:
    if not parts:
        return np.array([])
    first = parts[0]
    if sparse.issparse(first):
        return sparse.vstack(parts) if dim == 1 else sparse.hstack(parts)
    return np.concatenate(parts, axis=dim - 1)


[docs] def i2e_data(mpc, val, oldval, ordering, dim=1): """Reorder arbitrary data from internal to external indexing. Uses the ordering metadata stored by ``ext2int`` to map internal-order data back into the external layout, optionally filling into a previously saved external-order template ``oldval``. Parameters ---------- mpc : dict MATPOWER case struct in internal order, with ``order`` metadata. val : Any Internal-order data to map back to external ordering. oldval : Any External-order template value to receive the reordered data. ordering : str or sequence MATPOWER ordering descriptor. dim : int, optional One-based dimension along which to reorder. nargout : int, optional MATLAB compatibility flag. Returns ------- Any Value mapped back to external ordering. """ if "order" not in mpc: raise ValueError( "i2e_data: mpc does not have the 'order' field required for conversion back to external numbering." ) o = mpc["order"] if _state(o["state"]) != "i": raise ValueError("i2e_data: mpc does not appear to be in internal order") dim = int(np.asarray(dim).reshape(-1)[0]) if isinstance(ordering, str): if ordering == "gen": v = get_reorder(val, o[ordering]["e2i"], dim) else: v = val return set_reorder(oldval, v, o[ordering]["status"]["on"], dim) be = 0 bi = 0 parts: list[Any] = [] for item in ordering: ne = _dim_size(o["ext"][item], 1) ni = _dim_size(mpc[item], 1) v = get_reorder(val, np.arange(bi + 1, bi + ni + 1), dim) oldv = get_reorder(oldval, np.arange(be + 1, be + ne + 1), dim) parts.append(i2e_data(mpc, v, oldv, item, dim)) be += ne bi += ni ni = _dim_size(val, dim) if ni > bi: parts.append(get_reorder(val, np.arange(bi + 1, ni + 1), dim)) return _concat(parts, dim)