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));
            }
        }
Exemple #3
0
        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);
        }