如何使用 `for` 循环的可变嵌套创建函数?

问题描述 投票:0回答:1

要求

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


Benchmarking的特点

  • FUNCTIONS:允许计算
    variable
    数量的表达式或函数
  • 带有选项的参数:允许
    variable
    数量的参数,每个参数都有
    variable
    选项被考虑
  • 在上面包含一个 NULL 函数以捕获系统性能规范
  • 对于给定的试验(nsim),随机化:功能顺序,参数顺序
  • 为了获得良好的数据来源,记录
    seeds
    随机性
  • 允许
    Rprof
    和/或
    Rprofmem
  • 允许与第一个FUNCTION(
    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)

r simulation benchmarking variadic-functions variadic
1个回答
0
投票

这里有一些 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]);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.