STK组件:探索函数(Exploring Functions)

翻译:原文地址:http://help.agi.com/AGIComponents/html/ExploringFunctions.htm

在许多情况下,确定给定函数何时跨过阈值非常有用。当感兴趣的阈值为0.0时,这被称为求函数的根,任何阈值交叉问题都可以通过从方程的两边减去阈值来重新定义为求根问题。如果函数的数学公式可用,通常可以直接求解根。然而,如果不是这样的话,就必须用数字求根;换句话说,我们在独立变量的离散值处对函数进行采样,并检查采样值的趋势,以便将根的位置缩小到所需的精度水平。

函数探索器

DoubleFunctionExplorerDurationFunctionExplorerJulianDateFunctionExplorer类分别用于对doubleDurationJulianDate函数进行数值探索。除了找到阈值交叉点之外,这些函数探索器还报告了局部极小值和极大值,它们是函数具有零导数的位置,或者非正式地说,是函数改变方向的位置。JulianDateFunctionExplorer在STK组件内部用于计算过境。

ExploringFunctionsFunctionExplorer.png

函数探索器的一些主要功能包括:

  • 同时探索多个函数。
  • 确定函数的局部极值。
  • 确定阈值的交叉点。每个函数可以指定多个阈值。
  • 函数的数学公式不是必需的。
  • 函数的导数不需要可用。
  • 完全控制函数的采样方式。
  • 通过探索极值,即使没有样本落在阈值的另一侧,也可以找到阈值交叉点。
  • 即使对于具有平点和不连续性的函数,只要该函数可以在探索区间内进行求值,也可以预测其行为。
    以下是使用DoubleFunctionExplorer查找函数跨越特定阈值的值的基本示例:
var explorer = new DoubleFunctionExplorer
{
    FindAllCrossingsPrecisely = true
};
explorer.Functions.Add(x => 2 * x + 5, 10.0);
explorer.SampleSuggestionCallback = (start, stop, lastSample) => lastSample + 1.0;

var thresholdCrossings = new List<double>();
explorer.ThresholdCrossingFound += (sender, e) => thresholdCrossings.Add(e.Finding.CrossingVariable);

explorer.Explore(0.0, 10.0);

// thresholdCrossings列表包含函数跨越阈值时的X值。

首先,我们创建一个函数探索器,并通过设置FindAllCrossingsPrecision属性指示它应该精确地查找所有阈值交叉点。这将在下一节中进行更详细的讨论。接下来,我们添加我们感兴趣的函数,f(x)=2*x+5,并指出我们感兴趣的阈值为10.0。在这里,函数是用lambda表达式表示的,但是可以使用任何接受double并返回double的函数。该函数作为委托提供。

函数探索器通过对函数值进行离散采样来探索函数。因此,我们提供了一个SampleSuggestionCallback,用于确定函数采样的变量值。回调给出了正在探索的间隔的开始和结束以及上一个变量值,并期望返回下一个要采样的变量值。同样,我们使用lambda表达式指定回调函数,但是可以使用任何兼容的函数。我们将在后面的章节中更深入地讨论采样。

接下来,我们订阅每次发现阈值交叉时由函数探索器引发的事件。事件处理程序(我们表示为匿名委托)只是将阈值交叉的变量值添加到列表中。

最后,我们调用Explore方法来探索给定间隔内的函数。每当函数探索器发现一些有趣的东西时,它都会引发适当的事件,并调用附加的事件处理程序(如果有的话)。在本例中,在Explore方法返回后,thresholdCrossings集合包含单个变量值2.5。

发现和事件

所有三个函数探索器都会根据以下发现引发事件:

  • FunctionSampled:每次对函数进行采样时引发。
  • ThresholdCrossingIndicated:两个连续的样本位于阈值的两侧,表示函数在两个点之间的间隔内穿过阈值。引发此事件时,尚未确定交叉口的准确位置。
  • ThresholdCrossingFound:已经找到了阈值交叉口的精确位置。只有在ThresholdCrossingIndicated事件期间调用FindReciseCrossing方法,或者FindAllCrossingsPrecilitytrue时,才会精确地找到阈值交叉点。
  • LocalExtremumIndicated:三个连续的样本形成两个斜率相反的线段,表明函数在三个点的第一个点和最后一个点之间具有局部极值(最小值或最大值)。当这个事件发生时,还没有确定局部极值的精确位置。
  • LocalExtremumFound:已找到极值(最小值或最大值)的精确位置。 只有在LocalExtremumIndicated事件期间调用FindPreciseExtremum方法或者FindAllExtremaPreciselytrue时,才能找到极值。 如果ExploreExtremaToFindCrossingstrue,并且极值(如果找到)可能位于阈值的另一侧,则会发现极值,从而导致发现其他阈值交叉点。

采样

使用函数探索器时,必须提供一个回调来控制函数的采样方式。良好的采样对于获得准确的结果至关重要。如果函数采样频率不够高,可能会错过阈值交叉点和局部极值。如果采样太频繁,性能就会受到影响。理想采样在很大程度上取决于被采样函数的性质。

我们建议您使用DoubleFunctionSamplingJulianDateFunctionSamplingDurationFunctionSampling,而不是使用上面示例中所示的固定采样步长。函数探索器可配置为使用这些采样类,如下所示。

Function<double, double> function = GetAnyOldFunction();

DoubleFunctionSampling sampling = new DoubleFunctionSampling
{
    MinimumStep = 1.0,
    MaximumStep = 100.0,
    DefaultStep = 10.0,
    TrendingStep = 1.0
};

DoubleFunctionExplorer explorer = new DoubleFunctionExplorer();
explorer.SampleSuggestionCallback = sampling.GetFunctionSampler(function).GetNextSample;
explorer.Functions.Add(function.Evaluate, 1.234);

采样类型确定传递给GetFunctionSamplerFunction <TIndependent,TDependent>实例上的GetNextSampleSuggestion方法的下一个样本。 因此,函数本身控制着它的采样方式。 此外,采样类型具有MinimumStepMaximumStep属性,这些属性对函数可以建议的步长施加限制。 如果函数未提供有效建议,或者未向GetFunctionSampler提供任何函数,则使用DefaultStep

采样类型还允许您指定TrendingStep的大小。趋势步长发生在探索间隔的开始和结束时,其目的是确定函数在端点处的趋势方向。

ExploringFunctionsTrendingStep.png

考虑探索上图中显示的函数。探测从最左边的黄点开始,右边的两个黄点是接下来的两个样本。连接三个点的两条线的斜率以红色显示。因为两个线段都显示出减小的斜率,所以函数探索器不知道该函数在这三个样本之间的间隔内具有局部最大值。更糟糕的是,局部最大值超过阈值,因此如果我们不认识到存在这个局部最大值,我们将错过两个阈值交叉。

这是一个问题,因为最左边的黄点是第一个探索过的样本。如果我们之前已经开始探索(例如图中的绿点),则由前三个点形成的斜率将相反,函数探索器将识别该斜率表示局部最大值。找到局部最大值也会导致找到两个交叉点。但是,在我们从第一个黄点开始的情况下,我们可以做些什么来找到交叉点?

您可能已经猜到,答案是使用趋势步长。在间隔开始处的一小步,显示为蓝点,确定该函数在间隔开始时呈趋势正向。然后,第二个黄点给出了两个具有相反斜率的区段,表示局部最大值,我们找到了交叉点。

趋势步长越小,函数可以在阈值的“另一”侧花费的时间越短,而不会错过两个交叉。另一方面,如果趋势步长太小,则在探索间隔开始时和趋势步长中的函数值将是不可区分的。虽然函数探索器会考虑这种配置,其中前两个样本相等而第三个不同,以指示局部极值,在函数确实在间隔内持续增加或减少的情况下,我们将浪费时间搜索最终位于一个端点或另一个端点的极值。

局部极值

在对函数进行采样时,当三个采样函数值形成具有相反斜率的两个线段时,表示有局部极值(最小值或最大值)。此外,如果前两个值或后两个值相等,则表示为极值,但如果所有三个值相等则不表示为极值。当表示有极值时,将引发LocalExtremumIndicated事件,并保证局部极值存在于三个样本中的第一个和最后一个之间。但是,如果采样不充分,则第一个和最后一个样本之间可能存在多个极值。

如果FindAllExtremaPreciselytrue,则立即找到指示的极值的确切位置。如果ExploreExtremaToFindCrossingstrue并且极值是最大值且所有三个样本都低于阈值,或者最小值并且所有三个样本都高于阈值,则还会找到极值的精确位置。最后,如果用户在LocalExtremumIndicated事件期间显式调用FindPreciseExtremum方法,则会精确找到极值。当找到极值的精确位置时,函数探索器会引发LocalExtremumFound

使用BrentFindExtremum可以找到极值的精确位置。 ExtremumConvergenceCriteria属性控制用于确定何时发现极值达到足够精度的标准。当设置为ConvergenceCriteria.Variable时,当极值被小于ExtremumVariableTolerance的范围时,极值搜索会收敛。当设置为ConvergenceCriteria.Function时,当最后一个采样函数值在通过将曲线拟合到指示极值的三个点而估计的值的ExtremumValueTolerance范围内时,极值搜索收敛。 ConvergenceCriteria也可以允许融合。任何一个标准或者可以要求满足ConvergenceCriteria.Both标准。

如果采样不充分导致三个样本之间存在多个局部极值标明为一个极值,则函数探索器将只发现一个极值,并且它们不能保证找到哪一个极值。

ReportExtremaAtEndpoints设置为true时,还会在探测间隔的开始和结束时报告局部极值。例如,如果函数在间隔开始时减小,则第一个样本是局部最大值。类似地,如果函数在间隔结束时减少,则最后一个样本是局部最小值。如果函数在端点处是平坦的,则不会报告极值。

阈值交叉

在对函数进行采样时,当两个采样函数值位于阈值的相对侧时,表示有阈值交叉。当采样函数值恰好位于阈值上时,基于BehaviorWhenOnThreshold属性的值确定阈值交叉时,将其视为高于还是低于阈值。

当出现极值时,将引发ThresholdCrossingIndicated事件,并保证交叉存在于两点之间的某处。但是,如果采样不充分,则两个样本之间可能存在多个交叉点。

如果FindAllCrossingsPreciselytrue,则立即找到标明交叉点的确切位置。如果用户在ThresholdCrossingIndicated事件期间显式调用FindPreciseCrossing方法,也会找到交叉点的精确位置。当找到交叉点的精确位置时,函数探索器会引发ThresholdCrossingFound事件。

使用BrentFindRoot找到交叉点的精确位置。 ConvergenceCriteria属性控制用于确定何时发现交叉点达到足够精度的标准。当设置为ConvergenceCriteria.Variable时,当交叉点被小于CrossingVariableTolerance的间隔范围内时,交叉搜索会收敛。当设置为ConvergenceCriteria.Function时,当最后一个采样函数值在阈值的ValueTolerance范围内时,交叉搜索会收敛。 ConvergenceCriteria也可以允许融合。任何一个标准或者都可以要求满足ConvergenceCriteria.Both标准。当识别的交叉点不完全等于阈值时,SolutionType属性控制报告的交叉点是略高于还是略低于阈值。

当函数在阈值处是平坦的时,将平坦区域中的任意数量的样本报告为阈值交叉是合理的。相反,函数探索器根据SolutionType属性的值保证报告交叉的位置。当设置为ThresholdCrossingSolutionType.OnOrAboveThreshold,并且函数在增加时越过阈值时,报告的交叉是阈值上最早的采样变量值。如果函数在减小时越过阈值,则报告的交叉是阈值上的最新采样变量值。这与ThresholdCrossingSolutionType.OnOrAboveThreshold暗示应将阈值上的值视为高于阈值的观点一致;函数探索器首次报告它超过阈值并且最后一次超过阈值。类似地,当设置为ThresholdCrossingSolutionType.OnOrBelowThreshold,并且函数在增加时越过阈值时,报告的交叉是阈值上的最新采样变量值。如果函数在减小时越过阈值,则报告的交叉是阈值上最早的采样变量值。最后,当设置为ThresholdCrossingSolutionType.OnAboveOrBelowThreshold时,函数探索器会报告最早的交叉,无论方向如何。

如果采样不充分导致两个样本之间出现多个交叉点表示为一个交叉点,则函数探索器只能找到其中一个交叉点,并且无法保证找到哪个交叉点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容