STEP 1.2 幅優先探索と反復深化探索 2016

<背景解説>

  1. ホームディレクトリに作業ディレクトリ problem-solvingを作成しよう。このディレクトリに移動する。
  2. 小笠原先生のディレクトリから、今回の課題に関係するファイルをコピーする
  3. UNIXでコンパイル
  4. 深さ優先探索を実行してみる (mt-search b m ゴールの頂点 探索方法(0:深さ, 1:幅, 2:反復深化)
  5. リスト構造をプリントする関数には、printListと、printListLengthがある。
<実行例>
[z190119@ls03 ~/oga]% ./mt-search 2 3 4 0 (モデル木では分岐b=2, 深さm=3の2段目(d=2)左端の頂点)
-> [0] -> NULL
-> [2] -> [1] -> NULL
-> [6] -> [5] -> [1] -> NULL
-> [14] -> [13] -> [5] -> [1] -> NULL
-> [13] -> [5] -> [1] -> NULL
-> [5] -> [1] -> NULL
-> [12] -> [11] -> [1] -> NULL
-> [11] -> [1] -> NULL
-> [1] -> NULL
-> [4] -> [3] -> NULL
Path 3 : -> [4] -> [1] -> [0] .

[z190119@ls01 ~/oga]% ./mt-search 2 3 6 0
-> [0] -> NULL
-> [2] -> [1] -> NULL
-> [6] -> [5] -> [1] -> NULL
Path 3 : -> [6] -> [2] -> [0] .

<問題>

<実行結果 例> 

幅優先探索

[z190119@ls01 ~/oga]% ./mt-search 2 3 4 1
-> [0] -> NULL
-> [1] -> [2] -> NULL
-> [2] -> [3] -> [4] -> NULL
-> [3] -> [4] -> [5] -> [6] -> NULL
-> [4] -> [5] -> [6] -> [7] -> [8] -> NULL
Path 3 : -> [4] -> [1] -> [0] .

[z190119@ls01 ~/oga]% ./mt-search 2 3 6 1
-> [0] -> NULL
-> [1] -> [2] -> NULL
-> [2] -> [3] -> [4] -> NULL
-> [3] -> [4] -> [5] -> [6] -> NULL
-> [4] -> [5] -> [6] -> [7] -> [8] -> NULL
-> [5] -> [6] -> [7] -> [8] -> [9] -> [10] -> NULL
-> [6] -> [7] -> [8] -> [9] -> [10] -> [11] -> [12] -> NULL
Path 3 : -> [6] -> [2] -> [0] .

反復深化探索

[z190119@ls03 ~/oga]% ./mt-search 2 3 3 2
==================== cut depth =  1 ==================== Open:-> [0] -> NULL Open:-> [2] -> [1] -> NULL Open:-> [1] -> NULL Open:-> NULL ==================== cut depth =  2 ==================== Open:-> [0] -> NULL Open:-> [2] -> [1] -> NULL Open:-> [6] -> [5] -> [1] -> NULL Open:-> [5] -> [1] -> NULL Open:-> [1] -> NULL Open:-> [4] -> [3] -> NULL Open:-> [3] -> NULL Path 3 : -> [3] -> [1] -> [0] . [z190119@ls01 ~/oga]% ./mt-search 2 3 6 2 ==================== cut depth = 1 ==================== Open:-> [0] -> NULL Open:-> [2] -> [1] -> NULL Open:-> [1] -> NULL Open:-> NULL ==================== cut depth = 2 ==================== Open:-> [0] -> NULL Open:-> [2] -> [1] -> NULL Open:-> [6] -> [5] -> [1] -> NULL Path 3 : -> [6] -> [2] -> [0] .

(解答あり。コメントは少ない)

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MALLOC malloc
#define FREE(X) free(X)
// #include <gc.h>
// #define MALLOC GC_MALLOC
// #define FREE(X)

/************************************************************
 * State
 ************************************************************/
typedef int stid;

/**************************************************
 * 履歴用状態リスト
 **************************************************/
typedef struct _SL{
  stid state;
  struct _SL *next;
} SL;


SL *newSL(){
  SL *tmppt;

  tmppt = MALLOC(sizeof(SL));
  tmppt->next = NULL;
  return tmppt;
}

SL *pushSL(stid state, SL *pt){
  SL *tmppt;

  tmppt = newSL();
  tmppt->state = state;
  tmppt->next = pt;
  return tmppt;
}

SL *popSL(SL *pt){
  SL *tmppt;

  tmppt = pt->next;
  FREE(pt);
  return tmppt;
}

bool memberSL(stid state, SL *pt){

  if(pt == NULL) return false;
  else if (pt->state == state) return true;
  else return memberSL(state, pt->next);
}

int lengthSL(SL *pt){

  if(pt == NULL){
    return 0;
  } else {
    return lengthSL(pt->next) + 1;
  }
}

void printSL(SL *pt){

  if(pt == NULL) printf(".\n");
  else {
    printf("-> [%d] ", pt->state);
    printSL(pt->next);
  }
}

/************************************************************
 * 探索用木生成
 ************************************************************/
int BF; // Branching Factor
int MD; // Max Depth

// treeSize(D)
// size of a model tree with branching factor BF and depth D
// \sum_{j=0}^D B^j

int treeSize(int d){

  if(d <= 0) return 1;
  else return 1 + BF * treeSize(d-1);
}

// treeDepth(N)
// depth of the node N in a model tree with branching factor BF
// (root = 0)
int treeDepth(stid n){

  if(n == 0) return 0;
  else return 1 + treeDepth((n - 1) / BF);
}

// firstChild(N)
// the first child of the node N in a model tree with branching factor BF
// (root = 0)
bool firstChild(stid *p, stid *c){
  int d;
  d = treeDepth(*p);
  if(d == MD) return false;
  if(d == 0) *c = 1;
  else *c = treeSize(d) + BF * (*p - treeSize(d - 1));
  return true;
}

SL *generateChildren(stid p){
  stid fc;
  stid i;
  SL *sp = NULL;

  if(firstChild(&p, &fc)){
    //    printState(p); printf(" - "); printState(fc); printf("\n");
    //    for(i = 0; i < BF; i++) sp = pushSL(fc + i, sp);
    for(i = BF ; i != 0; i--) {
      //      printState(fc + i - (stid) 1); printf("\n");
      sp = pushSL(fc + i - (stid) 1, sp);
    }
  }
  return sp;
}

/************************************************************
 * 探索アルゴリズム用リスト
 ************************************************************/
typedef struct _list {
  stid state;
  int value;
  SL *history;
  struct _list *next;
} list;
list *ol;

#define PRINTLIST printList

list *newList(){

  list *tmppt;

  tmppt = MALLOC(sizeof(list));
  tmppt->next = NULL;
  tmppt->value = -1;
  // tmppt->state[BMAX2]='\0';
  return tmppt;
}

list *popList(list *pt){
  list *tmppt;

  tmppt = pt->next;
  FREE(pt);
  return tmppt;
}

list *pushList(stid state, SL *hpt, list *pt){
  list *tmpst;

  tmpst = newList();
  tmpst->next = pt;
  tmpst->state = state;
  tmpst->history = hpt;
  return tmpst;
}

/* 課題 */
list *appendList(stid state, SL *hpt, list *pt){
   /* 再帰バージョン */
  list *tmpst;

  if(pt == NULL){ /* ptそのものがNULLのとき 最後の要素 停止条件 */
    tmpst = newList(); /* tmpst -> next は、NULLで初期化されている */
    tmpst->state = state;
    tmpst->history = hpt; /* hptは、この頂点までの経路情報 SL型 */
    return tmpst; /* 新要素のアドレス */
  } else { /* 再帰条件。returnされるアドレスを繋ぎなおしていることに注意 */
    pt->next = appendList(state, hpt, pt->next); /* pt -> next == NULLのとき、つまり最後の要素だけ、変更になる */
    return pt; /* 自分自身のアドレスをreturn */
  }



  /**************************************************/
}

int lengthList(list *pt){

  if(pt == NULL){
    return 0;
  } else {
    return lengthList(pt->next) + 1;
  }
}

void printList(list *pt){

  if(pt != NULL){
    printf("-> [%d] ", pt->state);
    printList(pt->next);
  } else {
    printf("-> NULL\n");
  }
}

void printListLength(list *pt){

  printf(" %d\n", lengthList(pt));
}

/************************************************************
 * 探索アルゴリズム
 ************************************************************/

/**************************************************
 深さ優先探索 (Depth First Search)
 **************************************************/
SL *dfs(stid start, stid goal){
  int i;
  stid curstate;
  SL *nextstateset;
  SL *curhpt;

// 探索管理用リスト Lを初期状態だけのリストにする
  ol = NULL;
  ol = pushList(start, NULL, ol);

// while Lが空リストでない
  while(ol != NULL){
    PRINTLIST(ol);  // 探索管理用リストをプリント

    /* Lの先頭要素を取り出して、curstateに代入 */
    curstate = ol->state;
    curhpt = pushSL(curstate, ol->history);
    ol = popList(ol);
    if(curstate == goal) return(curhpt);

    nextstateset = generateChildren(curstate);
    while(nextstateset != NULL){
      if(memberSL(nextstateset->state, curhpt)==false){
        ol = pushList(nextstateset->state, curhpt, ol);
      }
      nextstateset=popSL(nextstateset);
    }
  }
  return(NULL);
}


/**************************************************
 幅優先探索 (Breadth First Search)
 **************************************************/
SL *bfs(stid start, stid goal){
  int i;
  stid curstate;
  SL *nextstateset;
  SL *curhpt;

// 探索管理用リスト Lを初期状態だけのリストにする
  ol = NULL;
  ol = pushList(start, NULL, ol);

// while Lが空リストでない
  while(ol != NULL){
    PRINTLIST(ol);  // 探索管理用リストをプリント

    /* Lの先頭要素を取り出して、curstateに代入 */
    curstate = ol->state;
    curhpt = pushSL(curstate, ol->history);
    ol = popList(ol);
    if(curstate == goal) return(curhpt);

    nextstateset = generateChildren(curstate);
    while(nextstateset != NULL){
      if(memberSL(nextstateset->state, curhpt)==false){
/*      ol = pushList(nextstateset->state, curhpt, ol); */
        ol = appendList(nextstateset->state, curhpt, ol);
      }
      nextstateset=popSL(nextstateset);
    }
  }
  return(NULL);
}

/**************************************************
 深さ制限探索 (Depth-limited Search)
 **************************************************/

SL *dls(stid start, stid goal, int limit){
  /**************************************************/
}

/**************************************************
 反復深化探索 (Iterative Deepening Search)
 **************************************************/
SL *ids(stid start, stid goal){
  int cutdepth;
  SL *result;

  cutdepth = 1;
  printf("==================== cut depth = %2d ====================\n",
         cutdepth);

  while((result = dls(start, goal, cutdepth++)) == NULL){
    printf("==================== cut depth = %2d ====================\n",
           cutdepth);
  }
  return(result);
}

/**********************************************************************
 Main
 **********************************************************************/

typedef struct _searchfunc {
  char *comment;
  SL *(*func)(stid, stid);
} searchfunc;

searchfunc searchtable[] = {
  {"Depth First Search", dfs},
  {"Breadth First Search", bfs},
  {"Iterative Deepening Search", ids},
  {NULL, NULL}
};

void help(char *cmdname){
  int i;

  fprintf(stderr, "Usage: %s BranchingFactor MaxDepth Goal [search_algorithm]\n", cmdname);
  for(i = 0; searchtable[i].comment!=NULL; i++){
    fprintf(stderr, "  %d : %s\n", i, searchtable[i].comment);
  }
}

int main(int argc, char *argv[]){
  stid start, goal;
  SL *sp;
  int maxalg, curalg;

  for(maxalg = 0; searchtable[maxalg].comment!=NULL; maxalg++);

  // 引数の個数のチェックと探索方法(第5引数,デフォールトは 0)の設定
  if( (argc != 4 && argc != 5) ||
      (curalg= argc == 5 ? atoi(argv[4]) : 0) < 0 ||
      maxalg <= curalg) {
    help(argv[0]);
    exit(0);
  }

  // 初期状態(0), 木のサイズ(分岐数,深さ)と目標状態の設定
  start = 0;
  BF = atoi(argv[1]);
  MD = atoi(argv[2]);
  goal = atoi(argv[3]);

  // 探索の実施
  sp = (searchtable[curalg].func)(start, goal);
  printf("Path %d : ", lengthSL(sp));
  printSL(sp);
}