Promela同时随机选择两个元素

时间:2019-02-26 16:06:05

标签: model promela spin

最近我开始学习Promela,我想从盒子中挑选两个球,其中我有10个黑球和4个白球,我可以将盒子建模为数组,但是我不知道如何同时选择2个球。从剩下的那些中选择一个然后再选择另一个将改变概率。你有什么想法吗?

1 个答案:

答案 0 :(得分:1)

当您只需要从idx个数字的连续间隔idy中提取对值[LOW, UPP]N = UPP - LOW + 1时,可以通过以下方法可以轻松解决保证idx != idy的问题:

  • idx中挑选[LOW, UPP]
  • idy中挑选[LOW, UPP - 1]
  • 调整idy wrt的值。 idx的值如下:

    idy = LOW + (((idx - LOW) + 1 + (idy - LOW)) % N)
    

,也就是说,您将idy解释为固定位移wrt。 idx。请注意,这种方法不会影响idy的概率分布,尤其是从概率的角度来看,它不会使idy依赖于idx


示例:

#define BLACK_BALLS 4
#define WHITE_BALLS 10
#define TOTAL_BALLS 14

bool box[TOTAL_BALLS];

inline my_select(var, upper) {
    if
        ::  0 <= upper -> var =  0;
        ::  1 <= upper -> var =  1;
        ::  2 <= upper -> var =  2;
        ::  3 <= upper -> var =  3;
        ::  4 <= upper -> var =  4;
        ::  5 <= upper -> var =  5;
        ::  6 <= upper -> var =  6;
        ::  7 <= upper -> var =  7;
        ::  8 <= upper -> var =  8;
        ::  9 <= upper -> var =  9;
        :: 10 <= upper -> var = 10;
        :: 11 <= upper -> var = 11;
        :: 12 <= upper -> var = 12;
        :: 13 <= upper -> var = 13;
    fi;
}

proctype pick_two_balls() {
    byte idx;
    byte idy;

    my_select(idx, TOTAL_BALLS - 1);
    my_select(idy, TOTAL_BALLS - 2);

    printf("Initial picks:\n")

    printf("\tpicked %d in [0, %d]\n", idx, TOTAL_BALLS - 1);
    printf("\tpicked %d in [0, %d]\n", idy, TOTAL_BALLS - 2);

    idy = ((idx + 1) + idy) % (TOTAL_BALLS);

    printf("Adjusted picks:\n");

    printf("\tball #01 at index %d\n", idx);
    printf("\tball #02 at index %d\n", idy);

    printf("Final Balls:\n");

    if
        :: box[idx]  -> printf("\tbox[%d] = black\n", idx);
        :: !box[idx] -> printf("\tbox[%d] = white\n", idx);
    fi;

    if
        :: box[idy]  -> printf("\tbox[%d] = black\n", idy);
        :: !box[idy] -> printf("\tbox[%d] = white\n", idy);
    fi;
}

init {
    byte idx = 0;
    byte todo = BLACK_BALLS;

    do  // not guaranteed to terminate!
        :: todo > 0 ->
            my_select(idx, TOTAL_BALLS - 1) ->
            if
                :: box[idx] ->
                    skip;
                :: else ->
                    box[idx] = true;
                    todo = todo - 1;
            fi;
        :: else ->
            break;
    od;

    for (idx: 0 .. TOTAL_BALLS - 1) {
        if
            :: box[idx] ->
                printf("box[%d] = black\n", idx);
            :: !box[idx] ->
                printf("box[%d] = white\n", idx);
        fi;
    }
    run pick_two_balls();
}

输出:

~$ spin p.pml 
      box[0] = white
      box[1] = black
      box[2] = white
      box[3] = white
      box[4] = white
      box[5] = white
      box[6] = white
      box[7] = white
      box[8] = white
      box[9] = white
      box[10] = white
      box[11] = black
      box[12] = black
      box[13] = black
          Initial picks:
            picked 9 in [0, 13]
            picked 7 in [0, 12]
          Adjusted picks:
            ball #01 at index 9
            ball #02 at index 3
          Final Balls:
            box[9] = white
            box[3] = white
2 processes created

注释#1::在正常情况下,我会使用select语句而不是编写自己的my_select(var, upper)函数。但是,select不能保证分配给var的值是采用均匀分布进行的,我认为这对您来说可能是个问题。


注释#2::当您需要提取多个索引时,上述数学表达式将无济于事。但是,您可以在机械意义上应用相同的原理:将used_indexes保留为bool的支持数组,如果某个索引使用了位置k,则truei。每次选择新的索引i时,都将从数组的开头开始计算空单元格,然后将i = 0减1。 j有了您要在原始数组中使用的“真实索引” used_indexes,因此您将该位置标记为 <div class="row"> <div class="col-md-8"> <!--======= grid view product =======--> <div class="my-custom-div-style"> <?php if ( woocommerce_product_loop() ) { do_action( 'woocommerce_before_shop_loop' ); woocommerce_product_loop_start(); if ( wc_get_loop_prop( 'total' ) ) { while ( have_posts() ) { the_post(); do_action( 'woocommerce_shop_loop' ); wc_get_template_part( 'content', 'product' ); } } woocommerce_product_loop_end(); do_action( 'woocommerce_after_shop_loop' ); } else { do_action( 'woocommerce_no_products_found' ); } ?> </div> </div> </div> 中使用的位置。