CoolFace
Apppublic

Aarondard5/constrained_multiOT

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
dynamics_capacity.py536 linesDownload Raw Back to root
1 2 3#######################################4# PACKAGES5#######################################6 7import pickle, time, warnings8import numpy as np9import networkx as nx10import random11import copy12import math13import scipy as sp14import itertools15 16from scipy.sparse import csr_matrix, lil_matrix, issparse, csc_matrix17from scipy.sparse import diags18from scipy.sparse import identity19from scipy.sparse.linalg import spsolve20from scipy import sparse21 22import quadprog23import scipy.optimize24import scipy.stats25 26 27import matplotlib.pyplot as plt28from matplotlib.ticker import MaxNLocator29 30#######################################31INF = 1e2032 33warnings.filterwarnings("ignore", message="Matrix is exactly singular")34 35 36def initialize_mu(flux, pflux, length, ord_norm=2):37 38    flux_norm = np.linalg.norm(flux, axis=1, ord=ord_norm)39    num = flux_norm ** (2 / (3 - pflux))40    return num41 42 43def remaining_e_ids(tdens_init, removed_e_id):44    return np.setdiff1d(np.arange(len(tdens_init)), removed_e_id)45 46 47def tdensinit(nedge, seed=10, tdens_init=None):48    """initialization of the conductivities: mu_e ~ U(0,1)"""49    prng = np.random.RandomState(seed=seed)50 51    if tdens_init is None:52        print("-" * 15)53        print(f"Using U(0,1) as tdens")54        print("-" * 15)55        tdens_0 = 0.1 + prng.uniform(0, 1, size=nedge)56    else:57        print("=" * 15)58        print(f"Using existing tdens")59        print("-" * 15)60        tdens_0 = (61            0.01 * prng.uniform(0, 1, size=nedge) + tdens_init62        )  # [remaining_e_ids(tdens_init, removed_e_id)]63        # tdens_0 = 0.1 + tdens_init  # [remaining_e_ids(tdens_init, removed_e_id)]64 65    weight = np.ones(nedge) + 0.01 * prng.uniform(0, 1, size=nedge)66 67    return tdens_0, weight68 69 70def dyn(71    g,72    nodes,73    pflux,74    nedge,75    length,76    forcing0,77    tol_var_tdens,78    removed_e_id,79    seed=10,80    verbose=False,81    N_real=1,82    plot_cost=False,83    coupling="l2",84    tdens0=None,85    constraint=True,86    clipping=False,87    capacity=INF,88    time_step=1,89    alpha=1,90    tot_time=300,91):92    """dynamics method"""93 94    capacity = np.full(nedge, capacity)  # set capacity on edges95    print(96        f"capacity shape:{capacity.shape}; min capacity:{np.min(capacity)}; max capacity:{np.max(capacity)}"97    )98 99    print("\ndynamics...")100 101    relax_linsys = 1.0e-5  # relaxation for stiffness matrix102    tot_time = tot_time  # upper bound on number of time steps103    threshold_cost = 1.0e-6  # threshold for stopping criteria using cost104    prng = np.random.RandomState(105        seed=seed106    )  # only needed if spsolve has problems (inside update)107 108    nnode = len(nodes)109    ncomm = forcing0.shape[0]110    forcing = forcing0.transpose()111 112    minCost = 1e14113    minCost_list = []114 115    inc_mat = csr_matrix(nx.incidence_matrix(g, nodelist=nodes, oriented=True))  # B116    117    118    inc_transpose = csr_matrix(inc_mat.transpose())  # B^T119    inv_len_mat = diags(1 / length, 0)  # diag[1/l_e]120 121    for r in range(N_real):122 123        tdens_0, weight = tdensinit(124            nedge, seed=seed + r, tdens_init=tdens0125        )  # conductivities initialization126 127        # forcing = csc_matrix(forcing0.transpose())128        # --------------------------------------------------------------------------------129        tdens = tdens_0.copy()130        td_mat = diags(tdens.astype(float), 0)  # matrix M131        # print(f"tdens:{tdens}")132        stiff = (133            inc_mat * td_mat * inv_len_mat * inc_transpose134        )  # B diag[mu] diag[1/l_e] B^T135        stiff_relax = stiff + relax_linsys * identity(nnode)  # avoid zero kernel136        pot = spsolve(stiff_relax, forcing).reshape((nnode, ncomm))  # pressure137        print(f"stiff_relax:{stiff_relax.shape} --  forcing:{forcing.shape} -- pot:{pot.shape}")138        # --------------------------------------------------------------------------------139        # Run dynamics140        convergence_achieved = False141        cost_update = 0142        cost_update_inter = 0143        cost_list = []144        g_list = []145        time_iteration = 0146 147        fmax = forcing0.max()148 149        not_in_C_id = np.where(compute_capacity_contraint(tdens, capacity) < 0)[0]150        print(f"initial # of active constraints: {len(not_in_C_id)}")151        while not convergence_achieved and time_iteration < tot_time:152 153            time_iteration += 1154 155            # update tdens-pot system156            tdens_old = tdens.copy()157            pot_old = pot.copy()158 159            # print(f'mu:{tdens}')160            # equations update161            tdens, pot, grad, info = update(162                g,163                tdens,164                pot,165                weight,166                inc_mat,167                inc_transpose,168                inv_len_mat,169                forcing,170                time_step,171                pflux,172                relax_linsys,173                nnode,174                coupling=coupling,175                constraint=constraint,176                clipping=clipping,177                capacity=capacity,178                alpha=alpha,179            )180 181            g_ = compute_capacity_contraint(tdens, capacity)182            g_list.append(g_)183 184            # print(f'g_list:{g_list}')185            # singular stiffness matrix186            if info != 0:187                print(f"info = {info}")188                tdens = (189                    tdens_old + prng.rand(*tdens.shape) * np.mean(tdens_old) / 1000.0190                )191                pot = pot_old + prng.rand(*pot.shape) * np.mean(pot_old) / 1000.0192 193            # 1) convergence with conductivities194            # var_tdens = max(np.abs(tdens - tdens_old))/time_step195            # print(time_iteration, var_tdens)196            if verbose > 1:197                print("==========")198 199            # 2) an alternative convergence criteria: using total cost and maximum variation of conductivities200            var_tdens = max(np.abs(tdens - tdens_old)) / time_step201 202            # var_tdens_inter = ([ max(np.abs(tdens_inter[i] - tdens_old_inter[i]))/time_step for i in range(nnode) ] )203            (204                convergence_achieved,205                cost_update,206                abs_diff_cost,207                flux_norm,208                flux_mat,209            ) = cost_convergence(210                threshold_cost,211                cost_update,212                tdens,213                pot,214                inc_mat,215                inv_len_mat,216                length,217                weight,218                pflux,219                convergence_achieved,220                var_tdens,221                coupling=coupling,222            )  # , var_tdens_inter)223 224            if verbose > 1:225                # print(time_iteration, var_tdens/forcing.max(), abs_diff_cost)226 227                # print('\r','It=',it,'err=', abs_diff,'J-J_old=',abs_diff_cost,sep=' ', end='', flush=True)228                print(229                    "\r",230                    "it=%3d, err/max_f=%5.2f, J_diff=%8.2e"231                    % (time_iteration, var_tdens / fmax, abs_diff_cost),232                    sep=" ",233                    end=" ",234                    flush=True,235                )236                time.sleep(0.05)237 238            cost_list.append(cost_update)239 240            if var_tdens < tol_var_tdens:  # or (var_tdens_inter < tol_var_tdens):241                convergence_achieved = True242 243            elif time_iteration >= tot_time:244                convergence_achieved = True245                tdens = tdens_old.copy()246                if verbose > 0:247                    print(248                        "ERROR: convergence dynamics not achieved, iteration time > maxit"249                    )250 251            if convergence_achieved == True and time_iteration < tot_time:252                if constraint == True:  # check that all constraints are satisfied253                    not_in_C_id = np.where(254                        compute_capacity_contraint(tdens, capacity) <= 0255                    )[0]256                    if len(not_in_C_id) > 0:257                        convergence_achieved = False258 259 260        if convergence_achieved:261            if verbose > 0:262                print("cost:", cost_update, " - N_real:", r, "- Best cost", minCost)263            if cost_update < minCost:264                minCost = cost_update265                minCost_list = cost_list266                tdens_best = tdens.copy()267                pot_best = pot.copy()268                flux_best_norm = flux_norm.copy()269                flux_best = flux_mat.copy()270                min_g_list = g_list.copy()271 272        else:273            print("ERROR: convergence dynamics not achieved")274 275    if plot_cost:276        plot_J(minCost_list, int_ticks=True)277        plot_gmu(min_g_list, not_in_C_id, tdens_best, capacity, int_ticks=True)278 279        # plt.plot(f_dot, rhs_ode)280    return (281        tdens_best,282        pot_best,283        flux_best_norm,284        minCost,285        minCost_list,286        flux_best,287        min_g_list,288    )289 290 291def update(292    g,293    tdens,294    pot,295    weight,296    inc_mat,297    inc_transpose,298    inv_len_mat,299    forcing,300    time_step,301    pflux,302    relax_linsys,303    nnode,304    coupling="l1",305    constraint=True,306    clipping=False,307    capacity=None,308    alpha=1,309):310 311    # updating dynamic...312 313    nedge = tdens.shape[0]314    nnode, ncomm = pot.shape315 316    weight = 1.0317    # weight = length318    grad = inv_len_mat * inc_transpose * pot  # discrete gradient319 320    if coupling == "l2":321        rhs_ode = ((tdens**pflux) * ((grad**2).sum(axis=1)) / (weight**2)) - tdens322    if coupling == "l1":323        rhs_ode = ((tdens**pflux) * ((np.abs(grad).sum(axis=1)) ** 2) / (weight**2)) - tdens324    # print(f"rhs_ode:{rhs_ode}")325    if clipping == True:  # use trivial method of clipping326        constraint = False327 328    # --------------------------329    # adding force to enforce constraints330    # --------------------------331 332    if constraint == True:333        """334        this section runs analytic result335        """336        small_err = 1e-05337        g_capacity = compute_capacity_contraint(tdens + small_err, capacity)338        not_in_C_id = np.where(g_capacity <= 0)[0]339        alpha_pos = 1 / time_step340 341        if len(not_in_C_id) > 0:342            for i in np.arange(nedge):343                if rhs_ode[i] >= alpha * g_capacity[i]:344                    rhs_ode[i] = alpha * g_capacity[i]345                else:346                    rhs_ode[i] = rhs_ode[i]  # -alpha_pos * tdens[i]  #347 348    # update conductivity349    if rhs_ode.ndim > 1:350        if alpha == 0:351            tdens = tdens + time_step * np.ravel(rhs_ode[:, 0])352        else:353            tdens = tdens + (alpha * time_step * np.ravel(rhs_ode[:, 0]))354    else:355        if alpha == 0:356            tdens = tdens + time_step * rhs_ode357        else:358            tdens = tdens + (alpha * time_step * rhs_ode)359 360    not_in_C_id = np.where(compute_capacity_contraint(tdens, capacity) < 0)[0]361    td_mat = diags(tdens.astype(float), 0)362 363    # update stiffness matrix364    stiff = inc_mat * td_mat * inv_len_mat * inc_transpose365 366    # spsolve367    stiff_relax = stiff + relax_linsys * identity(nnode)  # avoid zero kernel368    # update potential369    pot = spsolve(stiff_relax, forcing).reshape((nnode, ncomm))  # pressure370    if np.any(np.isnan(pot)):  # or np.any(np.isnan(pot_ctr)): # or np.any(pot != pot)371        info = -1372        pass373    else:374        info = 0375 376    return tdens, pot, grad, info377 378 379def calculate_cost(flux_mat, length, pflux=1.9, coupling="l2", tdens=None):380    if coupling == "l2":381        flux_norm = np.linalg.norm(flux_mat, axis=1)382    if coupling == "l1":383        flux_norm = np.linalg.norm(flux_mat, axis=1, ord=1)384 385    if tdens is None:386        return np.sum(length * (flux_norm ** (2 * (2 - pflux) / (3 - pflux))))387    else:388        normalization = 1.0 / np.sum(tdens)389        return normalization * np.sum(390            length * (flux_norm ** (2 * (2 - pflux) / (3 - pflux)))391        )392 393 394def cost_convergence(395    threshold_cost,396    cost,397    tdens,398    pot,399    inc_mat,400    inv_len_mat,401    length,402    weight,403    pflux,404    convergence_achieved,405    var_tdens,406    coupling="l1",407):  # , var_tdens_inter):408    """computing convergence using total cost: setting a high value for maximum conductivity variability"""409 410    L = len(pot)411    nnode = pot[0].shape[0]412    td_mat = np.diag(tdens.astype(float))413    flux_mat = np.matmul(td_mat * inv_len_mat * np.transpose(inc_mat), pot)414 415    if coupling == "l2":416        flux_norm = np.linalg.norm(flux_mat, axis=1)417    if coupling == "l1":418        flux_norm = np.linalg.norm(flux_mat, axis=1, ord=1)419 420    # cost_update = calculate_cost( flux_mat, length, pflux=pflux, coupling=coupling, tdens=tdens )421    normalization = 1.0 / np.sum(tdens)422    cost_update = normalization * np.sum(423        length * (flux_norm ** (2 * (2 - pflux) / (3 - pflux)))424    )425 426 427    abs_diff_cost = abs(cost_update - cost)428 429    convergence_achieved = bool(convergence_achieved)430    if min(pflux) > 0.0:431        if abs_diff_cost < threshold_cost:432            convergence_achieved = True433    else:434        if abs_diff_cost < threshold_cost and var_tdens < 1:435            convergence_achieved = True436 437    return convergence_achieved, cost_update, abs_diff_cost, flux_norm, flux_mat438 439 440 441 442def plot_J(443    values, indices=None, k_i=5, figsize=(7, 3), int_ticks=False, xlab="Iterations"444):445 446    fig, ax = plt.subplots(1, 1, figsize=figsize)447    # print('\n\nL: \n\n',values[k_i:])448 449    if indices is None:450        ax.plot(values[k_i:])451    else:452        ax.plot(indices[k_i:], values[k_i:])453    ax.set_xlabel(xlab)454    ax.set_ylabel("Best cost")455    if int_ticks:456        ax.xaxis.set_major_locator(MaxNLocator(integer=True))457    ax.grid()458 459    plt.tight_layout()460    plt.show()461 462 463def plot_gmu(464    g_func,465    not_in_C_id,466    tdens,467    capacity,468    indices=None,469    k_i=5,470    figsize=(14, 5),471    int_ticks=False,472    xlab="Edges",473    outfig=None,474):475    """476    plot function g(mu) = c_e - mu_e477    """478    g = compute_capacity_contraint(tdens, capacity)479 480    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize)481    fs = 23482    indices = None483    # for item in g_func:484    not_in_C_id = np.where(g < 0)[0]485 486    if indices is None:487        ax1.plot(g[k_i:])488    else:489        ax1.plot(indices[k_i:], g[k_i:])490    ax1.set_xlabel(xlab)491    ax1.set_ylabel(r"$g = c_e - \mu_e$", fontsize=fs)492    if int_ticks:493        ax1.xaxis.set_major_locator(MaxNLocator(integer=True))494    ax1.grid()495 496    # axis 2497    if indices is None:498        ax2.plot(g[not_in_C_id][k_i:])499    else:500        ax2.plot(indices[k_i:], g[not_in_C_id][k_i:])501    ax2.set_xlabel(xlab)502    ax2.set_ylabel(r"$g(\mu_e) = c_e - \mu_e < 0$", fontsize=fs)503    if int_ticks:504        ax2.xaxis.set_major_locator(MaxNLocator(integer=True))505    ax2.grid()506    507    plt.tight_layout()508    if outfig is not None:509        plt.savefig(outfig, dpi=300)510    return plt.show()511 512 513def capacity_constraint_QP(514    MultiOT_rhs_ode, infeasible_points_ids, capacity, g=0, alpha=1515):516 517    L = infeasible_points_ids.shape[0]518    v = np.zeros(L)519 520    alpha_g = alpha * g[infeasible_points_ids]521 522    mask = MultiOT_rhs_ode[infeasible_points_ids] >= alpha_g523    v[mask] = alpha_g[mask]524    v[np.logical_not(mask)] = -np.abs(525        MultiOT_rhs_ode[infeasible_points_ids][np.logical_not(mask)]526    )527    return v528 529 530def compute_capacity_contraint(tdens, capacities):531    return capacities - tdens532 533 534 535 536