【问题标题】:Iterating over values from fixed sum, in MatLab在 MatLab 中从固定总和中迭代值
【发布时间】:2012-03-19 22:04:19
【问题描述】:

假设我有 n 个弹珠,每个弹珠可以是 8 种可能的颜色之一。我想遍历弹珠颜色组合的所有可能值。如何在 MatLab 中做到这一点?

例如,如果n = 2,那么我想遍历:

2 0 0 0 0 0 0 0

1 1 0 0 0 0 0 0

1 0 1 0 0 0 0 0

1 0 0 1 0 0 0 0

1 0 0 0 1 0 0 0

1 0 0 0 0 1 0 0

1 0 0 0 0 0 1 0

1 0 0 0 0 0 0 1

0 2 0 0 0 0 0 0

0 1 1 0 0 0 0 0

0 1 0 1 0 0 0 0

等等

编辑:

这是一些伪代码的样子,但正如您所见,它非常草率。我对一种更简洁的方法感兴趣,并且不需要那个 if 语句......

for i8 = 0:1:n
    for i7 = 0:1:n - i8
        for i6 = 0:1:n - i8 - i7
            for i5 = 0:1:n - i8 - i7 - i6
                for i4 = 0:1:n - i8 - i7 - i6 - i5
                    for i3 = 0:1:n - i8 - i7 - i6 - i5 - i4
                        for i2 = 0:1:n - i8 - i7 - i6 - i5 - i4 - i3
                            for i1 = 0:1:n - i8 - i7 - i6 - i5 - i4 - i3 - i2
                                if i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 == n
                                    i = [i1, i2, i3, i4, i5, i6, i7, i8]
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end

【问题讨论】:

    标签: matlab combinatorics loops


    【解决方案1】:

    这里是解决方案(代码在 GNU/Octave 中测试过,它也应该在 Matlab 中工作)。 此代码来源于Octave-Forge multinom_exp.m

    function conf = marbin (nmar,nbin)
    %% Returns the position of nmar in nbis, allowing the marbles to be in the same bin.
    
    %% This is standard stars and bars.
     numsymbols = nbin+nmar-1;
     stars = nchoosek (1:numsymbols, nmar);
    
    %% Star labels minus their consecutive position becomes their index
    %% position!
     idx = bsxfun (@minus, stars, [0:nmar-1]);
    
    %% Manipulate indices into the proper shape for accumarray.
     nr = size (idx, 1);
     a = repmat ([1:nr], nmar, 1);
     b = idx';
     conf = [a(:), b(:)];
     conf = accumarray (conf, 1);
    

    【讨论】:

    • 你好牙买加虫,这段代码适用于任意数量的颜色和弹珠。它也是矢量化的,你不会有内存问题。输出的格式完全符合您的需要。什么问题,为什么不测试?
    • 它使用 stars and bars 方法的属性来计算弹珠的位置(每个 bin 都有与之关联的颜色状态)。就是这样,剩下的就是产生你想要的输出格式。如果您查看 GNU/Octave 中的 multinom_exp 函数,您会发现 JordiGH 是提出这个想法的人。我在网上找不到太多解释,但您可以获取 Feller 的书以了解更多信息。
    【解决方案2】:

    我认为这更容易是您考虑弹珠的状态,而不是颜色的状态。然后根据需要从大理石状态转换为颜色状态。例如,如果考虑所有可能的弹珠状态的有序列表,您可以创建如下所示的函数(使用全零作为“全部完成”标志):

    function state = nextmarblestate(state, nMarbles, nColors)
    %Increment the marble state by 1
    
    %Add one to the last marble
    state(end) = state(end)+1;
    
    %Propogate change towards the first marble as colors overflow
    for ixCurrent = nMarbles:-1:2
        if state(ixCurrent) > nColors;
            state(ixCurrent) = 1;
            state(ixCurrent-1) = state(ixCurrent-1)+1;
        else
            return;
        end
    end
    
    %Check to see if we are done (reset to 0)
    if state(1) > nColors
        state = zeros(1,nMarbles);
    end
    

    然后您可以编写一个快速循环来遍历所有弹珠状态,如下所示:

    nMarbles = 2;
    nColors = 8;
    
    marblestate = ones(1,nMarbles);
    while sum(marblestate)>0
        disp(['Marblestate = [' num2str(marblestate) ']'])
        marblestate = nextmarblestate(marblestate, nMarbles, nColors);
    end
    

    或者,为了得到你想要的结果,写一个从大理石状态到颜色状态的转换,像这样(对不起这里的简洁,这可以扩展为更漂亮的版本):

    marbleState2colorState = @(marblestate) arrayfun(@(color)sum(marblestate==color), 1:nColors);
    

    然后使用那个转换函数,像这样展开上面的while循环:

    marblestate = ones(1,nMarbles);
    while sum(marblestate)>0
        disp(['Marblestate = [' num2str(marblestate) '],  Colorstate = [' num2str(marbleState2colorState(marblestate)) ']'])
        marblestate = nextmarblestate(marblestate, nMarbles, nColors);
    end
    

    产生以下输出:

    Marblestate = [1  1],  Colorstate = [2  0  0  0  0  0  0  0]
    Marblestate = [1  2],  Colorstate = [1  1  0  0  0  0  0  0]
    Marblestate = [1  3],  Colorstate = [1  0  1  0  0  0  0  0]
    Marblestate = [1  4],  Colorstate = [1  0  0  1  0  0  0  0]
    Marblestate = [1  5],  Colorstate = [1  0  0  0  1  0  0  0]
    Marblestate = [1  6],  Colorstate = [1  0  0  0  0  1  0  0]
    Marblestate = [1  7],  Colorstate = [1  0  0  0  0  0  1  0]
    Marblestate = [1  8],  Colorstate = [1  0  0  0  0  0  0  1]
    Marblestate = [2  1],  Colorstate = [1  1  0  0  0  0  0  0]
    Marblestate = [2  2],  Colorstate = [0  2  0  0  0  0  0  0]
    Marblestate = [2  3],  Colorstate = [0  1  1  0  0  0  0  0]
    Marblestate = [2  4],  Colorstate = [0  1  0  1  0  0  0  0]
    Marblestate = [2  5],  Colorstate = [0  1  0  0  1  0  0  0]
    Marblestate = [2  6],  Colorstate = [0  1  0  0  0  1  0  0]
    Marblestate = [2  7],  Colorstate = [0  1  0  0  0  0  1  0]
    Marblestate = [2  8],  Colorstate = [0  1  0  0  0  0  0  1]
    Marblestate = [3  1],  Colorstate = [1  0  1  0  0  0  0  0]
    Marblestate = [3  2],  Colorstate = [0  1  1  0  0  0  0  0]
    Marblestate = [3  3],  Colorstate = [0  0  2  0  0  0  0  0]
    Marblestate = [3  4],  Colorstate = [0  0  1  1  0  0  0  0]
    Marblestate = [3  5],  Colorstate = [0  0  1  0  1  0  0  0]
    Marblestate = [3  6],  Colorstate = [0  0  1  0  0  1  0  0]
    Marblestate = [3  7],  Colorstate = [0  0  1  0  0  0  1  0]
    Marblestate = [3  8],  Colorstate = [0  0  1  0  0  0  0  1]
    Marblestate = [4  1],  Colorstate = [1  0  0  1  0  0  0  0]
    Marblestate = [4  2],  Colorstate = [0  1  0  1  0  0  0  0]
    Marblestate = [4  3],  Colorstate = [0  0  1  1  0  0  0  0]
    Marblestate = [4  4],  Colorstate = [0  0  0  2  0  0  0  0]
    Marblestate = [4  5],  Colorstate = [0  0  0  1  1  0  0  0]
    Marblestate = [4  6],  Colorstate = [0  0  0  1  0  1  0  0]
    Marblestate = [4  7],  Colorstate = [0  0  0  1  0  0  1  0]
    Marblestate = [4  8],  Colorstate = [0  0  0  1  0  0  0  1]
    Marblestate = [5  1],  Colorstate = [1  0  0  0  1  0  0  0]
    Marblestate = [5  2],  Colorstate = [0  1  0  0  1  0  0  0]
    Marblestate = [5  3],  Colorstate = [0  0  1  0  1  0  0  0]
    Marblestate = [5  4],  Colorstate = [0  0  0  1  1  0  0  0]
    Marblestate = [5  5],  Colorstate = [0  0  0  0  2  0  0  0]
    Marblestate = [5  6],  Colorstate = [0  0  0  0  1  1  0  0]
    Marblestate = [5  7],  Colorstate = [0  0  0  0  1  0  1  0]
    Marblestate = [5  8],  Colorstate = [0  0  0  0  1  0  0  1]
    Marblestate = [6  1],  Colorstate = [1  0  0  0  0  1  0  0]
    Marblestate = [6  2],  Colorstate = [0  1  0  0  0  1  0  0]
    Marblestate = [6  3],  Colorstate = [0  0  1  0  0  1  0  0]
    Marblestate = [6  4],  Colorstate = [0  0  0  1  0  1  0  0]
    Marblestate = [6  5],  Colorstate = [0  0  0  0  1  1  0  0]
    Marblestate = [6  6],  Colorstate = [0  0  0  0  0  2  0  0]
    Marblestate = [6  7],  Colorstate = [0  0  0  0  0  1  1  0]
    Marblestate = [6  8],  Colorstate = [0  0  0  0  0  1  0  1]
    Marblestate = [7  1],  Colorstate = [1  0  0  0  0  0  1  0]
    Marblestate = [7  2],  Colorstate = [0  1  0  0  0  0  1  0]
    Marblestate = [7  3],  Colorstate = [0  0  1  0  0  0  1  0]
    Marblestate = [7  4],  Colorstate = [0  0  0  1  0  0  1  0]
    Marblestate = [7  5],  Colorstate = [0  0  0  0  1  0  1  0]
    Marblestate = [7  6],  Colorstate = [0  0  0  0  0  1  1  0]
    Marblestate = [7  7],  Colorstate = [0  0  0  0  0  0  2  0]
    Marblestate = [7  8],  Colorstate = [0  0  0  0  0  0  1  1]
    Marblestate = [8  1],  Colorstate = [1  0  0  0  0  0  0  1]
    Marblestate = [8  2],  Colorstate = [0  1  0  0  0  0  0  1]
    Marblestate = [8  3],  Colorstate = [0  0  1  0  0  0  0  1]
    Marblestate = [8  4],  Colorstate = [0  0  0  1  0  0  0  1]
    Marblestate = [8  5],  Colorstate = [0  0  0  0  1  0  0  1]
    Marblestate = [8  6],  Colorstate = [0  0  0  0  0  1  0  1]
    Marblestate = [8  7],  Colorstate = [0  0  0  0  0  0  1  1]
    Marblestate = [8  8],  Colorstate = [0  0  0  0  0  0  0  2]
    

    【讨论】:

      【解决方案3】:

      如果你有 2 个弹珠,每个可以是 8 种可能的颜色之一,那么这就足够了:

      >> dec2base(0:63,8)
      ans =
      00
      01
      02
      03
      04
      05
      06
      07
      10
      11
      12
      13
      14
      15
      16
      17
      20
      21
      22
      23
      24
      25
      26
      27
      30
      31
      32
      33
      34
      35
      36
      37
      40
      41
      42
      43
      44
      45
      46
      47
      50
      51
      52
      53
      54
      55
      56
      57
      60
      61
      62
      63
      64
      65
      66
      67
      70
      71
      72
      73
      74
      75
      76
      77
      

      请注意,它以与您不同的方式存储信息,但存在相同的信息。如果需要,它应该很容易转换为您的表单。

      【讨论】:

      • 对,这只是迭代了 8^n,不是吗?如何转换我的问题中的格式(即总和为 n 的 8 个向量)?
      【解决方案4】:

      我相信以下代码 sn-p 适用于 n = 2 的情况。

      这是用 Octave 编写的,因为我目前无法访问 Matlab。

      我已经针对手动生成的结果使用各种低颜色值(2、3、4、5、6 和 8)进行了测试。

      colours = 4;
      marbles = 2;
      
      for i=1:colours
         a = zeros(1,colours);
         a(i) = marbles
         for j=i:colours-1
            a(j) = a(j) -1;
            a(j+1) = a(j+1)+1  
         endfor
      endfor 
      

      我仍在为任意数量的颜色和任意数量的弹珠的一般情况编写代码 sn-p。

      【讨论】:

      • 谢谢!如果你能让它适用于任何 n,那就太好了。 (到目前为止,它不起作用,因为例如对于 n=3,它不会让像 1 1 1 0 0 0 0 0 这样的东西的可能性。)
      【解决方案5】:
      nc = 8;    % number colors
      nm = 2;    % number marbles
      
      % For now let marbles be unique. There are then nc^nm assignments of
      % marbles to colors
      nmc = nc^nm;
      
      % Enumerate the assignments of marbles to colors: i.e., sub{k} is a row
      % array giving the color of marble k for each of the nmc assignments
      [sub{1:nm,1}] = ind2sub(nc*ones(1,nm),1:nmc);
      
      % We'll use accumarray to map the marble color assignments in sub to number
      % of marbles of each color
      % Bring sub into form required for application of accumarray
      s = mat2cell(cell2mat(sub),nm,ones(nmc,1));
      
      % apply accumarray to each assignement of colors to marbles
      a = cellfun(@(c)accumarray(c,1,[nc,1]),s,'UniformOutput',false);
      
      % Each element of a is a column vector giving the number of marbles of each
      % color. We want row vectors, and we want only the unique rows
      a = unique(cell2mat(a)','rows'); 
      
      % a is as desired. 
      

      【讨论】:

      • 这很好,但是 MatLab 的内存不足 n > 9。我正在寻找类似 n = 500 的迭代,所以为了不耗尽内存,我不'不想将每个可能的组合存储在一个数组中——我只需要遍历每个可能的组合(这样我就可以为每个组合执行一个简单的操作)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-14
      • 2016-07-24
      • 1970-01-01
      相关资源
      最近更新 更多