-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
aggiunta versione latex degli appunti del modulo pinotti
- Loading branch information
1 parent
09d6051
commit c153679
Showing
67 changed files
with
4,540 additions
and
0 deletions.
There are no files selected for viewing
Binary file added
BIN
+2.16 MB
...e/Anno 1/Advanced and Distributed Algorithms/Pinotti/Advanced_and_distributed_pinotti.pdf
Binary file not shown.
211 changes: 211 additions & 0 deletions
211
...e/Anno 1/Advanced and Distributed Algorithms/Pinotti/latex/Network_flow/delta_scaling.tex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
\chapter{Designing a Faster Flow Algorithm} | ||
|
||
\paragraph{Choosing Good Augmenting Paths} | ||
Nella sezione precedente, abbiamo visto che qualsiasi modo di scegliere | ||
un augmenting path aumenta il valore del flusso, e questo ha portato a | ||
un limite per C sul numero di augmentations, dove | ||
$C = \sum_{e \text{ out of }s} c_e$. Quando $C$ non è molto grande, | ||
questo può essere un limite ragionevole; tuttavia, è molto debole quando | ||
$C$ è grande.\\ | ||
|
||
L'obiettivo di questo capitolo è mostrare che con una migliore scelta dei | ||
path, possiamo migliorare significativamente questo limite. Una grande | ||
mole di lavoro è stata dedicata alla ricerca di metodi per scegliere | ||
augmenting path nel problema del flusso massimo in modo da minimizzare | ||
il numero di iterazioni. \textbf{Ricordiamo che l'augmentation aumenta | ||
il valore del flusso del percorso selezionato di un valore che è dato | ||
dal bottleneck; quindi, è un buon approccio quello di scegliere percorsi | ||
con una grande capacità di bottleneck.} | ||
|
||
\begin{myblockquote} | ||
\textbf{L'approccio migliore è quello di selezionare il percorso che ha | ||
il bottleneck di maggiore capacità.} | ||
\end{myblockquote} | ||
|
||
Tuttavia, trovare tali percorsi può rallentare di parecchio ogni singola | ||
iterazione. Eviteremo questo rallentamento non preoccupandoci di | ||
selezionare il percorso che ha esattamente la maggiore capacità di | ||
bottleneck. Invece, manterremo un cosiddetto \textbf{scaling parameter} | ||
$\Delta$ e cercheremo percorsi che abbiano un bottleneck di capacità | ||
di almeno $\Delta$. Sia $G_f(\Delta)$ il sottoinsieme del grafo | ||
residuo costituito solo da archi con capacità residua di almeno | ||
$\Delta$. Lavoreremo con valori di $\Delta$ che sono potenze di 2.\\ | ||
|
||
L'algoritmo è il seguente. | ||
|
||
\section{Scaling Max-Flow} | ||
|
||
|
||
\begin{lstlisting}[language=Python, mathescape=true] | ||
Initially f (e) = 0 for all e in G | ||
Initially set $\Delta$ to be the largest power of 2 that is no larger than the maximum capacity out of s: $\Delta$ $\leq$ max(e out of s ce) | ||
|
||
While $\Delta$ $\geq$ 1 | ||
While there is an s-t path in the graph Gf($\Delta$) | ||
Let P be a simple s-t path in Gf($\Delta$) | ||
f' = augment(f , P) | ||
Update f to be f' and update Gf ($\Delta$) | ||
Endwhile | ||
$\Delta$ = $\Delta$/2 | ||
Endwhile | ||
|
||
Return f | ||
\end{lstlisting} | ||
|
||
\subsection{Analyzing the Algorithm} | ||
|
||
Innanzitutto dobbiamo osservare che l'algoritmo | ||
\texttt{Scaling\ Max-Flow} \textbf{è in realtà solo una variante | ||
dell'originale algoritmo di Ford-Fulkerson}. I nuovi cicli, il valore | ||
$\Delta$ e il grafo residuo ristretto $G_f(\Delta)$ vengono | ||
utilizzati solo per \textbf{guidare la selezione del percorso residuo, | ||
con l'obiettivo di utilizzare archi con una grande capacità residua il | ||
più a lungo possibile.} Inoltre, tutte le proprietà che abbiamo | ||
dimostrato sull'algoritmo \texttt{Max-Flow} originale, sono vere anche | ||
per questa nuova versione: il flusso rimane di valore intero per tutto | ||
l'algoritmo, e quindi tutte le capacità residue sono di valore intero. | ||
|
||
\paragraph{Def 7.14} | ||
|
||
\begin{myblockquote} | ||
(7.14) Se tutte le capacità nella rete di flusso sono intere, allora | ||
esiste un flusso massimo $f$ per il quale ogni valore di flusso | ||
$f(e)$ è un numero intero. | ||
\end{myblockquote} | ||
|
||
\paragraph{Def. 7.15} | ||
|
||
\begin{myblockquote} | ||
Se le capacità hanno valori interi, allora in tutto l'algoritmo | ||
\texttt{Scaling\ Max-Flow} il flusso e le capacità residue rimangono | ||
valori interi. Ciò implica che quando $\Delta$ = 1, $G_f(\Delta)$ è | ||
uguale a $G_f$, e quindi quando l'algoritmo termina, $f$ è di valore | ||
massimo. | ||
\end{myblockquote} | ||
|
||
\subsection{Costo} | ||
|
||
Chiamiamo un'iterazione del ciclo esterno \texttt{While}, con un valore | ||
fisso di $\Delta$, la fase di $\Delta$-scaling. È facile dare un | ||
limite superiore al numero di diverse fasi di $\Delta$-scaling, in | ||
termini di valore di $C = \sum_{e \text{ out of }s} c_e$ che abbiamo | ||
usato anche nella sezione precedente. Il valore iniziale di $\Delta$ è | ||
al massimo $C$, scende di un fattore 2 e non scende mai al di sotto di | ||
1.\\ | ||
|
||
Quindi: \textgreater{} Il numero di iterazioni del ciclo \texttt{While} | ||
esterno è al massimo $\left\lceil 1 + log_2 C \right\rceil$.\\ | ||
|
||
La parte più difficile è limitare il numero di \emph{aumenti} eseguiti | ||
in ogni fase di ridimensionamento. L'idea qui è che stiamo usando | ||
percorsi che aumentano molto il flusso, e quindi dovrebbero esserci | ||
relativamente pochi aumenti. Durante la fase di $\Delta$-scaling | ||
utilizziamo solo archi con capacità residua di almeno $\Delta$.\\ | ||
Quindi: \textgreater{} Durante la fase di $\Delta$-scaling, ogni | ||
augmentation aumenta il valore del flusso di almeno $\Delta$.\\ | ||
|
||
L'intuizione chiave è che alla fine della fase di $\Delta$-scaling, il | ||
flusso $f$ non può essere troppo lontano dal valore massimo possibile.\\ | ||
|
||
\paragraph{Teorema} | ||
|
||
\begin{myblockquote} | ||
Sia $f$ il flusso alla fine della fase di $\Delta$-scaling. Esiste | ||
un taglio $s-t$ $(A, B)$ in $G$ per cui | ||
$c(A, B) \le v(f) + m\Delta$ , dove $m$ è il numero di archi nel | ||
grafo $G$. Di conseguenza, il flusso massimo nella rete ha valore al | ||
massimo $v(f) + m\Delta$. | ||
\end{myblockquote} | ||
|
||
\paragraph{Dimostrazione} | ||
|
||
Questa dimostrazione è analoga alla nostra dimostrazione della (7.9), la | ||
quale stabilisce che il flusso restituito dall'originale | ||
\texttt{Max-Flow\ Algorithm} è di valore massimo. Come in quella | ||
dimostrazione, dobbiamo identificare un taglio $(A, B)$ con la | ||
proprietà desiderata. Sia $A$ l'insieme di tutti i nodi $v$ in $G$ | ||
per i quali esiste un cammino $s-v$ in $G_f(\Delta)$. Sia $B$ | ||
l'insieme di tutti gli altri nodi: $B = V - A$. Possiamo vedere che | ||
$(A, B)$ è effettivamente un taglio $s-t$ altrimenti la fase non | ||
sarebbe terminata.\\ | ||
|
||
Consideriamo ora un arco $e = (u, v)$ in $G$ per il quale | ||
$u \in A$ e $v \in B$. Affermiamo che $c_e < f(e) + \Delta$ . | ||
Infatti, se così non fosse, allora $e$ sarebbe un arco in avanti nel | ||
grafo $G_f(\Delta)$, e poiché $u \in A$, esiste un cammino $s-u$ | ||
in $G_f(\Delta)$; aggiungendo $e$ a questo cammino, otterremmo un | ||
cammino $s-v$ in $G_f(\Delta)$, contraddicendo la nostra ipotesi che | ||
$v \in B$. Allo stesso modo, affermiamo che per ogni arco | ||
$e' = (u' , v')$ in $G$ per cui $u' \in B$ e $v' \in A$, abbiamo | ||
$f(e') < \Delta$. Infatti, se $f(e') \ge \Delta$, allora $e'$ | ||
darebbe luogo ad un arco all'indietro $e'' = (v'' , u'')$ nel grafo | ||
$G_f(\Delta)$, e poiché $v' \in A$, esiste un cammino $s-v'$ in | ||
$G_f(\Delta)$; aggiungendo $e''$ a questo cammino, otterremmo un | ||
cammino $s-u'$ $G_f(\Delta)$, contraddicendo la nostra ipotesi che | ||
$u' \in B$.\\ | ||
|
||
Quindi tutti gli archi $e$ uscenti da $A$ sono quasi saturati | ||
(soddisfano $c_e < f(e) + \Delta$) e tutti gli archi entranti in $A$ | ||
sono quasi vuoti (soddisfano $f(e) < \Delta$).\\ | ||
|
||
Possiamo ora usare (7.6) per raggiungere la conclusione desiderata: | ||
|
||
$$ | ||
v(f) = \sum_{e \text{ out of } A}f(e) - \sum_{e \text{ into } A}f(e) \ge \sum_{e \text{ out of } A}(c_e - \Delta) - \sum_{e \text{ into } A}\Delta = | ||
$$ | ||
$$ | ||
\sum_{e \text{ out of } A}c_e - \sum_{e \text{ out of } A}\Delta - \sum_{e \text{ into } A}\Delta \ge c(A, B) - m\Delta | ||
$$ | ||
|
||
Qui la prima disuguaglianza segue dai nostri limiti sui valori di flusso | ||
degli archi attraverso il taglio, e la seconda disuguaglianza segue dal | ||
semplice fatto che il grafo contiene solo $m$ archi in totale. Il | ||
valore del flusso massimo è limitato dalla capacità di qualsiasi taglio | ||
di (7.8). Usiamo il taglio $(A, B)$ per ottenere il limite dichiarato | ||
nella seconda affermazione. | ||
|
||
\paragraph{Def. 7.19} | ||
|
||
\begin{myblockquote} | ||
Il numero di aumenti in una fase di ridimensionamento (\textbf{scaling}) | ||
è al massimo di $2m$. | ||
\end{myblockquote} | ||
|
||
\paragraph{Dimostrazione} | ||
|
||
L'affermazione è chiaramente vera nella prima fase di scaling: possiamo | ||
usare ciascuno degli archi di $s$ solo per al massimo un augmentation | ||
in quella fase. Consideriamo ora una successiva fase di scaling | ||
$\Delta$, e sia $f_p$ il flusso alla fine della precedente fase di | ||
scalatura. In quella fase, abbiamo usato $\Delta' = 2\Delta$ come | ||
nostro parametro. Per la (7.18), il flusso massimo $f^*$ è al massimo | ||
$v(f^*) \le v(f_p) + m\Delta' = v(f_p) + 2m\Delta$ . Nella fase di | ||
$\Delta$-scalatura, ogni augmentation aumenta il flusso di almeno | ||
$\Delta$ , e quindi possono esserci al massimo $2m$ augmentations.\\ | ||
|
||
Una augmentation richiede un tempo $O(m)$, compreso il tempo | ||
necessario per impostare il grafo e trovare il percorso appropriato. | ||
Abbiamo al massimo $1 + \left\lceil log_2 C \right\rceil$ fasi di | ||
ridimensionamento $C$ e al massimo $2m$ augmentations in ciascuna | ||
fase di ridimensionamento. Abbiamo quindi il seguente risultato. | ||
|
||
\paragraph{Teorema 7.20} | ||
|
||
\begin{myblockquote} | ||
L'algoritmo \texttt{Scaling\ Max-Flow} in un grafo con $m$ archi e | ||
capacità intere trova un flusso massimo in al massimo | ||
$2m(1 + \left\lceil log_2 C \right\rceil)$ augmentations. Può essere | ||
implementato per eseguire al massimo in tempo $O(m^2 \cdot log_2 C)$. | ||
\end{myblockquote} | ||
|
||
Quando $C$ è grande, questo limite temporale è molto migliore del | ||
limite $O(mC)$ applicato a un'implementazione arbitraria | ||
dell'algoritmo di \texttt{Ford-Fulkerson}. Il generico algoritmo di | ||
Ford-Fulkerson richiede un tempo proporzionale alla grandezza delle | ||
capacità, mentre l'algoritmo di scaling richiede solo un tempo | ||
proporzionale al numero di bit necessari per specificare le capacità | ||
nell'input del problema . Di conseguenza, l'algoritmo di | ||
ridimensionamento funziona in tempo polinomiale nella dimensione | ||
dell'input (ovvero, il numero di archi e la rappresentazione numerica | ||
delle capacità), e quindi soddisfa il nostro obiettivo tradizionale di | ||
ottenere un algoritmo polinomiale. |
114 changes: 114 additions & 0 deletions
114
...strale/Anno 1/Advanced and Distributed Algorithms/Pinotti/latex/Network_flow/fat_flow.tex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
\chapter{Algoritmo di Edmonds-Karp o Dinits(?)} | ||
\section{Introduzione} | ||
L'algoritmo di Ford-Fulkerson più che un algoritmo è un procedimento concettuale, dato che molte caratteristiche non sono specificate.\\ | ||
|
||
Altri hanno studiato delle implementazioni di Ford-Fulkerson specificando l'oridne ci scelta dei nodi su cui effettuare l'augment, due di queste sono lo \textbf{shortest path max flow} e il \textbf{fat flow}. | ||
|
||
|
||
\section{Shortest Path Max Flow} | ||
Migliora la complessità di Ford-Fulkerson scegliendo il cammino aumentante in base al risultato di una ricerca in ampiezza, preferendo quindi il cammino più corto tra il nodo e il sink.\\ | ||
|
||
Il cammino corretto può essere trovato in tempo $O(E)$ eseguendo una \texttt{BFS} nel grafo residuale, e ci garantisce di terminare in tempo polinomiale, tagliando quindi la dipendenza dell'algoritmo di Ford-Fulkerson dalle capacità degli archi. | ||
|
||
\subsection{Analisi dell'algoritmo} | ||
Ora andremo a dimostrare la terminazione polinomiale dell'algoritmo con le seguenti 2 osservazioni, ma prima ci definiamo $\delta_f(u,v)$ come la distanza del cammino minimo da $u$ a $v$ nel grafo residuale $G_f$, considerando che ogni arco ha distanza unitaria. | ||
|
||
\begin{myblockquote} | ||
Se l'agloritmo di Edmonds-Karp viene eseguito su una rete di flusso $G = (V, E)$ con sorgente $s$ e pozzo $t$, allora per ogni vertice $v \in V - \{s,t\}$, la distanza de cammino minimo $\delta_f(s,v)$ nella rete residua $G_f$ aumenta monotonicamente per ogni aumento di flusso. | ||
\end{myblockquote} | ||
|
||
\textbf{Dimostrazione.} Supponiamo per assurdo che per qualche vertice $v \in V - \{s, t\}$ ci sia un aumento di flusso che provoca una diminuzione della distanza del cammino minimo da $s$ a $v$. Sia $f$ il flusso appena prima del primo aumento che riduce una distanza del cammino minimo; | ||
sia $f^{'}$ il flusso subito dopo. Se $v$ è il vertice con il minimo $\delta_{f^{'}}(s,v)$ la cui distanza è stata ridotta dall'aumento, allora $\delta_{f^{'}}(s,v) < \delta_{f}(s,v)$. | ||
Se $p = s \rightsquigarrow u \rightarrow v$ è un cammino minimo da $s$ a $v$ in $G_{f{'}}$, allora | ||
$(u,v) \in E_{f^{'}}$ e: | ||
|
||
$$ | ||
\delta_{f^{'}}(s,u) = \delta_{f^{'}}(s,v) -1 | ||
$$ | ||
|
||
Per il modo in cui abbiamo scelto $v$, sappiamo che la distanza del vertice $u$ dalla sorgente $s$ non è \textbf{aumentata(?)}, ovvero: | ||
$$ | ||
\delta_{f^{'}}(s,u) \ge \delta_{f}(s,u) | ||
$$ | ||
Noi asseriamo che $(u,v) \notin E_f$. \textbf{Perchè?} | ||
|
||
Se avessimo $(u,v) \in E_f$ allora dovremmo avere anche: | ||
|
||
$$ | ||
\delta_{f}(s,v) \le \delta_{f}(s,u) +1 \\ | ||
\le \delta_{f^{'}}(s,u) -1 \\ | ||
= \delta_{f^{'}}(s,v) -2 | ||
$$ | ||
Questo contraddice l'ipotesi che $\delta_{f^{'}}(s,v) < \delta_{f}(s,v)$. | ||
|
||
Come è possibile avere $(u,v) \notin E_f$ e $(u,v) \in E_f^{'}$? | ||
L'augment deve avere incrementato il flusso da $v$ a $u$. L'algoritmo di Edmondo-Karp aumenta sempre il flusso lungo tutto i cammini minimi, e quindi il cammino minimo da $s$ a $u$ in $G_f$ ha $(v,u)$ come suo ultimo arco, per tanto si ha: | ||
|
||
$$ | ||
\delta_{f}(s,v) = \delta_{f}(s,u) -1 \\ | ||
\le \delta_{f^{'}}(s,u) -1 \\ | ||
= \delta_{f^{'}}(s,v) -2 | ||
$$ | ||
|
||
Questo contraddice l'ipotesi che $\delta_f^{'}(s,v) < \delta_f(s,v)$, quindi l'ipotesi dell'esistenza di un tale vertice $v$ non è corretta.\\ | ||
\\ | ||
\textbf{Il prossimo teorema limita il numero di iterazioni dell'algoritmo} | ||
|
||
\begin{myblockquote} | ||
Se l'algoritmo viene eseguito su una rete di flusso $G = (V, E)$ con sorgente $s$ e pozzo $t$, allora il numero totale di aumenti di glusso effettuati dall'algoritmo è $O(VE)$ | ||
\end{myblockquote} | ||
|
||
\textbf{Dimostrazione.} Diciamo che un arco $(u,v)$ di una rete residua $G_f$ è \textbf{critico} in un cammino aumentante $p$ se la capacità residua di $p$ è la capacità residua di $(u,v)$. | ||
Dopo aver aumentato il flusso lungo un cammino aumentante ogni arco critico scompare dalla rete residua. Inoltre in ogni cammino aumentante ci deve essere almeno un arco critico. | ||
|
||
Dimostreremo che ogni arco può diventare critico al più $\frac{|V|}{2}$ volte.\\ | ||
|
||
Siano $u$ e $v$ due vertici collegati da un arco, poichè i cammini aumentanti sono i cammini minimi, quando $(u,v)$ diventa \textbf{critico} si ha: | ||
$$ | ||
\delta_f(s,v) = \delta_{f^{'}}(s,u) +1 | ||
$$ | ||
Una volta che il flusso viene aumentato l'arco $(u,v)$ scompare dalla rete residua e non potrà riapparire successivamente in un altro cammino aumentante fino a che il flusso da $u$ a $v$ non diminuirà, e questo accade solo se $(u,v)$ apppare in un cammino aumentante. | ||
|
||
Se consideriamo che $f^{'}$ è il flusso quando si verifica questo evento, allora si ha | ||
|
||
$$ | ||
\delta_{f^{'}}(s,u) = \delta_{f^{'}}(s,v) +1 | ||
$$ | ||
Poichè $\delta_f(s,v) \le \delta_{f^{'}}(s,v)$ per la dimostrazione precedente, si ha: | ||
|
||
$$ | ||
\delta_{f^{'}}(s,u) = \delta_{f^{'}}(s,v) + 1 \\ | ||
\ge \delta_f(s,v) + 1 | ||
= \delta_f(s,v) +2 | ||
$$ | ||
|
||
|
||
Di conseguenza, dall'istante in cui $(u,v)$ diventa critico, all'istante in cui diventa di nuovo critico, la distanza di $u$ dalla sorgente aumenta almeno di 2 unità. | ||
|
||
La distanza di $u$ dalla sorgente inizialmente è almeno pari a 0. | ||
|
||
I vertici intermedi in un cammino minimo da $s$ a $u$ non possono contenere $s, u$ o $t$. | ||
Pertanto, fino al momento in cui u diventa irraggiungibile dalla sorgente, se mai si verifica la cosa, la sua distanza sarà al massimo $|V| -2$. Quindi dopo la prima volta che diventa critico esso può ridiventarlo al massimo altre $\frac{|V|}{2}$ volte. | ||
|
||
Poichè ci sono $O(E)$ coppie di vertici che possono essere connessi da un arco in un grafo residuale, il numero di archi critici durante l'intera esecuzione dell'algoritmo è $O(VE)$. | ||
|
||
|
||
|
||
|
||
\section{Fat Flow} | ||
Migliora la complessità di Ford-Fulkerson scegliendo il cammino aumentante con il più grande bottleneck disponibile.\\ | ||
|
||
È relativamente facile far vedere come il cammino con il massimo bottleneck da $s$ a $t$ in un grafo direzionato può essere calcolato in tempo di $O(E\log{V})$ usando una variante dell'algoritmo di Dijkstra. Semplicemente si crea uno spanning tree direzionato $T$, con radice in $s$. Ripetutamente trovando l'arco con capacità maggiore uscente da $T$ e lo si aggiunge a $T$ stesso finchè $T$ non conterrà un cammino da $s$ a $t$. | ||
|
||
\subsection{Analisi dell'algoritmo} | ||
|
||
Possiamo ora analizzare l'algoritmo in termini di maximum flow $f^{*}$. Sia $f$ un qualsiasi flow in $G$, e $f'$ il maximum flow nel grafo residuale corrente $G_f$. (All'inizio dell'algoritmo $G_f = G$ e $f' = f^{*}$.) | ||
Sia $e$ l'arco del bottleneck nel prossimo augmenting path. Sia $S$ il set di nodi raggiungibili da $s$ attraverso archi in $G$ con capacità maggiore di $c(e)$ e sia $T = V$ \textbackslash $S$. Per costruzione, $T$ non è vuoto, e ogni arco da $S$ a $T$ ha capacità al massimo $c(e)$. Perciò la capacità del taglio $(S,T)$ è al massimo $c(e) \cdot E$. D'altro canto, il teorema del Maxflow-Mincut implica che $||S,T|| \geq |f|$. Da ciò si evince che $c(e) \geq |f|/E$.\\ | ||
|
||
La dimostrazione precedente implica che aumentando $f$ attraverso il path con il maggior bottleneck in $G_f$ moltiplica il valore del flusso massimo in $G_f$ di un fattore di al massimo $1 - 1/E$. In altre parole il flusso residuale \textit{decade esponenzialmente} all'aumentare delle iterazioni. Dopo $E \cdot \ln{|f^{*}|}$ iterazioni il valore del flusso massimo in $G_f$ sarà al amssimo: | ||
$$ | ||
|f^{*}|\cdot(1-1/E)^{E\cdot \ln{|f^{*}|}} < |f^{*}|e^{-\ln{|f^{*}|}} = 1 | ||
$$ | ||
(La $e$ in questione è la costante di Eulero, non l'arco) In particolare, \textit{se tutte le capacità sono interi}, allora dopo $E\cdot \ln{|f^{*}|}$ iterazioni la capacità massima del grafo residuale sarà \textit{zero} e $f$ sarà il flusso massimo.\\ | ||
|
||
Concludiamo che per grafi con capacità intere l'algoritmo \textbf{Fat Flow} richiede $O(E^2\log{E}\log{|f^{*}|})$. |
Oops, something went wrong.