public void ParameterCyclingOptimizerReturnsValueCloseToOptimumOneParameter() { var expected = 42.0; var parameterSettings = new[] { new ParameterSetting(0, 50, 1, 30) }; Func <double[], double> costFunc = parameters => Math.Abs(expected - parameters[0]); var actual = ParameterCyclingOptimizer.Optimize(costFunc, parameterSettings, 100); Assert.That(actual.Parameters[0], Is.EqualTo(expected).Within(parameterSettings[0].StepSize)); }
public void ParameterCyclingOptimizerReturnsValueCloseToOptimumThreeParameters() { var expected = new double[] { 1, 13, -4 }; var parameterSettings = new[] { new ParameterSetting(0, 10, 0.1, Double.NaN), new ParameterSetting(5, 20, 0.5, 19), new ParameterSetting(-10, 10, 0.2, 1.1) }; Func <double[], double> costFunc = parameters => Math.Abs(expected[0] - parameters[0]) + Math.Abs(expected[1] - parameters[1]) + Math.Abs(expected[2] - parameters[2]); var actual = ParameterCyclingOptimizer.Optimize(costFunc, parameterSettings, 1000); for (int p = 0; p < expected.Length; p++) { Assert.That(actual.Parameters[p], Is.EqualTo(expected[p]).Within(parameterSettings[p].StepSize)); } }
public static IList <Point3D> Calculate(Image <Gray, byte> distanceMap) { var aminoAcidCount = distanceMap.Height; var aminoAcidPositions = new Point3D[aminoAcidCount]; // We need 3 reference points which will be our coordinate system // Reference 1: aminoAcidPositions[0] = new Point3D(0, 0, 0); var referenceIndices = new List <int> { 0 }; // Reference 2: var aminoAcidDistancesToRef0 = AminoAcidDistancesToIndex(distanceMap, 0); var mostDistantAminoAcid = aminoAcidDistancesToRef0.Select((distance, idx) => new { Index = idx, Distance = distance }) .Where(x => x.Distance < CutoffDistance) .MaximumItem(x => x.Distance); var mostDistantAminoAcidIdx = mostDistantAminoAcid.Index; aminoAcidPositions[mostDistantAminoAcidIdx] = new Point3D(mostDistantAminoAcid.Distance, 0, 0); referenceIndices.Add(mostDistantAminoAcidIdx); // Reference 3: var distanceRef0Ref1 = mostDistantAminoAcid.Distance; var aminoAcidDistancesToRef1 = AminoAcidDistancesToIndex(distanceMap, mostDistantAminoAcidIdx); var largestTriangleInequalityIdx = -1; var largestTriangleInequalityDiff = double.NegativeInfinity; for (int aminoAcidIdx = 1; aminoAcidIdx < aminoAcidCount; aminoAcidIdx++) { if (referenceIndices.Contains(aminoAcidIdx)) { continue; } var distanceToRef0 = aminoAcidDistancesToRef0[aminoAcidIdx]; var distanceToRef1 = aminoAcidDistancesToRef1[aminoAcidIdx]; var triangleInequalityDiff = distanceToRef0 + distanceToRef1 - distanceRef0Ref1; if (triangleInequalityDiff > largestTriangleInequalityDiff) { largestTriangleInequalityDiff = triangleInequalityDiff; largestTriangleInequalityIdx = aminoAcidIdx; } } var distanceRef0Ref2 = aminoAcidDistancesToRef0[largestTriangleInequalityIdx]; var distanceRef1Ref2 = aminoAcidDistancesToRef1[largestTriangleInequalityIdx]; var triangleArea = CalculateTriangleArea(distanceRef0Ref1, distanceRef0Ref2, distanceRef1Ref2); var triangleHeight = 2 * triangleArea / distanceRef0Ref1; var ref2X = Math.Sqrt(distanceRef0Ref2.Square() - triangleHeight.Square()); var ref2Y = triangleHeight; aminoAcidPositions[largestTriangleInequalityIdx] = new Point3D(ref2X, ref2Y, 0); var actualDistanceToRef0 = aminoAcidPositions[largestTriangleInequalityIdx].DistanceTo(aminoAcidPositions[referenceIndices[0]]); if ((actualDistanceToRef0 - distanceRef0Ref2).Abs() > 10) { throw new Exception(); } referenceIndices.Add(largestTriangleInequalityIdx); // Reference 4: var aminoAcidDistancesToRef2 = AminoAcidDistancesToIndex(distanceMap, largestTriangleInequalityIdx); largestTriangleInequalityIdx = -1; largestTriangleInequalityDiff = double.NegativeInfinity; for (int aminoAcidIdx = 1; aminoAcidIdx < aminoAcidCount; aminoAcidIdx++) { if (referenceIndices.Contains(aminoAcidIdx)) { continue; } var distanceToRef0 = aminoAcidDistancesToRef0[aminoAcidIdx]; var distanceToRef1 = aminoAcidDistancesToRef1[aminoAcidIdx]; var distanceToRef2 = aminoAcidDistancesToRef2[aminoAcidIdx]; var triangleInequalityDiff01 = distanceToRef0 + distanceToRef1 - distanceRef0Ref1; var triangleInequalityDiff02 = distanceToRef0 + distanceToRef2 - distanceRef0Ref2; var triangleInequalityDiff12 = distanceToRef1 + distanceToRef2 - distanceRef1Ref2; var minTriangleInequalityDiff = new[] { triangleInequalityDiff01, triangleInequalityDiff02, triangleInequalityDiff12 }.Min(); if (minTriangleInequalityDiff > largestTriangleInequalityDiff) { largestTriangleInequalityDiff = minTriangleInequalityDiff; largestTriangleInequalityIdx = aminoAcidIdx; } } // Find position from optimization var limit = mostDistantAminoAcid.Distance; var parameterSetting = new[] { new ParameterSetting("X", -limit, limit, 1, limit / 2), new ParameterSetting("Y", -limit, limit, 1, limit / 2), new ParameterSetting("Y", -limit, limit, 1, limit / 2) }; var targetDistances = referenceIndices.ToDictionary( idx => idx, idx => IntensityToDistance(distanceMap[largestTriangleInequalityIdx, idx].Intensity)); double CostFunc(double[] parameters) { double deviationSum = 0; var point = new Point3D(parameters[0], parameters[1], parameters[2]); foreach (var referenceIndex in referenceIndices) { var referencePoint = aminoAcidPositions[referenceIndex]; var distanceToReference = point.DistanceTo(referencePoint); var targetDistance = targetDistances[referenceIndex]; deviationSum += (distanceToReference - targetDistance).Abs(); } return(deviationSum); } var optimizationResult = ParameterCyclingOptimizer.Optimize(CostFunc, parameterSetting); if (optimizationResult.Cost > 10) { throw new Exception("Reference 4 solution not accurate enough"); } aminoAcidPositions[largestTriangleInequalityIdx] = new Point3D( optimizationResult.Parameters[0], optimizationResult.Parameters[1], optimizationResult.Parameters[2]); referenceIndices.Add(largestTriangleInequalityIdx); var skippedIndices = new List <int>(); var referencePoints = referenceIndices .Select(referenceIndex => aminoAcidPositions[referenceIndex]) .ToList(); foreach (var aminoAcidIdx in Enumerable.Range(0, aminoAcidCount).Except(referenceIndices)) { var distancesToRefs = referenceIndices .Select(referenceIndex => IntensityToDistance(distanceMap[referenceIndex, aminoAcidIdx].Intensity)) .ToList(); if (distancesToRefs.Any(distance => distance >= CutoffDistance)) { skippedIndices.Add(aminoAcidIdx); continue; } aminoAcidPositions[aminoAcidIdx] = DeterminePositionFromReference(distancesToRefs, referencePoints); } var iterations = 0; while (skippedIndices.Count > 0 && iterations < 10) { iterations++; referencePoints.Clear(); var referencePointCandidateIndices = aminoAcidPositions .Select((position, idx) => new { Index = idx, IsKnown = position != null }) .Where(x => x.IsKnown) .Select(x => x.Index) .ToList(); for (int idx = 0; idx < 4; idx++) { var candidateIdx = StaticRandom.Rng.Next(referencePointCandidateIndices.Count); referencePoints.Add(aminoAcidPositions[candidateIdx]); referencePointCandidateIndices.RemoveAt(candidateIdx); } var skippedIndicesCopy = skippedIndices.ToList(); skippedIndices.Clear(); foreach (var aminoAcidIdx in skippedIndicesCopy) { var distancesToRefs = referenceIndices .Select(referenceIndex => IntensityToDistance(distanceMap[referenceIndex, aminoAcidIdx].Intensity)) .ToList(); if (distancesToRefs.Any(distance => distance >= CutoffDistance)) { skippedIndices.Add(aminoAcidIdx); continue; } aminoAcidPositions[aminoAcidIdx] = DeterminePositionFromReference(distancesToRefs, referencePoints); } } return(aminoAcidPositions); }