-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix GeoPatch algorithm #264
Changes from 3 commits
e93bf68
488f860
094d088
9896535
e5b0d04
7e67cde
6b722f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,73 +24,44 @@ defmodule ArchEthic.P2P.GeoPatch do | |
end | ||
|
||
defp compute_random_patch do | ||
list_char = Enum.concat([?0..?9, ?A..?F]) | ||
Enum.take_random(list_char, 3) |> List.to_string() | ||
list_char1 = Enum.concat([?0..?9, ?A..?F]) | ||
list_char2 = Enum.concat([?0..?3, ?C..?F]) | ||
|
||
Enum.take_random(list_char1, 2) | ||
|> List.insert_at(1, Enum.take_random(list_char2, 1)) | ||
|> List.to_string() | ||
end | ||
|
||
defp compute_patch(lat, lon) do | ||
lat_sign = sign(lat) | ||
lon_sign = sign(lon) | ||
|
||
fdc = [lat / 90, lon / 180] | ||
|
||
sd = | ||
[(lat - lat_sign * 45) / 2, (lon - lon_sign * 90) / 2] | ||
|> resolve_with_sign([lat, lon]) | ||
lon_pos = (lon + 180) / 22.5 | ||
# Adding 4 to have second digit hex value from C to 3 | ||
lat_pos = (lat + 90) / 22.5 + 4 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. avoid adding 4 and adding 90, 180 was in earlier implementation so, avoid it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hello ! The advantage of this implementation is that it takes less ressources and less execution times than the previous implementation, i.e guetting a value from an array by his index is faster than doing multiple if condition to find the good hexadecimal value. To be easier to read, instead of adding 4 to @samuel-uniris What is your advice about it ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So in term of performance pattern matching (multiple function clause) is like if/else block under the good bu is quite fast and optimized during compilation. Accessing a random element in a list is not the same in Erlang. List are not arrays but linked list , which means to access nth element, need to scan nth before . When the list is big is not efficient. There is different strategy for this problem. In term of readability the pattern matching is better when you have a several if/else/case blocks. For reusability, sure it's better to keep a main indexing/reference, but keep in mind it's function programming, so variables a immutable. So you get a new memory reference after each mutation or assignment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi ! Updated in last commit to use tuple. Using pattern matching function was not as easy to read because it needs to much function to catch all conditions. |
||
|
||
sdc = [List.first(sd) / 22.5, List.last(sd) / 45] | ||
first_digit = main_index_patch(trunc(lon_pos)) | ||
second_digit = main_index_patch(trunc(lat_pos)) | ||
|
||
td = | ||
[ | ||
(List.first(sd) - lat_sign * 11.25) / 2, | ||
(List.last(sd) - lon_sign * 22.5) / 2 | ||
] | ||
|> resolve_with_sign(sd) | ||
lat_precision = ((lat_pos - trunc(lat_pos)) / 0.25) |> trunc() | ||
lon_precision = ((lon_pos - trunc(lon_pos)) / 0.25) |> trunc() | ||
|
||
tdc = [List.first(td) / 5.625, List.last(td) / 11.25] | ||
third_digit = precision_index_patch(lat_precision, lon_precision) | ||
|
||
patch = | ||
[index_patch(fdc), index_patch(sdc), index_patch(tdc)] | ||
|> Enum.join("") | ||
|
||
patch | ||
[first_digit, second_digit, third_digit] | ||
|> Enum.join("") | ||
end | ||
|
||
defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < -0.5 and s_i >= -1, do: '0' | ||
defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 0 and s_i >= -0.5, do: '1' | ||
defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 0.5 and s_i >= 0, do: '2' | ||
defp index_patch([f_i, s_i]) when f_i > 0.5 and f_i <= 1 and s_i < 1 and s_i >= 0.5, do: '3' | ||
|
||
defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < -0.5 and s_i >= -1, do: '4' | ||
defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 0 and s_i >= -0.5, do: '5' | ||
defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 0.5 and s_i >= 0, do: '6' | ||
defp index_patch([f_i, s_i]) when f_i > 0 and f_i <= 0.5 and s_i < 1 and s_i >= 0.5, do: '7' | ||
|
||
defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < -0.5 and s_i >= -1, do: '8' | ||
defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 0 and s_i >= -0.5, do: '9' | ||
defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 0.5 and s_i >= 0, do: 'A' | ||
defp index_patch([f_i, s_i]) when f_i > -0.5 and f_i <= 0 and s_i < 1 and s_i >= 0.5, do: 'B' | ||
|
||
defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < -0.5 and s_i >= -1, do: 'C' | ||
defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 0 and s_i >= -0.5, do: 'D' | ||
defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 0.5 and s_i >= 0, do: 'E' | ||
defp index_patch([f_i, s_i]) when f_i > -1 and f_i <= -0.5 and s_i < 1 and s_i >= 0.5, do: 'F' | ||
|
||
defp sign(number) when number < 0, do: -1 | ||
defp sign(number) when number >= 0, do: 1 | ||
defp main_index_patch(index) do | ||
['8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7'] | ||
|> Enum.at(index) | ||
end | ||
|
||
defp resolve_with_sign([first, second], [first2, second2]) do | ||
defp precision_index_patch(index1, index2) do | ||
[ | ||
do_resolve_with_sign(first, first2), | ||
do_resolve_with_sign(second, second2) | ||
['0', '1', '2', '3'], | ||
['4', '5', '6', '7'], | ||
['8', '9', 'A', 'B'], | ||
['C', 'D', 'E', 'F'] | ||
] | ||
end | ||
|
||
defp do_resolve_with_sign(x1, x2) do | ||
if sign(x1) == sign(x2) do | ||
x1 | ||
else | ||
x2 / 2 | ||
end | ||
|> Enum.at(index1) | ||
|> Enum.at(index2) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@I-Archer-Zero
Looks like added 90,180 to avoid negative sign but look at
lat_pos
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It must be
lat_pos = (lat + 90) / 22.5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi !
Dividing lat by 22.5 will have a result between 0 and 8. But we are looking for a range between 0 and 16 to get all hexadecimal possibilities (0 to F).
So we have to divide by 11.25 to get it.
I think on issue's example there is a mismatch. On the graph, latitude only have 8 parts, but on explication bellow it says that first 2 digits are on range of 0 to F so 16 parts...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@I-Archer-Zero
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Neylix (Cc @samuel-uniris)
Good observation!
lat should be divided by 22.5 and not 11.25 because we need square patches (not rectangle)
This also means that the lat/22.5 will have a result between 0 to 8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi ! Thanks for your return.
I didn't know it had to be a square, I'll update it as you requested. Also need to add 4 to result to get index from C to 3 as in your graph.
I also noticed that in issue you say that first digit is for longitude index, but I did latitude first, should I update it too ?
I'm actually out of my PC until sunday, I'll update it at this time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello !
I fixed calculation in lastest commits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest you can you
>=
and<=
condition checks and fix the edge cases and also implement the algo as mentioned in #253. So, first digit and third digt can be [8,9,A,B,C,D,E,F,0,1,2,3,4,5,6,7] And second digit can be [C,D,E,F,0,1,2,3]As precision digit being computed as per previous implementation.