Il discreto il più grande problema deve definire la posizione di P strutture tra N nodi discreti per massimizzare la somma delle distanze (o la media delle distanze) calcolate tra tutte le coppie di strutture selezionate. Pertanto, consideriamo che le strutture siano nodi spostati in un grafo orientato G(V, UN). Il peso di ciascun arco da io A J è la metrica della distanza (dispersione). dᵢⱼ conosciuto in anticipo. Inoltre, considera le variabili binarie xᵢ per indicare se una posizione io è selezionato e zᵢⱼ per indicare se entrambi io E J sono selezionati.
L’obiettivo può essere definito come segue:
Oltre ai vincoli per linearizzare il prodotto di variabili binarie presentati nella sezione precedente, è necessario includere un vincolo per garantire che P le posizioni sono selezionate.
Possiamo quindi definire i vincoli del problema come:
Mettiamolo nel codice usando Python. Per fare ciò, dobbiamo iniziare importando le librerie che verranno utilizzate. La Biblioteca insensato verrà utilizzato per calcoli di algebra lineare e per creare punti di coordinate casuali; le funzioni forma quadrata E pdist from scipy verrà utilizzato per calcolare le distanze data una matrice di coordinate; matplotlib sarà il nostro strumento di visualizzazione; E Piomo il linguaggio di modellazione algebrica (AML) (con solutore HiGHS).
import numpy as np
from scipy.spatial.distance import squareform, pdist
import matplotlib.pyplot as plt
import pyomo.environ as pyo
from pyomo.contrib.appsi.solvers.highs import Highs
Dobbiamo creare N punti e definire quanti di questi devono essere selezionati come ubicazioni della struttura. Fissando il seme casuale (12) in ogni esecuzione del codice si dovrebbero ottenere i punti rappresentati nell’introduzione.
# Fix random seeds
np.random.seed(12)# Create random points
N = 25
p = 5
coordinates = np.random.random((N, 2))
# Calculate pairwise distances
distances = squareform(pdist(coordinates))
Ora abbiamo gli elementi necessari per iniziare il nostro Piomo modello.
Esistono due approcci per modellare un problema Piomo: Astratto E Calcestruzzo Modelli. Nel primo approccio, le espressioni algebriche del problema vengono definite prima che vengano forniti alcuni valori dei dati, mentre, nel secondo, l’istanza del modello viene creata immediatamente non appena vengono definiti i suoi elementi. Puoi trovare ulteriori informazioni su questi approcci nel documentazione della biblioteca o nel libro di Bynum et al. (2021). In questo articolo adotteremo il Calcestruzzo formulazione del modello.
model = pyo.ConcreteModel()
In questo modello ne abbiamo due imposta: nodi e archi. Poiché stiamo considerando un grafo diretto completo, esistono archi tra ogni coppia di due nodi tranne che dal nodo a se stesso.
# Sets of nodes and arcs
model.V = pyo.Set(initialize=range(N))
model.A = pyo.Set(initialize=((i, j) for i in model.V for j in model.V if i != j))
I parametri forniti in anticipo sono il numero di nodi che devono essere selezionati e le distanze tra coppie di nodi.
# Parameters
model.d = pyo.Param(model.A, initialize={(i, j): distances(i, j) for (i, j) in model.A})
model.p = pyo.Param(initialize=p)
Quindi, includiamo le variabili decisionali.
# Decision variables
model.x = pyo.Var(model.V, within=pyo.Binary)
model.z = pyo.Var(model.A, within=pyo.Binary)
E i vincoli…
# p nodes are selected
def p_selection(model):
return sum(model.x(:)) == model.p# If starting node is not selected, the arc is 0
def dispersion_c1(model, i, j):
return model.z(i, j) <= model.x(i)
# If ending node is not selected, the arc is 0
def dispersion_c2(model, i, j):
return model.z(i, j) <= model.x(j)
# Include constraints in model
model.p_selection = pyo.Constraint(rule=p_selection)
model.dispersion_c1 = pyo.Constraint(model.A, rule=dispersion_c1)
model.dispersion_c2 = pyo.Constraint(model.A, rule=dispersion_c2)
Infine, dobbiamo creare la funzione obiettivo.
def disp_obj(model):
return sum(model.z(i, j) * model.d(i, j) for (i, j) in model.A)model.obj = pyo.Objective(rule=disp_obj, sense=pyo.maximize)
Ora il il più grande il modello è pronto per essere risolto. Dobbiamo quindi istanziare un risolutore compatibile con Piomo per gestirlo. IL Alti il risolutore è disponibile in Piomo (controlla le importazioni) dalla versione 6.4.3 se il altaspia il pacchetto è installato. Quindi assicurati di eseguire a pip install highspy
.
solver = Highs()
solver.solve(model)
E, dopo circa 120 secondi di tempo di elaborazione, otteniamo i seguenti risultati:
Si noti che, anche se la dispersione totale è massimizzata, due strutture nell’angolo in alto a sinistra sono ancora abbastanza vicine l’una all’altra, il che può essere indesiderabile. Quindi, in alternativa al il più grande formulazione abbiamo la P–dispersione modello in cui massimizziamo la distanza minima tra qualsiasi coppia di nodi selezionati.
Fonte: towardsdatascience.com