我正在用Java编写一个辅助学习算法。
我遇到了一个数学问题,我可能可以解决,但由于处理量很大,我需要一个最优解。
尽管如此,如果有人知道一个优化的库,那将是非常棒的,但语言是Java,所以这需要考虑在内。
这个想法相当简单:
对象将存储变量的组合,如ABDC、ACDE、DE、AE。
组合的最大数量将基于我在不减慢程序速度的情况下能运行多少个组合,理论上假设是100个。
决策过程将在每次迭代中生成一个随机变量。如果生成的变量是某个组合的一部分,例如’A’是ABDC和ACDE的一部分,那么C和B(或存储组合中的任何后续字母)的倾向性将增加。
为了更清楚地说明,让我们假设’A’、’B’、’C’、’D’和’E’是唯一可能的变量。实际上,可能会有12或14个,但最大数量也取决于我在不产生延迟的情况下能处理多少个变量。
由于有五个可能的变量,它将在第一次迭代中生成加权的1/5随机选择。如果这次选择结果是’A’,那么在下一次迭代中,’B’和’C’的倾向性将变为2/5,而不是1/5。
如果下一次迭代生成’B’,那么’D’的倾向性将增加到3/5。注意:这种关系是指数增长的;实际上,它不会是1/5,而是一个小幅提升,如10%,如果它达到序列中的第四个变量,可能会增长到50%。
现在,在Java中,我可以通过跟踪每个对象的所有存储组合来实现这一功能。我在想,通过在每次迭代中将跟踪过程分成小步骤进行,应该不会太慢。
另一种解决方案是映射所有可能的组合及其潜在倾向性。当然,这只需要一个搜索功能,但也带来了一些问题,需要计算所有可能性并存储在某处,可能是在文件中。
有人建议我应该使用马尔可夫模型和/或库,尽管我不太熟悉这种数学知识。
如何在Java中快速计算这个过程?
.
示例 >>>
只有一个序列ABC。
对于三个数字,机会开始是平等的,所以看起来像是rand(1,3)
如果结果是A,我们增加B的可能性,因为它是序列中的下一个字母。假设我们将其翻倍。
所以现在机会是:A=1/4,C=1/4,B=2/4
函数现在看起来像是rand(1,4),其中3和4的结果都代表选项B。
如果下一个结果是B,我们希望增加C的可能性,因为它是序列中的下一个字符,但增加的幅度是上次的两倍(指数增长)
现在机会大约是:A=1/6,C=1/6,B=4/6
函数现在是rand(1/6),其中值3、4、5、6代表C。
回答:
如果你愿意,可以编写一个C/C++版本,并使用NDK(NDK的开销在于从Java到C/C++方法的JNI转换,但一旦转换完成,它们会快得多)
这是一个想法。但是…我认为你不必走那么远(至少对于较小的集合来说)(也许以后对于大型集合,移动到NDK可能是一个更好的选择)
我认为你最好将这视为一个“整数分数”数组,也就是说…对于每组动作的概率使用一个二维数组。意思是分子在“顶行”,分母在“底行”。由于你将要处理的集合很可能很小,我认为一个简单的节点链表,每个节点有自己的概率集会起作用。(这些概率是从S到S’的转换表,从“那个”节点开始。)
int[][] probs = new int[100][2];
所以你可以把它看作…
1 2 1 1
4 3 4 9
作为1/4,2/3,1/4,1/9,使用整数算术。这在算法的“某些”部分会更容易,因为你将能够为“removeColumn”(设为0/0,并跳过其余处理等(或者你想如何表示它))和’adjustProbabilities()’创建很好的辅助函数
(如果你将分母设为一个单一的整数(最低公分母),你可能可以只使用一个分子数组,但我可能会在2D数组版本工作后再进行这种优化)
然后只需编写‘简单’通用的P、R和V方法,这些方法在每个节点上与该数据交互。然后通过良好的面向对象设计使它们可调整/可扩展/等。
然后只需“玩弄数字”来调整折扣因子等。
我认为这更多的是“花时间测试它”而不是关于任何真正复杂的数学算法等的问题,因为从我所见,没有“明显”的地方可以优化核心算法。