fn make_y_bus_Yf(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_col = slice(branch, [0], [TAP-1,TAP]); // tap ratio column

    index = find(tap_col);      // indices of non-zero tap ratios
    tap_init = set(ones(nl, 1), index, get_multi(tap_col, index)); // assign non-zero tap ratios
    tap = tap_init .* 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
    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(0, nl),range(0, nl));                           // double set of row indices
        j = range(0,nb);
        upper = horzcat(Yff', Yft');
        lower = horzcat(Ytf', Ytt');
        Yf = full(sparse(i, horzcat(f, t), upper, nl, nb));
        Yt = full(sparse(i, horzcat(f, t), lower, nl, nb));

        // build Ybus
        // branch admittances + shunt admittance
        Ybus = full(sparse(horzcat(f,f,t,t), horzcat(f,t,f,t), vertcat(Yff,Yft,Ytf,Ytt), nb, nb)) +
               full(sparse(j, j, Ysh, nb, nb));
    } else {
        // large case running on MATLAB
        // build connection matrices
        i = range(0, nl);
        j = range(0, nb);
        Cf = full(sparse(i, f, ones(nl, 1), nl, nb));      // connection matrix for line & from buses
        Ct = full(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 = full(sparse(i, i, Yff, nl, nl)) * Cf + full(sparse(i, i, Yft, nl, nl)) * Ct;
        Yt = full(sparse(i, i, Ytf, nl, nl)) * Cf + full(sparse(i, i, Ytt, nl, nl)) * Ct;

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

    return Yf;
}