Examine individual changes
Appearance
This page allows you to examine the variables generated by the Edit Filter for an individual change.
Variables generated for this change
Variable | Value |
---|---|
Edit count of the user (user_editcount ) | 3 |
Name of the user account (user_name ) | 'DollarAkshay' |
Age of the user account (user_age ) | 21819154 |
Groups (including implicit) the user is in (user_groups ) | [
0 => '*',
1 => 'user'
] |
Rights that the user has (user_rights ) | [
0 => 'createaccount',
1 => 'read',
2 => 'edit',
3 => 'createtalk',
4 => 'writeapi',
5 => 'viewmywatchlist',
6 => 'editmywatchlist',
7 => 'viewmyprivateinfo',
8 => 'editmyprivateinfo',
9 => 'editmyoptions',
10 => 'abusefilter-log-detail',
11 => 'urlshortener-create-url',
12 => 'centralauth-merge',
13 => 'abusefilter-view',
14 => 'abusefilter-log',
15 => 'vipsscaler-test',
16 => 'collectionsaveasuserpage',
17 => 'reupload-own',
18 => 'move-rootuserpages',
19 => 'createpage',
20 => 'minoredit',
21 => 'editmyusercss',
22 => 'editmyuserjson',
23 => 'editmyuserjs',
24 => 'purge',
25 => 'sendemail',
26 => 'applychangetags',
27 => 'spamblacklistlog',
28 => 'mwoauthmanagemygrants'
] |
Whether the user is editing from mobile app (user_app ) | false |
Whether or not a user is editing through the mobile interface (user_mobile ) | false |
Page ID (page_id ) | 8818504 |
Page namespace (page_namespace ) | 0 |
Page title without namespace (page_title ) | '2-opt' |
Full page title (page_prefixedtitle ) | '2-opt' |
Edit protection level of the page (page_restrictions_edit ) | [] |
Last ten users to contribute to the page (page_recent_contributors ) | [
0 => 'DollarAkshay',
1 => 'Sagarw10',
2 => 'Gabrieldelai',
3 => '2A01:4B00:869F:ED00:A98E:4253:5A97:246C',
4 => 'WikiCleanerBot',
5 => 'Amakuha',
6 => 'GünniX',
7 => 'BartDioos',
8 => 'AnomieBOT',
9 => '87.74.230.212'
] |
Page age in seconds (page_age ) | 483370370 |
Action (action ) | 'edit' |
Edit summary/reason (summary ) | 'Adding efficient c++ implementation to do 2-opt swaps' |
Old content model (old_content_model ) | 'wikitext' |
New content model (new_content_model ) | 'wikitext' |
Old page wikitext, before the edit (old_wikitext ) | '[[File:2-opt wiki.svg|thumb|2-opt]]
In [[Optimization (mathematics)|optimization]], '''2-opt''' is a simple local search algorithm for solving the [[traveling salesman problem]].
The 2-opt algorithm was first proposed by Croes in 1958,<ref>G. A. Croes, A method for solving traveling salesman problems. Operations Res. 6 (1958) , pp., 791-812. </ref> although the basic move had already been suggested by Flood.<ref>M. M. Flood, The traveling-salesman problem. Operations Res. 4 (1956) , pp., 61-75.</ref> The main idea behind it is to take a route that crosses over itself and reorder it so that it does not.
- A B - - A - B -
× ==>
- C D - - C - D -
A complete 2-opt local search will compare every possible valid combination of the swapping mechanism. This technique can be applied to the traveling salesman problem as well as many related problems. These include the [[vehicle routing problem]] (VRP) as well as the capacitated VRP, which require minor modification of the algorithm.
This is the mechanism by which the 2-opt swap manipulates a given route. Here v1 and v2 are the first vertices of the edges you wish to swap when traversing through the route:
'''procedure''' 2optSwap(route, v1, v2) {
1. take route[0] to route[v1] and add them in order to new_route
2. take route[v1+1] to route[v2] and add them in reverse order to new_route
3. take route[v2+1] to route[end] and add them in order to new_route
'''return''' new_route;
}
Here is an example of the above with arbitrary input:
* Example route: A → B → E → D → C → F → G → H → A
* Example parameters: v1=1, v2=4 (starting index 0)
* Contents of new_route by step:
*# '''(A → B)'''
*# A → B → '''(C → D → E)'''
*# A → B → C → D → E → '''(F → G → H → A)'''
This is the complete 2-opt swap making use of the above mechanism:
'''repeat until''' no improvement is made {
best_distance = calculateTotalDistance(existing_route)
start_again:
'''for''' (i = 0; i <= number of nodes eligible to be swapped - 1; i++) {
'''for''' (j = i + 1; j <= number of nodes eligible to be swapped; j++) {
new_route = 2optSwap(existing_route, i, j)
new_distance = calculateTotalDistance(new_route)
'''if''' (new_distance < best_distance) {
existing_route = new_route
best_distance = new_distance
goto start_again
}
}
}
}
Note: If you start/end at a particular node or depot, then you must remove this from the search as an eligible candidate for swapping, as reversing the order will cause an invalid path.
For example, with depot at A:
A → B → C → D → A
Swapping using node[0] and node[2] would yield
C → B → A → D → A
which is not valid (does not leave from A, the depot).
==See also==
*[[3-opt]]
*[[local search (optimization)]]
*[[Lin–Kernighan heuristic]]
==References==
{{Reflist}}
* {{cite book|author = G. A. CROES | year = 1958 | title = A method for solving traveling salesman problems | publisher = Operations Res. 6 (1958) , pp., 791-812.}}
* {{cite book|author = M. M. FLOOD | year = 1956 | title = The traveling-salesman problem | publisher = Operations Res. 4 (1956) , pp., 61-75.}}
==External links==
*[https://www.cs.ubc.ca/~hutter/previous-earg/EmpAlgReadingGroup/TSP-JohMcg97.pdf The Traveling Salesman Problem: A Case Study in Local Optimization]
*[http://www-e.uni-magdeburg.de/mertens/TSP/node3.html Improving Solutions: 2-opt Exchanges]
[[Category:Heuristic algorithms]]
[[Category:Travelling salesman problem]]' |
New page wikitext, after the edit (new_wikitext ) | '[[File:2-opt wiki.svg|thumb|2-opt]]
In [[Optimization (mathematics)|optimization]], '''2-opt''' is a simple local search algorithm for solving the [[traveling salesman problem]].
The 2-opt algorithm was first proposed by Croes in 1958,<ref>G. A. Croes, A method for solving traveling salesman problems. Operations Res. 6 (1958) , pp., 791-812. </ref> although the basic move had already been suggested by Flood.<ref>M. M. Flood, The traveling-salesman problem. Operations Res. 4 (1956) , pp., 61-75.</ref> The main idea behind it is to take a route that crosses over itself and reorder it so that it does not.
- A B - - A - B -
× ==>
- C D - - C - D -
A complete 2-opt local search will compare every possible valid combination of the swapping mechanism. This technique can be applied to the traveling salesman problem as well as many related problems. These include the [[vehicle routing problem]] (VRP) as well as the capacitated VRP, which require minor modification of the algorithm.
This is the mechanism by which the 2-opt swap manipulates a given route. Here v1 and v2 are the first vertices of the edges you wish to swap when traversing through the route:
'''procedure''' 2optSwap(route, v1, v2) {
1. take route[0] to route[v1] and add them in order to new_route
2. take route[v1+1] to route[v2] and add them in reverse order to new_route
3. take route[v2+1] to route[end] and add them in order to new_route
'''return''' new_route;
}
Here is an example of the above with arbitrary input:
* Example route: A → B → E → D → C → F → G → H → A
* Example parameters: v1=1, v2=4 (starting index 0)
* Contents of new_route by step:
*# '''(A → B)'''
*# A → B → '''(C → D → E)'''
*# A → B → C → D → E → '''(F → G → H → A)'''
This is the complete 2-opt swap making use of the above mechanism:
'''repeat until''' no improvement is made {
best_distance = calculateTotalDistance(existing_route)
start_again:
'''for''' (i = 0; i <= number of nodes eligible to be swapped - 1; i++) {
'''for''' (j = i + 1; j <= number of nodes eligible to be swapped; j++) {
new_route = 2optSwap(existing_route, i, j)
new_distance = calculateTotalDistance(new_route)
'''if''' (new_distance < best_distance) {
existing_route = new_route
best_distance = new_distance
goto start_again
}
}
}
}
Note: If you start/end at a particular node or depot, then you must remove this from the search as an eligible candidate for swapping, as reversing the order will cause an invalid path.
For example, with depot at A:
A → B → C → D → A
Swapping using node[0] and node[2] would yield
C → B → A → D → A
which is not valid (does not leave from A, the depot).
== Efficient Implementation ==
Building the new route and calculating the distance of the new route can be a very expensive operation, usually <math>O(n)</math> where '''n''' is the number of vertices in the route. This can be converted into an <math>O(1)</math> operation. Since a 2-opt operation involves removing 2 edges and adding 2 different edges we can subtract and add the distances of only those edges.
lengthDelta = - dist(route[v1], route[v1+1]) - dist(route[v2], route[v2+1]) + dist(route[v1+1], route[v2+1])
If <code>lengthDelta</code> is negative that would mean that the new distance after the swap would be smaller. Once it is known that <code>lengthDelta</code> is negative, then we perform a 2-opt swap. This saves us a lot of computation.
Also using squared distances there helps reduce the computation by skipping a square root function call. Since we only care about comparing two distances and not the exact distance, this will help speed things up. Its not much, but it helps with large problems that have small time constraints.
<syntaxhighlight lang="c++">
void do2Opt(vector<Point> &path, int i, int j) {
reverse(begin(path) + i + 1, begin(path) + j + 1);
}
vector<Point> path = ...a vector of x,y points...; // The starting vertex is not included at the end
int curLength = pathLengthSq(path); // Squared length of the entire path, including the distance from last vertex to the first
int n = path.size();
bool foundImprovement = true;
while (foundImprovement) {
foundImprovement = false;
for(int i=0; i <= n - 2; i++) {
for(int j=i+1; j <= n - 1; j++) {
int lengthDelta = - path[i].dist2(path[i + 1 % n]) - path[j].dist2(path[(j + 1) % n])
+ path[i].dist2(path[j]) + path[i + 1 % n].dist2(path[(j + 1) % n]);
// If the length of the path is reduced, do a 2-opt swap
if (lengthDelta < 0) {
do2Opt(path, i, j);
curLength += lengthDelta;
foundImprovement = true;
}
}
}
}
</syntaxhighlight>
==See also==
*[[3-opt]]
*[[local search (optimization)]]
*[[Lin–Kernighan heuristic]]
==References==
{{Reflist}}
* {{cite book|author = G. A. CROES | year = 1958 | title = A method for solving traveling salesman problems | publisher = Operations Res. 6 (1958) , pp., 791-812.}}
* {{cite book|author = M. M. FLOOD | year = 1956 | title = The traveling-salesman problem | publisher = Operations Res. 4 (1956) , pp., 61-75.}}
==External links==
*[https://www.cs.ubc.ca/~hutter/previous-earg/EmpAlgReadingGroup/TSP-JohMcg97.pdf The Traveling Salesman Problem: A Case Study in Local Optimization]
*[http://www-e.uni-magdeburg.de/mertens/TSP/node3.html Improving Solutions: 2-opt Exchanges]
[[Category:Heuristic algorithms]]
[[Category:Travelling salesman problem]]' |
Unified diff of changes made by edit (edit_diff ) | '@@ -55,4 +55,44 @@
which is not valid (does not leave from A, the depot).
+
+== Efficient Implementation ==
+
+Building the new route and calculating the distance of the new route can be a very expensive operation, usually <math>O(n)</math> where '''n''' is the number of vertices in the route. This can be converted into an <math>O(1)</math> operation. Since a 2-opt operation involves removing 2 edges and adding 2 different edges we can subtract and add the distances of only those edges.
+
+ lengthDelta = - dist(route[v1], route[v1+1]) - dist(route[v2], route[v2+1]) + dist(route[v1+1], route[v2+1])
+
+If <code>lengthDelta</code> is negative that would mean that the new distance after the swap would be smaller. Once it is known that <code>lengthDelta</code> is negative, then we perform a 2-opt swap. This saves us a lot of computation.
+
+Also using squared distances there helps reduce the computation by skipping a square root function call. Since we only care about comparing two distances and not the exact distance, this will help speed things up. Its not much, but it helps with large problems that have small time constraints.
+
+<syntaxhighlight lang="c++">
+
+void do2Opt(vector<Point> &path, int i, int j) {
+ reverse(begin(path) + i + 1, begin(path) + j + 1);
+}
+
+vector<Point> path = ...a vector of x,y points...; // The starting vertex is not included at the end
+int curLength = pathLengthSq(path); // Squared length of the entire path, including the distance from last vertex to the first
+int n = path.size();
+bool foundImprovement = true;
+
+while (foundImprovement) {
+ foundImprovement = false;
+
+ for(int i=0; i <= n - 2; i++) {
+ for(int j=i+1; j <= n - 1; j++) {
+ int lengthDelta = - path[i].dist2(path[i + 1 % n]) - path[j].dist2(path[(j + 1) % n])
+ + path[i].dist2(path[j]) + path[i + 1 % n].dist2(path[(j + 1) % n]);
+
+ // If the length of the path is reduced, do a 2-opt swap
+ if (lengthDelta < 0) {
+ do2Opt(path, i, j);
+ curLength += lengthDelta;
+ foundImprovement = true;
+ }
+ }
+ }
+}
+</syntaxhighlight>
==See also==
' |
New page size (new_size ) | 5783 |
Old page size (old_size ) | 3677 |
Size change in edit (edit_delta ) | 2106 |
Lines added in edit (added_lines ) | [
0 => '',
1 => '== Efficient Implementation ==',
2 => '',
3 => 'Building the new route and calculating the distance of the new route can be a very expensive operation, usually <math>O(n)</math> where '''n''' is the number of vertices in the route. This can be converted into an <math>O(1)</math> operation. Since a 2-opt operation involves removing 2 edges and adding 2 different edges we can subtract and add the distances of only those edges.',
4 => '',
5 => ' lengthDelta = - dist(route[v1], route[v1+1]) - dist(route[v2], route[v2+1]) + dist(route[v1+1], route[v2+1]) ',
6 => '',
7 => 'If <code>lengthDelta</code> is negative that would mean that the new distance after the swap would be smaller. Once it is known that <code>lengthDelta</code> is negative, then we perform a 2-opt swap. This saves us a lot of computation.',
8 => '',
9 => 'Also using squared distances there helps reduce the computation by skipping a square root function call. Since we only care about comparing two distances and not the exact distance, this will help speed things up. Its not much, but it helps with large problems that have small time constraints.',
10 => '',
11 => '<syntaxhighlight lang="c++">',
12 => '',
13 => 'void do2Opt(vector<Point> &path, int i, int j) {',
14 => ' reverse(begin(path) + i + 1, begin(path) + j + 1);',
15 => '}',
16 => '',
17 => 'vector<Point> path = ...a vector of x,y points...; // The starting vertex is not included at the end',
18 => 'int curLength = pathLengthSq(path); // Squared length of the entire path, including the distance from last vertex to the first',
19 => 'int n = path.size();',
20 => 'bool foundImprovement = true;',
21 => '',
22 => 'while (foundImprovement) {',
23 => ' foundImprovement = false;',
24 => '',
25 => ' for(int i=0; i <= n - 2; i++) {',
26 => ' for(int j=i+1; j <= n - 1; j++) {',
27 => ' int lengthDelta = - path[i].dist2(path[i + 1 % n]) - path[j].dist2(path[(j + 1) % n])',
28 => ' + path[i].dist2(path[j]) + path[i + 1 % n].dist2(path[(j + 1) % n]);',
29 => '',
30 => ' // If the length of the path is reduced, do a 2-opt swap',
31 => ' if (lengthDelta < 0) {',
32 => ' do2Opt(path, i, j);',
33 => ' curLength += lengthDelta;',
34 => ' foundImprovement = true;',
35 => ' }',
36 => ' }',
37 => ' }',
38 => '}',
39 => '</syntaxhighlight>'
] |
Lines removed in edit (removed_lines ) | [] |
All external links added in the edit (added_links ) | [] |
All external links removed in the edit (removed_links ) | [] |
All external links in the new text (all_links ) | [
0 => 'https://www.cs.ubc.ca/~hutter/previous-earg/EmpAlgReadingGroup/TSP-JohMcg97.pdf',
1 => 'http://www-e.uni-magdeburg.de/mertens/TSP/node3.html'
] |
Links in the page, before the edit (old_links ) | [
0 => 'http://www-e.uni-magdeburg.de/mertens/TSP/node3.html',
1 => 'https://www.cs.ubc.ca/~hutter/previous-earg/EmpAlgReadingGroup/TSP-JohMcg97.pdf'
] |
Whether or not the change was made through a Tor exit node (tor_exit_node ) | false |
Unix timestamp of change (timestamp ) | 1651610583 |