using System; namespace Microsoft.Msagl.Routing.Visibility { /// /// A real functionf defined on /// the integers 0, 1, . . . , n-1 is said to be unimodal if there exists an integer m such that f is strictly increasing (respectively, decreasing) on [ 0, m] and /// decreasing (respectively, increasing) on [m + 1, n-1] /// No three sequential elements have the same value /// internal class UnimodalSequence { Func sequence; /// /// the sequence values /// internal Func Sequence { get { return sequence; } set { sequence = value; } } int length; /// /// the length of the sequence: the sequence starts from 0 /// internal int Length { get { return length; } set { length = value; } } internal UnimodalSequence(Func sequenceDelegate, int length) { this.Sequence = sequenceDelegate; this.Length = length; } internal enum Behavior { Increasing, Decreasing, Extremum, } internal int FindMinimum() { //find out first that the minimum is inside of the domain int a = 0; int b = Length - 1; int m = a + (b - a) / 2; double valAtM = Sequence(m); if (valAtM >= Sequence(0) && valAtM >= Sequence(Length - 1)) return Sequence(0) < Sequence(Length - 1) ? 0 : Length - 1; while (b - a > 1) { m = a + (b - a) / 2; switch (BehaviourAtIndex(m)) { case Behavior.Decreasing: a = m; break; case Behavior.Increasing: b = m; break; case Behavior.Extremum: return m; } } if (a == b) return a; return Sequence(a) <= Sequence(b) ? a : b; } private Behavior BehaviourAtIndex(int m) { double seqAtM=Sequence(m); if (m == 0) { double seqAt1 = Sequence(1); if (seqAt1 == seqAtM) return Behavior.Extremum; return seqAt1 > seqAtM ? Behavior.Increasing : Behavior.Decreasing; } if (m == Length-1) { double seqAt1 = Sequence(Length-2); if (seqAt1 == seqAtM) return Behavior.Extremum; return seqAt1 > seqAtM ? Behavior.Decreasing : Behavior.Increasing; } double delLeft = seqAtM - Sequence(m - 1); double delRight = Sequence(m + 1) - seqAtM; if (delLeft * delRight <= 0) return Behavior.Extremum; return delLeft > 0 ? Behavior.Increasing : Behavior.Decreasing; } internal int FindMaximum() { //find out first that the maximum is inside of the domain int a = 0; int b = Length - 1; int m = a + (b - a) / 2; double valAtM = Sequence(m); if (valAtM <= Sequence(0) && valAtM <= Sequence(Length - 1)) return Sequence(0) > Sequence(Length - 1) ? 0 : Length - 1; while (b - a > 1) { m = a + (b - a) / 2; switch (BehaviourAtIndex(m)) { case Behavior.Decreasing: b = m; break; case Behavior.Increasing: a = m; break; case Behavior.Extremum: return m; } } if (a == b) return a; return Sequence(a) >= Sequence(b) ? a : b; } } }