fn make_y_bus(baseMVA, bus, branch) {
    // constants
    nb = size(bus, 0);          // number of buses
    nl = size(branch, 0);       // number of lines

    // for each branch, compute the elements of the branch admittance matrix where
    //
    //      | If |   | Yff  Yft |   | Vf |
    //      |    | = |          | * |    |
    //      | It |   | Ytf  Ytt |   | Vt |
    //
    stat = slice(branch, [0], [BR_STATUS-1,BR_STATUS]);                    // ones at in-service branches
    Ys = stat ./ (slice(branch, [0], [BR_R-1,BR_R]) + c(0,1) * slice(branch, [0], [BR_X-1,BR_X]));  // series admittance
    Bc = stat .* slice(branch, [0], [BR_B-1,BR_B]);                           // line charging susceptance
    tap = ones(nl, 1);                              // default tap ratio = 1

    //i = find(branch(:, TAP));                       // indices of non-zero tap ratios
    //tap(i) = slice(branch, [0], [TAP-1,TAP]);               // assign non-zero tap ratios
    tap = tap .* exp(c(0,1)*pi/180 * slice(branch, [0], [SHIFT-1,SHIFT])); // add phase shifters
    Ytt = Ys + c(0,1) * Bc/2;
    Yff = Ytt ./ (tap .* conj(tap));
    Yft = - Ys ./ conj(tap);
    Ytf = - Ys ./ tap;

    // compute shunt admittance
    // if Psh is the real power consumed by the shunt at V = 1.0 p.u.
    // and Qsh is the reactive power injected by the shunt at V = 1.0 p.u.
    // then Psh - j Qsh = V * conj(Ysh * V) = conj(Ysh) = Gs - j Bs,
    // i.e. Ysh = Psh + j Qsh, so ...

    // vector of shunt admittances
    Ysh = (slice(bus, [0], [GS-1,GS]) + c(0,1) * slice(bus, [0], [BS-1,BS])) / baseMVA;

    // bus indices
    f = slice(branch, [0], F_BUS-1) - 1; // list of "from" buses
    t = slice(branch, [0], T_BUS-1) - 1; // list of "to" buses
    Ybus = [0];
    if nb < 300 {
        // small case
        // build Yf and Yt such that Yf * V is the vector of complex branch currents injected
        // at each branch's "from" bus, and Yt is the same for the "to" bus end
        i = horzcat(range(1,nl),range(1,nl)) - 1;                           // double set of row indices
        j = range(0,nb - 1);
        upper = horzcat(Yff, Yft);
        lower = horzcat(Ytf, Ytt);
        Yf = sparse(i, horzcat(f, t), upper, nl, nb);
        Yt = sparse(i, horzcat(f, t), lower, nl, nb);

        // build Ybus
        // branch admittances + shunt admittance
        Ybus = sparse(horzcat(f,f,t,t), horzcat(f,t,f,t), vertcat(upper,lower), nb, nb) +
               sparse(j, j, Ysh, nb, nb);
    } else {
        // large case running on MATLAB
        // build connection matrices
        i = range(0,nl-1);
        j = range(0,nb-1);
        Cf = sparse(i, f, ones(nl, 1), nl, nb);      // connection matrix for line & from buses
        Ct = sparse(i, t, ones(nl, 1), nl, nb);      // connection matrix for line & to buses

        // build Yf and Yt such that Yf * V is the vector of complex branch currents injected
        // at each branch's "from" bus, and Yt is the same for the "to" bus end

        Yf = sparse(i, i, Yff, nl, nl) * Cf + sparse(i, i, Yft, nl, nl) * Ct;
        Yt = sparse(i, i, Ytf, nl, nl) * Cf + sparse(i, i, Ytt, nl, nl) * Ct;

        // build Ybus
        // branch admittances + shunt admittance
        Ybus = Cf' * Yf + Ct' * Yt +
               sparse(j, j, Ysh, nb, nb);
    }
    return Ybus;
}

