Slow Entity Spatial Query - c#

I am trying to create a method to lookup locations stored in my entity database. I am attempting to do this using the DbGeography class and in soem cases i am having success but often the operation times out.
The data set i am working with is around 420,000 records and often my queries take around 30 seconds when they don't fail. Is this normal performance for my current usage?
This is my code,
private List<TransportStop> StopsNearby(double latitude, double longitude, double radiusInKm)
{
var location = CreatePoint(latitude, longitude);
var radiusInMeters = radiusInKm * 1000;
var stops =
from c in Data.Naptans
let distance = c.L.Distance(location)
where distance <= radiusInMeters
select c;
return stops.ToList();
}

Try to change your method to Task like that:
public Task<List<TransportStop>> StopsNearby(double latitude, double longitude, double radiusInKm)
{
var location = CreatePoint(latitude, longitude);
var radiusInMeters = radiusInKm * 1000;
var stops =
from c in Data.Naptans
let distance = c.L.Distance(location)
where distance <= radiusInMeters
select c;
return stops.ToList();
}
And then the reference to call this method is like that:
public async Task Test()
{
var stopsNearby = await StopsNearby(1, 1, 1);
}

Related

Using Math.NET Numerics is it possible to generate a normally distributed sample with upper and lower bounds?

It's very easy to generate normally distributed data with a desired mean and standard distribution:
IEnumerable<double> sample = MathNet.Numerics.Distributions.Normal.Samples(mean, sd).Take(n);
However with a sufficiently large value for n you will get values miles away from the mean. To put it into context I have a real world data set with mean = 15.93 and sd = 6.84. For this data set it is impossible to have a value over 30 or under 0, but I cannot see a way to add upper and lower bounds to the data that is generated.
I can remove data that falls outside of this range as below, but this results in the mean and SD for the generated sample differing significantly (in my opinion, probably not statistically) from the values I requested.
Normal.Samples(mean, sd).Where(x => x is >= 0 and <= 30).Take(n);
Is there any way to ensure that the values generated fall within a specified range without effecting the mean and SD of the generated data?
The following proposed solution relies on a specific formula for calculating the standard deviation relative to the bounds: the standard deviation has to be a third of the difference between the mean and the required minimum or maximum.
This first code block is the TruncatedNormalDistribution class, which encapsulates MathNet's Normal class. The main technique for making a truncated normal distribution is in the constructor. Note the resulting workaround that is required in the Sample method:
using MathNet.Numerics.Distributions;
public class TruncatedNormalDistribution {
public TruncatedNormalDistribution(double xMin, double xMax) {
XMin = xMin;
XMax = xMax;
double mean = XMin + (XMax - XMin) / 2; // Halfway between minimum and maximum.
// If the standard deviation is a third of the difference between the mean and
// the required minimum or maximum of a normal distribution, 99.7% of samples should
// be in the required range.
double standardDeviation = (mean - XMin) / 3;
Distribution = new Normal(mean, standardDeviation);
}
private Normal Distribution { get; }
private double XMin { get; }
private double XMax { get; }
public double CumulativeDistribution(double x) {
return Distribution.CumulativeDistribution(x);
}
public double Density(double x) {
return Distribution.Density(x);
}
public double Sample() {
// Constrain results lower than XMin or higher than XMax
// to those bounds.
return Math.Clamp(Distribution.Sample(), XMin, XMax);
}
}
And here is a usage example. For a visual representation of the results, open each of the two output CSV files in a spreadsheet, such as Excel, and map its data to a line chart:
// Put the path of the folder where the CSVs will be saved here
const string chartFolderPath =
#"C:\Insert\chart\folder\path\here";
const double xMin = 0;
const double xMax = 100;
var distribution = new TruncatedNormalDistribution(xMin, xMax);
// Densities
var dictionary = new Dictionary<double, double>();
for (double x = xMin; x <= xMax; x += 1) {
dictionary.Add(x, distribution.Density(x));
}
string csvPath = Path.Combine(
chartFolderPath,
$"Truncated Normal Densities, Range {xMin} to {xMax}.csv");
using var writer = new StreamWriter(csvPath);
foreach ((double key, double value) in dictionary) {
writer.WriteLine($"{key},{value}");
}
// Cumulative Distributions
dictionary.Clear();
for (double x = xMin; x <= xMax; x += 1) {
dictionary.Add(x, distribution.CumulativeDistribution(x));
}
csvPath = Path.Combine(
chartFolderPath,
$"Truncated Normal Cumulative Distributions, Range {xMin} to {xMax}.csv");
using var writer2 = new StreamWriter(csvPath);
foreach ((double key, double value) in dictionary) {
writer2.WriteLine($"{key},{value}");
}

How to use the Nelder Meade Simplex algorithm in mathdotnet for function maximization

In my C# program I have a dataset where each data point consists of:
a stimulus intensity (intensity) as x-coordinate
the percentage of correct response (percentageCorrect) to stimulus as y-coordinate
When the intensity is low percentageCorrect is low. When the intensity is high the percentageCorrect is high. The function graph is an S-shaped curve as the percentageCorrect reaches an asymptote at low and high ends.
I am trying to find the threshold intensity where percentageCorrect is half way between the asymtotes at either end (center of the S-shaped curve)
I understand this to be a function maximization problem that can be solved by the Nelder Meade Simplex algorithm.
I am trying to solve my problem using the Nelder Meade Simplex algorithm in mathdotnet and its IObjectiveFunction parameter.
However, I am having trouble understanding the API of the NedlerMeadeSimplex class FindMinimum method and the IObjectiveFunction EvaluateAt method.
I am new to numerical analysis that is pre-requisite for this question.
Specific questions are:
For the NedlerMeadeSimplex class FindMinimum method what are the initialGuess and initialPertubation parameters?
For the IObjectiveFunction EvaluateAt method, what is the point parameter? I vaguely understand that the point parameter is a datum in the dataset being minimized
How can I map my data set to this API and solve my problem?
Thanks for any guidance on this.
The initial guess is a guess at the model parameters.
I've always used the forms that don't require an entry of the initialPertubation parameter, so I can't help you there.
The objective function is what your are trying to minimize. For example, for a least squares fit, it would calculate the sum of squared areas at the point given in the argument. Something like this:
private double SumSqError(Vector<double> v)
{
double err = 0;
for (int i = 0; i < 100; i++)
{
double y_val = v[0] + v[1] * Math.Exp(v[2] * x[i]);
err += Math.Pow(y_val - y[i], 2);
}
return err;
}
You don't have to supply the point. The algorithm does that over and over while searching for the minimum. Note that the subroutine as access to the vector x.
Here is the code for a test program fitting a function to random data:
private void btnMinFit_Click(object sender, EventArgs e)
{
Random RanGen = new Random();
x = new double[100];
y = new double[100];
// fit exponential expression with three parameters
double a = 5.0;
double b = 0.5;
double c = 0.05;
// create data set
for (int i = 0; i < 100; i++) x[i] = 10 + Convert.ToDouble(i) * 90.0 / 99.0; // values span 10 to 100
for (int i = 0; i < 100; i++)
{
double y_val = a + b * Math.Exp(c * x[i]);
y[i] = y_val + 0.1 * RanGen.NextDouble() * y_val; // add error term scaled to y-value
}
// var fphv = new Func<double, double, double, double>((x, A, B) => A * x + B * x + A * B * x * x); extraneous test
var f1 = new Func<Vector<double>, double>(x => LogEval(x));
var obj = ObjectiveFunction.Value(f1);
var solver = new NelderMeadSimplex(1e-5, maximumIterations: 10000);
var initialGuess = new DenseVector(new[] { 3.0, 6.0, 0.6 });
var result = solver.FindMinimum(obj, initialGuess);
Console.WriteLine(result.MinimizingPoint.ToString());
}

Checking if 2 geolocations with radius are within eachothers radius

I'm trying to determine if a tracker is within 5km of it's destination.
This tracker has a Lat, Lng and Accuracy
So this would give us
public static void Main()
{
// Current location
var trackerLat = <Lat>;
var trackerLng = <Lng>;
var trackerAcc = 150;
// Destination
var destinationLat = <Lat>;
var destinationLng = <Lng>;
var withingRange = 5000;
if (isWithingRange(trackerLat, trackerLng, trackerAcc, destinationLat, destinationLng, withingRange))
Console.WriteLine("Close");
else
Console.WriteLine("Not close");
}
private static bool isWithingRange(double c1x, double c1y, double r1, double c2x, double c2y, double r2) {
var dX = c1x - c2x;
var dY = c1y - c2y;
var radius = r1 + r2;
var distsqt = Math.Sqrt((dX * dX) + (dY * dY));
Console.WriteLine(String.Format("Val1: {0}, val2: {1}", distsqt, radius));
if (distsqt < radius)
return true;
else
return false;
}
But this says it's always within range :(
I would think the range format is wrong compared to the coordinate system, but I can't seem to find on how to convert it correctly
fiddle: https://dotnetfiddle.net/FEGC2B
Take a look at GeoCoordinate (System.Device.Location). It has a GetDistanceTo() method that gives you the distance in meters to another GeoCoordinate.
https://learn.microsoft.com/en-us/dotnet/api/system.device.location.geocoordinate
Use System.Device:
var location1 = new System.Device.Location.GeoCoordinate(latitude1, longitude1);
var location2 = new System.Device.Location.GeoCoordinate(latitude2, longitude2);
return location1.GetDistanceTo(location2) <= (radius1 + radius2);

LINQ command for data reduction of GPS data

I have this:
public class LatLon
{
public double lat {get;set;}
public double lon {get;set;}
}
in a List<LatLon>. It contains of
p1 { lat = 49.9429989, lon = 3.9542134 }
p2 { lat = 49.9429989, lon = 3.9542133 }
p3 { lat = 49.9429989, lon = 3.9542136 }
etc..
My goal is to remove coordinates from this list whose difference to other coordinates is lower than the boundaries of lat_bound and lon_bound, so even though the person recording stood at a place for a long time, it means there is only one coordinate left. What would be the LINQ command?
Example:
p1 { lat = 4.555, lon = 6.555 }
p2 { lat = 4.556, lon = 6.556 }
.
Then Math.Abs(p1.lat - p2.lat) = 0.001 and Math.Abs(p1.lon - p2.lon) = 0.001. p1.lon - p2.lon is the lon difference to one other coordinate's lon-value. Let's say lon_bound equals 0.0005 then this very coordinate is being removed if lat_bound is also 0.0005, as 0.001 > 0.0005.
EDIT: I decided to pipe to http://www.gpsbabel.org instead.
LINQ Does not make wonders. The problem you are referring to is not just a "Distict" type problem.
1st You have to make a function to measure distance between 2 points.
2nd You need to detect clusters of points..(organize close points into groups)
Finally the easiest thing to do is to Group By a Belonging cluster and keep only 1point from each group.....
But then again.....there are several other problems which might not produce accurate results.
For example whats the one point that represents its group best?
You can use Math.Round to round the values to the precision that you want.
Then use Linq Distinct to remove the duplicates.
void Main()
{
var list = new List<Coordinate>()
{
new Coordinate(25.25251, 100.21254),
new Coordinate(25.25252, 100.21255),
new Coordinate(25.25253, 100.21256),
new Coordinate(25.80000, 100.90000)
};
int precision = 4;
var res = list.Select(x => new Coordinate(
Math.Round(x.Lon, precision),
Math.Round(x.Lat, precision))).Distinct().ToList();
}
public struct Coordinate
{
private double lon;
private double lat;
public Coordinate(double lon, double lat)
{
this.lon = lon;
this.lat = lat;
}
public double Lat { get { return lat; } }
public double Lon { get { return lon; } }
}
(Note that I have I'm using a struct and not a class for the Coordinate's)
If you have a function Func<LatLon, LatLon, bool> bounded that returns true if the two points are within your bound and false if not then this query works:
var keeps =
latlons
.Aggregate(new List<LatLon>(), (xs, y) =>
{
if (!xs.Any(x => bounded(x, y)))
{
xs.Add(y);
}
return xs;
});
You can filter by proximity like this:
public class LatLon
{
public double lat {get;set;}
public double lon {get;set;}
}
class ProximityFilter
{
private LatLon m_ref = null;
internal bool DifferentFromPrevious(LatLon arg)
{
if (m_ref == null)
{
m_ref = arg;
return true;
}
var are_different = Math.Abs(arg.lat - m_ref.lat) > 0.001 || Math.Abs(arg.lon - m_ref.lon) > 0.001;
if (are_different)
m_ref = arg;
return are_different;
}
}
class Program
{
static int Main(string[] args)
{
var p1 = new LatLon { lat = 49.9429989, lon = 3.9542134 };
var p2 = new LatLon { lat = 49.9529989, lon = 3.9642134 };
var p3 = new LatLon { lat = 49.9429989, lon = 3.9542133 };
var p4 = new LatLon { lat = 49.9429989, lon = 3.9542136 };
var list = new List<LatLon> {p1, p2, p3, p4};
var filter = new ProximityFilter();
var cleaned = list.Where(filter.DifferentFromPrevious);
// ...
}
}
You can't use Distinct as it will remove the point with a value seen before, even if there is a different value between them.
Additionally, this approach has O(N) complexity, so at least theoretically it performs better than Distinct. It also works both with structs and classes.

Convert latitude and longitude to utm point in 43 Zone

I have latitude and longitude points like(23.7019973789308,72.5465551902882)
like this, I have many point, who are enter by Users in my application,
I just want to convert them in Meters in 43 Zone in C#.
I did't get any suitable code, who can convert these points.
I go through this link also, but did't get solution.
http://www.igorexchange.com/node/927
I tried this code also....
static public IPoint FromLatLonToUTM(double lon, double lat, out double UTM_x, out double UTM_y)
{
ISpatialReferenceFactory2 pSpatRefFact;
IProjectedCoordinateSystem pToPCS;
IGeographicCoordinateSystem pFromGCS;
IGeometry pGeo ;
IPoint pPoint;
UTM_x = 0;
UTM_y = 0;
pPoint = new PointClass();
pPoint.PutCoords(lon, lat);
pSpatRefFact = new SpatialReferenceEnvironmentClass();
pFromGCS = pSpatRefFact.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_NAD1983);
pToPCS = pSpatRefFact.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_NAD1983UTM_17N);
pGeo = pPoint;
pGeo.SpatialReference = pFromGCS;
pGeo.Project (pToPCS);
pPoint = (IPoint) pGeo;
UTM_x = pPoint.X;
UTM_y = pPoint.Y;
Debug.Write(UTM_x);
Debug.WriteLine("");
Debug.Write(UTM_y);
Debug.WriteLine("");
return pPoint;
}
Help me.............

Categories

Resources