for(i in 1:nsim)
{
for(fi in 1:length(FUNCTIONS))
for(p1 in 1:length(param1))
{
for(p2 in 1:length(param2))
{
# ... [mathematically and so on]
for(pN in length(paramN))
{
# do something here
# with (i, fi, p1, p2, ... pN)
下面是stackoverflow的定义。对我来说,它代表了可以使用函数(通常是过程性的)解决的问题的适当抽象量。
因此,我正在根据我一直遇到的一些字符串操作问题,使用
microbenchmark
审查我的一些代码和选项。走下“兔子洞”,我回顾了microbenchmark
纳米计时并决定看看他们是否同意标准协议。 microbenchmark
计算相对较快,但 print
和 summary
很慢,我想要一些基准参考,所以我写了一个函数 ggg.benchmark
导致这个输出。
time.is ... [milliseconds (ms)] per call
idx expression min lower-trecile median upper-trecile max relative.efficiency relative.factor Rank
2 2 cpp_time() 0.00000035 0.00000057 0.00000065 0.00000074 0.00024615 52.90 0.47101 1
4 4 cpp_milli()/1000 0.00000040 0.00000060 0.00000069 0.00000080 0.00011427 50.00 0.50000 2
6 6 cpp_micro()/1000000 0.00000039 0.00000062 0.00000071 0.00000082 0.00011449 48.55 0.51449 3
5 5 cpp_now("milli")/1000 0.00000049 0.00000068 0.00000083 0.00000098 0.00010462 39.86 0.60145 4
7 7 cpp_now("micro")/1000000 0.00000049 0.00000068 0.00000084 0.00000100 0.00145392 39.13 0.60870 5
9 9 cpp_now("nano")/1000000000 0.00000050 0.00000069 0.00000084 0.00000100 0.00011454 39.13 0.60870 6
1 1 as.numeric(Sys.time()) 0.00000102 0.00000129 0.00000138 0.00000149 0.00000814 0.00 1.00000 7
8 8 cpp_nano()/1000000000 0.00000123 0.00000150 0.00000157 0.00000171 0.00000986 -13.77 1.13768 8
3 3 .now() 0.00000130 0.00000160 0.00000169 0.00000186 0.00001599 -22.46 1.22464 9
11 11 time.now("cpp") 0.00000598 0.00000684 0.00000714 0.00000769 0.00141655 -417.39 5.17391 10
12 12 time.now("base") 0.00000599 0.00000686 0.00000716 0.00000770 0.00002909 -418.84 5.18841 11
10 10 time.now("first") 0.00000710 0.00000811 0.00000851 0.00000918 0.00128414 -516.67 6.16667 12
13 13 str.uniqid() 0.00017347 0.00017944 0.00018093 0.00018328 0.00289352 -13010.87 131.10870 13
我的函数运行良好,但我添加了一个缓存算法来加速它(参见
max
与 median
的偏差),并运行以下命令:
> ggg.benchmark(mb.irony)
"milliseconds (ms)"
"mil"
"057b92b71ccfa406fc5d509f8b459d0e"
time.is ... [milliseconds (ms)] per call
idx expression min lower-trecile median upper-trecile max relative.efficiency relative.factor Rank
5 5 ggg.benchmark(mb.res) 53.57657 54.12626 54.17876 54.88361 218.67247 99.00 0.00998 1
4 4 summary(mb.res, "eps") 4475.81297 4488.51471 4489.81239 4523.80740 4533.85203 17.32 0.82683 2
1 1 summary(mb.res, "ns") 5413.74017 5424.41295 5430.13278 5456.10914 5600.27456 0.00 1.00000 3
2 2 summary(mb.res, "us") 5416.56048 5446.56292 5448.34089 5459.35504 5474.32398 -0.34 1.00335 4
3 3 summary(mb.res, "ms") 5418.25978 5449.20442 5462.20611 5493.99542 5578.11555 -0.59 1.00591 5
variable
数量的表达式或函数variable
数量的参数,每个参数都有variable
选项被考虑seeds
随机性Rprof
和/或Rprofmem
referent
)或流行结果(common
)进行比较检查,以同时测试准确性当我回顾我对基准模拟的需求时,我想出了以下函数参数:
bm = function(..., list=NULL,
setup = list("nsim" = 100, "compare.values" = TRUE, "identical.to" = "referent", "tol" = 0, "Rprof" = FALSE, "Rprofmem" = FALSE),
params = list(
"str" = c("<i>hello friend</i>", " hello there world ", " ¡hola!, ¿que tal? "),
"sep" = c(" ", "", "¿", "</i>")
)
)
{
在上面的场景中,这是设计的基础。我有两个参数:字符串
str
和分隔符sep
。我可以将参数 CHOICES 或 OPTIONS 的集合传递给这些参数。在给定的嵌套 for 循环中,我将使用一个 str
CHOICE 和一个 sep
CHOICE 来执行调用。这意味着对于作为 trial
的单个 nsim
,我有 (1+FUNCTIONS * length(param1) * length(param2)
) 次要执行。对于 nsim=1000
和 12 个函数,param1 有 3 个选择,param2 有 4 个选择,我有以下内容:
Combinations to be performed: 1000×13×3×4 = 156,000
也许我可以使用
while
循环。我可以将所有独特的组合捕获为一个字符串,以便稍后执行单次运行 ...
12-2-3 ... FUNCTION[12] ... PARAM1[2] ... PARAM2[3] ...
对于给定的
nsim
...我将以随机顺序遍历所有功能,以随机顺序遍历所有每个PARAM ...
也许如果我不是这么线性/程序地思考,会有另一种方式(递归)。欢迎提出其他策略的建议,因为我想让它发挥作用。
然而,归根结底,这是我长期以来一直挥之不去的编程问题。我用固定循环对许多 for 循环进行了硬编码,但想不出如何使其可变。欢迎任何
C-based
解决方案:C++, C, javascript, R
variadic
循环?for(i in 1:nsim)
{
for(fi in 1:length(FUNCTIONS))
for(p1 in 1:length(param1))
{
for(p2 in 1:length(param2))
{
# ... [mathematically and so on]
for(pN in length(paramN))
{
# do something here
# with (i, fi, p1, p2, ... pN)
这里有一些 Java 代码可以满足您的需求:
package p;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.function.Consumer;
// file:///D:/ray/dev/XPokerEval/XPokerEval.Pokersource/java/javadoc/org/pokersource/enum/NestedLoopEnumeration.html
public class NestedLoops implements Enumeration {
NestedLoops(Integer[] indices,Integer[] limits) {
this(indices,limits,null,null);
}
NestedLoops(Integer[] indices,Integer[] limits,Integer[] deltas) {
this(indices,limits,deltas,null);
}
NestedLoops(Integer[] indices,Integer[] limits,Integer[] deltas,Integer[] initialValues) {
this.indices=indices;
this.limits=limits;
if(deltas!=null) this.deltas=deltas;
else {
int n=indices.length;
this.deltas=new Integer[n];
for(int i=0;i<n;i++)
this.deltas[i]=1;
}
if(initialValues!=null) this.initialValues=initialValues;
else {
int n=indices.length;
this.initialValues=new Integer[n];
for(int i=0;i<n;i++)
this.initialValues[i]=0;
}
}
void initialize() {
iterations=0;
count=0;
int n=indices.length;
for(int i=0;i<n;i++)
indices[i]=initialValues[i];
}
boolean check() {
for(int i=0;i<indices.length;i++)
if(indices[i]>=limits[i]) return false;
return true;
}
Integer[] getNextState() {
if(deltas==null) { // looks like we can remove this
for(int i=indices.length-1;i>=0;indices[i--]=0)
if(indices[i]+1<limits[i]) {
indices[i]++;
return indices;
}
} else {
for(int i=indices.length-1;i>=0;indices[i--]=0)
if(indices[i]+deltas[i]<limits[i]) {
indices[i]+=deltas[i];
return indices;
}
}
return null;
}
@Override public boolean hasMoreElements() {
return hasMoreElements;
}
@Override public Object nextElement() {
if(hasMoreElements) { // this is why the enumeration copies the indices
Object rc=indices;
indices=getNextState();
hasMoreElements=check();
return rc;
} else return null;
}
void loop(Consumer<Integer[]> consumer,int max) { // maybe should be run()?
if(deltas!=null) for(int i=0;i<deltas.length;i++)
if(deltas[i]<=0) {
// System.out.println("delta["+i+"]="+deltas[i]+" is <=0!");
throw new RuntimeException("delta["+i+"]="+deltas[i]+" is <=0!");
}
hasMoreElements=check();
if(hasMoreElements) while(indices!=null) {
if(iterations++>max) {
System.out.println("iterations > "+max+" bailing2!");
return;
}
// System.out.print("instance indices: "+Arrays.asList(indices));
// System.out.print(", limits: "+Arrays.asList(limits));
// System.out.print(", deltas: "+Arrays.asList(deltas));
// System.out.println(", initial values:
// "+Arrays.asList(initialValues));
if(consumer!=null) consumer.accept(indices);
indices=getNextState();
}
hasMoreElements=false;
}
int iterations;
int count; // for user to count whatever he wants
Integer[] indices;
boolean hasMoreElements;
final Integer[] limits;
final Integer[] deltas;
final Integer[] initialValues;
static int xx=0; // yuck! - get rid of this!
}
// 这是一个测试用例:
package p;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.function.Consumer;
import org.junit.Test;
public class NestedLoopsInstanceTestCase {
final int[] ns=new int[1];
Consumer<Integer[]> counter=x -> {
//System.out.println(Arrays.asList(x)+" "+ns[0]);
if(x!=null) ns[0]++;
};
@Test public void testGetNextState() {}
@Test public void testIndices11WithAllOnes() {
Integer[] limits= {1,1};
Integer[] deltas= {1,1};
Integer[] indices= {0,0};
JNL nestedLoops=new JNL(indices,limits,deltas);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(1,ns[0]);
}
@Test public void testIndices12WithAllOnes() {
Integer[] limits=new Integer[] {1,2};
Integer[] deltas= {1,1};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits,deltas);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(2,ns[0]);
}
@Test public void testIndices21WithAllOnes() {
Integer[] limits=new Integer[] {2,1};
Integer[] deltas= {1,1};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits,deltas);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(2,ns[0]);
}
@Test public void testIndices23WithAllOnes() {
Integer[] limits=new Integer[] {2,3};
Integer[] deltas= {1,1};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits,deltas);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(6,ns[0]);
}
@Test public void testLoop11() {
Integer[] limits= {1,1};
Integer[] indices= {0,0};
JNL nestedLoops=new JNL(indices,limits);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(1,ns[0]);
}
@Test public void testLoop12() {
Integer[] limits=new Integer[] {1,2};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(2,ns[0]);
}
@Test public void testLoop21() {
Integer[] limits=new Integer[] {2,1};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(2,ns[0]);
}
@Test public void testLoop23() {
Integer[] limits=new Integer[] {2,3};
Integer[] indices=new Integer[] {0,0};
JNL nestedLoops=new JNL(indices,limits);
nestedLoops.initialize();
nestedLoops.loop(counter,Integer.MAX_VALUE);
assertEquals(6,ns[0]);
}
}