bambooflow Note

ランダム生成

最終更新:

bambooflow

- view
メンバー限定 登録/ログイン
SystemC SCVによるランダム生成
メモ書き。


基本的なランダム生成

もっとも簡単なランダム生成

  • 例:範囲0〜10の整数をランダム生成
// int型のランダム変数data_pを用意
  scv_smart_ptr<int> data_p( "data" );
 
  data_p->keep_only( 0, 10 ); // 0~10までをランダム生成とする設定
 
  for (int i=0; i<10; i++) {
    data_p->next(); // ランダムの更新(これを実行しないといつまでも同じ値のまま)
    printf( "data = %d\n", data_p->read() ); // 値を取得
  }
 

  • 実行結果
data = 1
data = 10
data = 6
data = 8
data = 10
data = 2
data = 9
data = 3
data = 0
data = 7
 


配分ランダム生成

  • 例:範囲を0〜2と99〜100の整数値をランダム生成
scv_random::set_global_seed(100); // ランダムのシードを100に設定
 
scv_smart<data_t> p( "p" );
 
p->keep_only( 0, 100 );  // 0~100をランダム生成する
p->keep_out( 3, 98);     // 3〜98はランダム生成しない
 
for (int i=0; i<10; ++i) {
  p->next();
  printf( "data = %d\n", p.read() );
}
 

  • 実行結果
data = 100
data = 2
data = 0
data = 1
data = 0
data = 0
data = 99
data = 99
data = 0
data = 100
 


重み付けランダム生成


  • 例:0〜4の整数を出現率をかえてランダム生成
scv_random::set_global_seed(100);
 
    scv_bag<int> dist;
    dist.add( 0, 50 );  // 50%の割合で0を出現させる
    dist.add( 1, 30 );  // 30%の割合で1を出現させる
    dist.add( 2, 10 );  // 10%の割合で2を出現させる
    dist.add( 3, 8 );   //  8%の割合で3を出現させる
    dist.add( 4, 2 );   //  2%の割合で4を出現させる
 
    scv_smart_ptr<int> p( "p" );
    p->set_mode( dist );  //セット
 
    int total = 0;
    int cnt[5] = {0, 0, 0, 0, 0};
 
    for (int i=0; i<10000; i++) {
        int p_num;
        p->next();         // 更新
        p_num = p.read();  // ランダム値取得
 
        if (0 <= p_num && p_num < 5) {
            ++cnt[p_num];
            ++total;
        }
    }
    for (int i=0; i<5; i++) {
        printf( "p=%d, [%4d / %5d]\n", i, cnt[i], total );
    }
 

  • 実行結果
p=0, [5051 / 10000]
p=1, [2949 / 10000]
p=2, [1038 / 10000]
p=3, [ 784 / 10000]
p=4, [ 178 / 10000]
 
distで設定されたおおよその出現率でpは出力されていることがわかる。


重み付けランダム生成(レンジ指定)


  • 例:範囲をもった重み付け
scv_random::set_global_seed(100);
 
    scv_bag< pair<int,int> > dist;
    dist.add( pair<int,int>( 0, 3), 30 );  // 0〜3の値を30%の割合で出現させる
    dist.add( pair<int,int>( 4,10), 50 );  // 4〜10の値を50%の割合で出現させる
    dist.add( pair<int,int>(11,20), 15 );  // 11〜20の値を15%の割合で出現させる
    dist.add( pair<int,int>(21,80),  5 );  // 21〜80の値を5%の割合で出現させる
 
    scv_smart_ptr<int> p( "a" );
    p->set_mode( dist );
 
    int total = 0;
    int cnt[5] = {0, 0, 0, 0, 0};
 
    for (int i=0; i<10000; i++) {
        int p_num;
        p->next();
        p_num = p.read();
 
        if (0<=p_num && p_num<4) {
            ++cnt[0]; ++total;
        }
        else if (4<=p_num && p_num<11) {
            ++cnt[1]; ++total;
        }
        else if (11<=p_num && p_num<21) {
            ++cnt[2]; ++total;
        }
        else if (21<=p_num && p_num<81) {
            ++cnt[3]; ++total;
        }
    }
    printf( "[ 0- 3], [%4d / %5d]\n", cnt[0], total );
    printf( "[ 4-10], [%4d / %5d]\n", cnt[1], total );
    printf( "[11-20], [%4d / %5d]\n", cnt[2], total );
    printf( "[21-80], [%4d / %5d]\n", cnt[3], total );
 
 

  • 実行結果
[ 0- 3], [3047 / 10000]
[ 4-10], [4942 / 10000]
[11-20], [1500 / 10000]
[21-80], [ 511 / 10000]
 



制限付きランダム生成(scv_constraint_baseの使用)


scv_constraint_baseを使うと、制約を1つのクラスにまとめることができるメリットがある。
このクラスは継承することも可能で、制約をより効率的に与えることができるようになる。

  • 例:0〜4または6〜10までの整数値をランダム生成
#include "scv.h"
 
struct data_const : public scv_constraint_base {
    scv_smart_ptr<int> p;
 
    SCV_CONSTRAINT_CTOR(data_const) {
        SCV_CONSTRAINT( 0<=p() && p()<10 && p()!=5 );   // ランダム制約
    }
};
 
int sc_main( int argc, char* argv[] )
{
    scv_random::set_global_seed(100);
 
    data_const data( "data" );
 
    for (int i=0; i<20; i++) {
        data.next();             // 更新
        printf( "data = %d\n", data.p->read() );  // ランダム値取得
    }
 
    return 0;
}
 

  • 実行結果
data = 7
data = 4
data = 1
data = 0
data = 2
data = 0
data = 6
data = 2
data = 4
data = 7
data = 9
data = 3
data = 9
data = 3
data = 4
data = 4
data = 8
data = 0
data = 6
data = 3
 

もう少し複雑なランダム生成

構造体を使ったランダム生成


  • 例:ユーザ定義型中の変数をランダム値とする
#include "scv.h"
 
// 普通のユーザ定義型を準備
struct mydata_t {
    sc_uint<16> dat;
    unsigned char array[3];
};
 
// ユーザ定義型mydata_tに合わせて定義
SCV_EXTENSIONS( mydata_t )
{
public:
    scv_extensions<sc_uint<16> > dat;
    scv_extensions<unsigned char[3]> array;
 
    SCV_EXTENSIONS_CTOR( mydata_t ) {
        SCV_FIELD( dat );
        SCV_FIELD( array );
    }
};
 
int sc_main( int argc, char* argv[] )
{
    scv_random::set_global_seed(100);
 
    mydata_t d;
    scv_smart_ptr<mydata_t> p;
 
    p->dat.keep_only(0, 10 );
 
    for (int i=0; i<10; i++) {
        p->next();       // ランダム値更新
        d = p->read();   // コピーできる
        printf( "dat=%d, array=%d, %d, %d\n",
                (int)d.dat, (int)d.array[0], (int)d.array[1], (int)d.array[2] );
    }
    return 0;
}
 

  • 実行結果
dat=10, array=208, 22, 160
dat=0, array=181, 57, 245
dat=8, array=198, 104, 204
dat=4, array=17, 156, 53
dat=7, array=92, 87, 234
dat=4, array=89, 196, 161
dat=4, array=22, 28, 162
dat=6, array=186, 74, 152
dat=8, array=110, 209, 171
dat=8, array=152, 237, 205
 


(応用)構造体+条件付きランダム生成


  • 例:
    • ユーザ定義型packet_tを用意→ランダム生成指定
    • ユーザ定義型を条件付き制約指定
    • 制約を継承して、さらに条件付き制約指定

#include "scv.h"
// 通常のユーザ定義型を用意
struct packet_t {
    sc_uint<32> src_addr;
    sc_uint<32> dest_addr;
    sc_uint<16> length;
};
 
//ユーザ定義型packet_tの拡張定義
template<>
class scv_extensions<packet_t> : public scv_extensions_base<packet_t>
{
public:
    scv_extensions< sc_uint<32> > src_addr;
    scv_extensions< sc_uint<32> > dest_addr;
    scv_extensions< sc_uint<16> > length;
 
    SCV_EXTENSIONS_CTOR(packet_t) {
        SCV_FIELD(src_addr);
        SCV_FIELD(dest_addr);
        SCV_FIELD(length);
    }
};
 
//ユーザ定義型packet_tに対する制約を設定
struct packet_base_constraint : public scv_constraint_base
{
    scv_smart_ptr<packet_t> packet;
 
    SCV_CONSTRAINT_CTOR(packet_base_constraint) {
        // Soft Constraint
        SCV_SOFT_CONSTRAINT( (packet->length > 64) && (packet->length < 1500) );  // Min & Max
        // Hard Constraint
        SCV_CONSTRAINT( packet->src_addr() != packet->dest_addr() );
        SCV_CONSTRAINT( packet->length() > 20 );
    }
};
 
// 制約packet_base_constraintを継承して新たな制約packet_constraintをつくる
struct packet_constraint : public packet_base_constraint
{
    scv_smart_ptr< sc_uint<32> > dest_min;
    scv_smart_ptr< sc_uint<32> > dest_max;
 
    SCV_CONSTRAINT_CTOR(packet_constraint) {
        // use the base constraint
        SCV_BASE_CONSTRAINT(packet_base_constraint);
 
        SCV_CONSTRAINT( (packet->dest_addr() > dest_min())
                && (packet->dest_addr() < dest_max()) );
 
        SCV_CONSTRAINT(
                ((packet->src_addr() > (packet->dest_addr() + 0x100000) ) &&
                 (packet->src_addr() < (packet->dest_addr() + 0x200000) )) ||
                ((packet->src_addr() < (packet->dest_addr() - 0x10000) )) &&
                 (packet->src_addr() > (packet->dest_addr() - 0xfffff)  ) );
        SCV_CONSTRAINT( packet->length() == 64 );
    }
};
 
 
int sc_main( int argc, char* argv[] )
{
    scv_random::set_global_seed(100);
 
    packet_t pkt;
    packet_constraint pkt_c( "pkt_c" );
 
    pkt_c.dest_min->disable_randomization();
    pkt_c.dest_max->disable_randomization();
    *pkt_c.dest_min = 0x100000;
    *pkt_c.dest_max = 0x800000;
 
    for (int i=0; i<10; i++) {
        pkt_c.next();
        pkt = pkt_c.packet->read();
        printf( "src_addr  = %08x\n", (int)pkt.src_addr );
        printf( "dest_addr = %08x\n", (int)pkt.dest_addr );
        printf( "length    = %d\n", (int)pkt.length );
    }
 
    return 0;
}
 

  • 実行結果
 *** SCV_ERROR: CONSTRAINT_ERROR_OVER_CONSTRAINED at time 0 s in process <main>
    Constraints for over-constrained object 'pkt_c' will be ignored.
src_addr  = 008e6617
dest_addr = 00711f52
length    = 64
src_addr  = 00755da2
dest_addr = 005a4210
length    = 64
src_addr  = 0054ca51
dest_addr = 006187a8
length    = 64
src_addr  = 0065a389
dest_addr = 006fd55e
length    = 64
src_addr  = 0046ce02
dest_addr = 004889e1
length    = 64
src_addr  = 004a19e6
dest_addr = 0059637b
length    = 64
src_addr  = 00268b9a
dest_addr = 001069d1
length    = 64
src_addr  = 0045c242
dest_addr = 004d6c07
length    = 64
src_addr  = 004e95ef
dest_addr = 005d25a4
length    = 64
src_addr  = 0042bb4e
dest_addr = 00313678
length    = 64
 
最初にエラーがでるけど、とりあえず気にしないでおく.
おそらく、Soft Constraintに関するエラーだと思われる.

その他の使い方

ランダム生成の停止


  • 例:出力を300に固定
scv_smart_ptr<int> p( "a" );
 
    p->disable_randomization();   // ランダム生成を停止
    p->write( 300 );              // pへ値300を書き込む
 
    for (int i=0; i<10; i++) {
        p->next();                // 更新
        printf( "data = %d\n", p->read() );  // 値取得
    }
 

data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
data = 300
 

ランダムの停止は、デバッグ時や直接代入したいときに利用できる.


分布の指定


分布の指定は4種類ある。
RAMDAM 指定分布範囲での一様なランダム生成
SCAN とりうる値で小さいものから大きいものへと生成
RANDOM_AVOID_DUPLICATE 生成可能な数値が出尽くすまで同一の値を生成しない
DISTRIBUTION scv_bag<>で確率分布を指定

デフォルト設定では、
p->set_mode( RANDOM );



順列型ランダム生成(RANDOM_AVOID_DUPLICATE)


SystemVerilogのrandcのように順列型の乱数生成のようにできる。

  • 例:0〜9までの順列型のランダム生成
scv_random::set_global_seed(100);
 
    scv_smart_ptr<int> p;
 
    p->keep_only(0, 9);
    p->set_mode( scv_extensions_if::RANDOM_AVOID_DUPLICATE ); // 分布の指定
 
    for (int i=0; i<2; i++) {
        for (int j=0; j<10; j++) {
            p->next();
            printf( "%d\n", p->read() );
        }
        printf( "\n" );
    }
 

  • 実行結果
4
1
8
9
7
2
3
6
0
5
 
8
2
1
5
0
9
4
6
7
3
 


参照

記事メニュー
目安箱バナー