Better names for variables [closes #18]
This commit is contained in:
parent
baee83266a
commit
11564fd4d3
|
@ -480,7 +480,7 @@ efficiently implemented using them.
|
||||||
A convenient way to store the adjacency lists is to declare
|
A convenient way to store the adjacency lists is to declare
|
||||||
an array of vectors as follows:
|
an array of vectors as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
vector<int> v[N];
|
vector<int> adj[N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The constant $N$ is chosen so that all
|
The constant $N$ is chosen so that all
|
||||||
|
@ -503,11 +503,11 @@ For example, the graph
|
||||||
\end{center}
|
\end{center}
|
||||||
can be stored as follows:
|
can be stored as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
v[1].push_back(2);
|
adj[1].push_back(2);
|
||||||
v[2].push_back(3);
|
adj[2].push_back(3);
|
||||||
v[2].push_back(4);
|
adj[2].push_back(4);
|
||||||
v[3].push_back(4);
|
adj[3].push_back(4);
|
||||||
v[4].push_back(1);
|
adj[4].push_back(1);
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
If the graph is undirected, it can be stored in a similar way,
|
If the graph is undirected, it can be stored in a similar way,
|
||||||
|
@ -517,7 +517,7 @@ For a weighted graph, the structure can be extended
|
||||||
as follows:
|
as follows:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
vector<pair<int,int>> v[N];
|
vector<pair<int,int>> adj[N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
If there is an edge from node $a$ to node $b$
|
If there is an edge from node $a$ to node $b$
|
||||||
|
@ -541,11 +541,11 @@ For example, the graph
|
||||||
\end{center}
|
\end{center}
|
||||||
can be stored as follows:
|
can be stored as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
v[1].push_back({2,5});
|
adj[1].push_back({2,5});
|
||||||
v[2].push_back({3,7});
|
adj[2].push_back({3,7});
|
||||||
v[2].push_back({4,6});
|
adj[2].push_back({4,6});
|
||||||
v[3].push_back({4,5});
|
adj[3].push_back({4,5});
|
||||||
v[4].push_back({1,2});
|
adj[4].push_back({1,2});
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The benefit in using adjacency lists is that
|
The benefit in using adjacency lists is that
|
||||||
|
@ -555,7 +555,7 @@ For example, the following loop goes through all nodes
|
||||||
to which we can move from node $s$:
|
to which we can move from node $s$:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (auto u : v[s]) {
|
for (auto u : adj[s]) {
|
||||||
// process node u
|
// process node u
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
@ -570,14 +570,14 @@ We can efficiently check from an adjacency matrix
|
||||||
if there is an edge between two nodes.
|
if there is an edge between two nodes.
|
||||||
The matrix can be stored as an array
|
The matrix can be stored as an array
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
int v[N][N];
|
int mat[N][N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
where each value $\texttt{v}[a][b]$ indicates
|
where each value $\texttt{mat}[a][b]$ indicates
|
||||||
whether the graph contains an edge from
|
whether the graph contains an edge from
|
||||||
node $a$ to node $b$.
|
node $a$ to node $b$.
|
||||||
If the edge is included in the graph,
|
If the edge is included in the graph,
|
||||||
then $\texttt{v}[a][b]=1$,
|
then $\texttt{mat}[a][b]=1$,
|
||||||
and otherwise $\texttt{v}[a][b]=0$.
|
and otherwise $\texttt{mat}[a][b]=0$.
|
||||||
For example, the graph
|
For example, the graph
|
||||||
\begin{center}
|
\begin{center}
|
||||||
\begin{tikzpicture}[scale=0.9]
|
\begin{tikzpicture}[scale=0.9]
|
||||||
|
@ -696,7 +696,7 @@ at a given node.
|
||||||
|
|
||||||
The edge list can be stored in a vector
|
The edge list can be stored in a vector
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
vector<pair<int,int>> v;
|
vector<pair<int,int>> edges;
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
where each pair $(a,b)$ denotes that
|
where each pair $(a,b)$ denotes that
|
||||||
there is an edge from node $a$ to node $b$.
|
there is an edge from node $a$ to node $b$.
|
||||||
|
@ -718,18 +718,18 @@ Thus, the graph
|
||||||
\end{center}
|
\end{center}
|
||||||
can be represented as follows:
|
can be represented as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
v.push_back({1,2});
|
edges.push_back({1,2});
|
||||||
v.push_back({2,3});
|
edges.push_back({2,3});
|
||||||
v.push_back({2,4});
|
edges.push_back({2,4});
|
||||||
v.push_back({3,4});
|
edges.push_back({3,4});
|
||||||
v.push_back({4,1});
|
edges.push_back({4,1});
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
\noindent
|
\noindent
|
||||||
If the graph is weighted, the structure can
|
If the graph is weighted, the structure can
|
||||||
be extended as follows:
|
be extended as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
vector<tuple<int,int,int>> v;
|
vector<tuple<int,int,int>> edges;
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
Each element in this list is of the
|
Each element in this list is of the
|
||||||
form $(a,b,w)$, which means that there
|
form $(a,b,w)$, which means that there
|
||||||
|
@ -753,10 +753,10 @@ For example, the graph
|
||||||
\begin{samepage}
|
\begin{samepage}
|
||||||
can be represented as follows:
|
can be represented as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
v.push_back(make_tuple(1,2,5));
|
edges.push_back({1,2,5});
|
||||||
v.push_back(make_tuple(2,3,7));
|
edges.push_back({2,3,7});
|
||||||
v.push_back(make_tuple(2,4,6));
|
edges.push_back({2,4,6});
|
||||||
v.push_back(make_tuple(3,4,5));
|
edges.push_back({3,4,5});
|
||||||
v.push_back(make_tuple(4,1,2));
|
edges.push_back({4,1,2});
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
\end{samepage}
|
\end{samepage}
|
||||||
|
|
|
@ -129,23 +129,23 @@ a depth-first search at a given node.
|
||||||
The function assumes that the graph is
|
The function assumes that the graph is
|
||||||
stored as adjacency lists in an array
|
stored as adjacency lists in an array
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
vector<int> v[N];
|
vector<int> adj[N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
and also maintains an array
|
and also maintains an array
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
bool visited[N];
|
bool vis[N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
that keeps track of the visited nodes.
|
that keeps track of the visited nodes.
|
||||||
Initially, each array value is \texttt{false},
|
Initially, each array value is \texttt{false},
|
||||||
and when the search arrives at node $s$,
|
and when the search arrives at node $s$,
|
||||||
the value of \texttt{visited}[$s$] becomes \texttt{true}.
|
the value of \texttt{vis}[$s$] becomes \texttt{true}.
|
||||||
The function can be implemented as follows:
|
The function can be implemented as follows:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
void dfs(int s) {
|
void dfs(int s) {
|
||||||
if (visited[s]) return;
|
if (vis[s]) return;
|
||||||
visited[s] = true;
|
vis[s] = true;
|
||||||
// process node s
|
// process node s
|
||||||
for (auto u: v[s]) {
|
for (auto u: adj[s]) {
|
||||||
dfs(u);
|
dfs(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,8 +313,8 @@ as adjacency lists and maintains the following
|
||||||
data structures:
|
data structures:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
queue<int> q;
|
queue<int> q;
|
||||||
bool visited[N];
|
bool vis[N];
|
||||||
int distance[N];
|
int dist[N];
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
The queue \texttt{q}
|
The queue \texttt{q}
|
||||||
|
@ -323,24 +323,24 @@ of their distance.
|
||||||
New nodes are always added to the end
|
New nodes are always added to the end
|
||||||
of the queue, and the node at the beginning
|
of the queue, and the node at the beginning
|
||||||
of the queue is the next node to be processed.
|
of the queue is the next node to be processed.
|
||||||
The array \texttt{visited} indicates
|
The array \texttt{vis} indicates
|
||||||
which nodes the search has already visited,
|
which nodes the search has already visited,
|
||||||
and the array \texttt{distance} will contain the
|
and the array \texttt{dist} will contain the
|
||||||
distances to all nodes in the graph.
|
distances to all nodes in the graph.
|
||||||
|
|
||||||
The search can be implemented as follows,
|
The search can be implemented as follows,
|
||||||
starting at node $x$:
|
starting at node $x$:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
visited[x] = true;
|
vis[x] = true;
|
||||||
distance[x] = 0;
|
dist[x] = 0;
|
||||||
q.push(x);
|
q.push(x);
|
||||||
while (!q.empty()) {
|
while (!q.empty()) {
|
||||||
int s = q.front(); q.pop();
|
int s = q.front(); q.pop();
|
||||||
// process node s
|
// process node s
|
||||||
for (auto u : v[s]) {
|
for (auto u : adj[s]) {
|
||||||
if (visited[u]) continue;
|
if (vis[u]) continue;
|
||||||
visited[u] = true;
|
vis[u] = true;
|
||||||
distance[u] = distance[s]+1;
|
dist[u] = dist[s]+1;
|
||||||
q.push(u);
|
q.push(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
139
chapter13.tex
139
chapter13.tex
|
@ -193,12 +193,10 @@ The following implementation of the
|
||||||
Bellman–Ford algorithm finds the shortest distances
|
Bellman–Ford algorithm finds the shortest distances
|
||||||
from a node $x$ to all other nodes in the graph.
|
from a node $x$ to all other nodes in the graph.
|
||||||
The code assumes that the graph is stored
|
The code assumes that the graph is stored
|
||||||
as adjacency lists in an array
|
as an edge list \texttt{edges}
|
||||||
\begin{lstlisting}
|
that consists of tuples of the form $(a,b,w)$,
|
||||||
vector<pair<int,int>> v[N];
|
meaning that there is an edge from node $a$ to node $b$
|
||||||
\end{lstlisting}
|
with weight $w$.
|
||||||
as pairs of the form $(x,w)$:
|
|
||||||
there is an edge to node $x$ with weight $w$.
|
|
||||||
|
|
||||||
The algorithm consists of $n-1$ rounds,
|
The algorithm consists of $n-1$ rounds,
|
||||||
and on each round the algorithm goes through
|
and on each round the algorithm goes through
|
||||||
|
@ -210,14 +208,13 @@ to all nodes in the graph.
|
||||||
The constant \texttt{INF} denotes an infinite distance.
|
The constant \texttt{INF} denotes an infinite distance.
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int i = 1; i <= n; i++) distance[i] = INF;
|
for (int i = 1; i <= n; i++) dist[i] = INF;
|
||||||
distance[x] = 0;
|
dist[x] = 0;
|
||||||
for (int i = 1; i <= n-1; i++) {
|
for (int i = 1; i <= n-1; i++) {
|
||||||
for (int a = 1; a <= n; a++) {
|
for (auto e : edges) {
|
||||||
for (auto b : v[a]) {
|
int a, b, w;
|
||||||
distance[b.first] = min(distance[b.first],
|
tie(a, b, w) = e;
|
||||||
distance[a]+b.second);
|
dist[b] = min(dist[b], dist[a]+w);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
@ -298,29 +295,29 @@ Then, the algorithm always processes the
|
||||||
first node in the queue, and when an edge
|
first node in the queue, and when an edge
|
||||||
$a \rightarrow b$ reduces a distance,
|
$a \rightarrow b$ reduces a distance,
|
||||||
node $b$ is added to the queue.
|
node $b$ is added to the queue.
|
||||||
|
%
|
||||||
The following implementation uses a
|
% The following implementation uses a
|
||||||
\texttt{queue} \texttt{q}.
|
% \texttt{queue} \texttt{q}.
|
||||||
In addition, an array \texttt{inqueue} indicates
|
% In addition, an array \texttt{inqueue} indicates
|
||||||
if a node is already in the queue,
|
% if a node is already in the queue,
|
||||||
in which case the algorithm does not add
|
% in which case the algorithm does not add
|
||||||
the node to the queue again.
|
% the node to the queue again.
|
||||||
|
%
|
||||||
\begin{lstlisting}
|
% \begin{lstlisting}
|
||||||
for (int i = 1; i <= n; i++) distance[i] = INF;
|
% for (int i = 1; i <= n; i++) distance[i] = INF;
|
||||||
distance[x] = 0;
|
% distance[x] = 0;
|
||||||
q.push(x);
|
% q.push(x);
|
||||||
while (!q.empty()) {
|
% while (!q.empty()) {
|
||||||
int a = q.front(); q.pop();
|
% int a = q.front(); q.pop();
|
||||||
inqueue[a] = false;
|
% inqueue[a] = false;
|
||||||
for (auto b : v[a]) {
|
% for (auto b : v[a]) {
|
||||||
if (distance[a]+b.second < distance[b.first]) {
|
% if (distance[a]+b.second < distance[b.first]) {
|
||||||
distance[b.first] = distance[a]+b.second;
|
% distance[b.first] = distance[a]+b.second;
|
||||||
if (!inqueue[b]) {q.push(b); inqueue[b] = true;}
|
% if (!inqueue[b]) {q.push(b); inqueue[b] = true;}
|
||||||
}
|
% }
|
||||||
}
|
% }
|
||||||
}
|
% }
|
||||||
\end{lstlisting}
|
% \end{lstlisting}
|
||||||
|
|
||||||
The efficiency of the SPFA algorithm depends
|
The efficiency of the SPFA algorithm depends
|
||||||
on the structure of the graph:
|
on the structure of the graph:
|
||||||
|
@ -542,8 +539,10 @@ compensates the previous large weight $6$.
|
||||||
The following implementation of Dijkstra's algorithm
|
The following implementation of Dijkstra's algorithm
|
||||||
calculates the minimum distances from a node $x$
|
calculates the minimum distances from a node $x$
|
||||||
to all other nodes.
|
to all other nodes.
|
||||||
The graph is stored in an array \texttt{v}
|
The graph is stored as adjacency lists
|
||||||
as adjacency lists like in the Bellman–Ford algorithm.
|
so that \texttt{adj[$a$]} contains a pair $(b,w)$
|
||||||
|
always when there is an edge from node $a$ to node $b$
|
||||||
|
with weight $w$.
|
||||||
|
|
||||||
An efficient implementation of Dijkstra's algorithm
|
An efficient implementation of Dijkstra's algorithm
|
||||||
requires that it is possible to efficiently find the
|
requires that it is possible to efficiently find the
|
||||||
|
@ -553,43 +552,41 @@ that contains the nodes ordered by their distances.
|
||||||
Using a priority queue, the next node to be processed
|
Using a priority queue, the next node to be processed
|
||||||
can be retrieved in logarithmic time.
|
can be retrieved in logarithmic time.
|
||||||
|
|
||||||
In the following implementation,
|
The following implementation uses a priority queue
|
||||||
the priority queue contains pairs whose first
|
\texttt{q} that contains pairs of the form $(-d,x)$:
|
||||||
element is the current distance to the node and second
|
the current distance to node $x$ is $d$.
|
||||||
element is the identifier of the node.
|
The array $\texttt{dist}$ contains the distance to
|
||||||
\begin{lstlisting}
|
each node, and the array $\texttt{ready}$ indicates
|
||||||
priority_queue<pair<int,int>> q;
|
whether a node has been processed.
|
||||||
\end{lstlisting}
|
Initially the distance to $0$ to $x$ and $\infty$ to all other nodes.
|
||||||
A small difficulty is that in Dijkstra's algorithm,
|
|
||||||
we should find the node with the \emph{minimum} distance,
|
|
||||||
while the C++ priority queue finds the \emph{maximum}
|
|
||||||
element by default.
|
|
||||||
An easy trick is to use \emph{negative} distances,
|
|
||||||
which allows us to directly use the C++ priority queue.
|
|
||||||
|
|
||||||
The code keeps track of processed nodes
|
|
||||||
in an array \texttt{ready},
|
|
||||||
and maintains the distances in an array \texttt{distance}.
|
|
||||||
Initially, the distance to the starting node is 0,
|
|
||||||
and the distance to all other nodes is infinite.
|
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int i = 1; i <= n; i++) distance[i] = INF;
|
for (int i = 1; i <= n; i++) dist[i] = INF;
|
||||||
distance[x] = 0;
|
dist[x] = 0;
|
||||||
q.push({0,x});
|
q.push({0,x});
|
||||||
while (!q.empty()) {
|
while (!q.empty()) {
|
||||||
int a = q.top().second; q.pop();
|
int a = q.top().second; q.pop();
|
||||||
if (ready[a]) continue;
|
if (ready[a]) continue;
|
||||||
ready[a] = true;
|
ready[a] = true;
|
||||||
for (auto b : v[a]) {
|
for (auto u : v[a]) {
|
||||||
if (distance[a]+b.second < distance[b.first]) {
|
int b = u.first, w = u.second;
|
||||||
distance[b.first] = distance[a]+b.second;
|
if (dist[a]+w < dist[b]) {
|
||||||
q.push({-distance[b.first],b.first});
|
dist[b] = dist[a]+w;
|
||||||
|
q.push({-dist[b],b});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Note that the priority queue contains \emph{negative}
|
||||||
|
distances to nodes.
|
||||||
|
The reason for this is that the C++ priority queue finds the \emph{maximum}
|
||||||
|
element by default while we would like to find \emph{minimum} elements.
|
||||||
|
By using negative distances,
|
||||||
|
we can directly use the default version of the C++ priority queue\footnote{Of
|
||||||
|
course, we could also declare the priority queue as in Chapter 4.5
|
||||||
|
and use positive distances, but the implementation would be a bit longer.}.
|
||||||
|
|
||||||
The time complexity of the above implementation is
|
The time complexity of the above implementation is
|
||||||
$O(n+m \log m)$ because the algorithm goes through
|
$O(n+m \log m)$ because the algorithm goes through
|
||||||
all nodes in the graph and adds for each edge
|
all nodes in the graph and adds for each edge
|
||||||
|
@ -761,17 +758,17 @@ The advantage of the
|
||||||
Floyd–Warshall algorithm that it is
|
Floyd–Warshall algorithm that it is
|
||||||
easy to implement.
|
easy to implement.
|
||||||
The following code constructs a
|
The following code constructs a
|
||||||
distance matrix \texttt{d} where $\texttt{d}[a][b]$
|
distance matrix where $\texttt{dist}[a][b]$
|
||||||
is the shortest distance between nodes $a$ and $b$.
|
is the shortest distance between nodes $a$ and $b$.
|
||||||
First, the algorithm initializes \texttt{d}
|
First, the algorithm initializes \texttt{dist}
|
||||||
using the adjacency matrix \texttt{v} of the graph:
|
using the adjacency matrix \texttt{mat} of the graph:
|
||||||
|
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
for (int j = 1; j <= n; j++) {
|
for (int j = 1; j <= n; j++) {
|
||||||
if (i == j) d[i][j] = 0;
|
if (i == j) dist[i][j] = 0;
|
||||||
else if (v[i][j]) d[i][j] = v[i][j];
|
else if (mat[i][j]) dist[i][j] = mat[i][j];
|
||||||
else d[i][j] = INF;
|
else dist[i][j] = INF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
@ -782,7 +779,7 @@ After this, the shortest distances can be found as follows:
|
||||||
for (int k = 1; k <= n; k++) {
|
for (int k = 1; k <= n; k++) {
|
||||||
for (int i = 1; i <= n; i++) {
|
for (int i = 1; i <= n; i++) {
|
||||||
for (int j = 1; j <= n; j++) {
|
for (int j = 1; j <= n; j++) {
|
||||||
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
|
dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -790,7 +787,7 @@ for (int k = 1; k <= n; k++) {
|
||||||
|
|
||||||
The time complexity of the algorithm is $O(n^3)$,
|
The time complexity of the algorithm is $O(n^3)$,
|
||||||
because it contains three nested loops
|
because it contains three nested loops
|
||||||
that go through the nodes in the graph.
|
that go through the nodes of the graph.
|
||||||
|
|
||||||
Since the implementation of the Floyd–Warshall
|
Since the implementation of the Floyd–Warshall
|
||||||
algorithm is simple, the algorithm can be
|
algorithm is simple, the algorithm can be
|
||||||
|
|
|
@ -101,7 +101,7 @@ The following recursive function can be used:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
void dfs(int s, int e) {
|
void dfs(int s, int e) {
|
||||||
// process node s
|
// process node s
|
||||||
for (auto u : v[s]) {
|
for (auto u : adj[s]) {
|
||||||
if (u != e) dfs(u, s);
|
if (u != e) dfs(u, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ recursively using the following code:
|
||||||
\begin{lstlisting}
|
\begin{lstlisting}
|
||||||
void dfs(int s, int e) {
|
void dfs(int s, int e) {
|
||||||
count[s] = 1;
|
count[s] = 1;
|
||||||
for (auto u : v[s]) {
|
for (auto u : adj[s]) {
|
||||||
if (u == e) continue;
|
if (u == e) continue;
|
||||||
dfs(u, s);
|
dfs(u, s);
|
||||||
count[s] += count[u];
|
count[s] += count[u];
|
||||||
|
|
Loading…
Reference in New Issue