Wednesday, February 17, 2016

Two-pass algorithm for binary image

Two-pass algorithm for binary image is one of the applications of union-find data structure. The idea of the algorithm is described in this lecture note (page 10/24)


Here is a simple implementation of the two-pass algorithm on binary image. The algorithm will add a label to each connected component in the image. The connectivity is tested based on the definition of 4-connectivity.

Sample input:

0 1 0 0 0 0 1
1 1 0 1 0 1 1
0 0 0 1 1 0 0

Sample output:

0 1 0 0 0 0 2
1 1 0 3 0 2 2
0 0 0 3 3 0 0



[twopass.h]


#ifndef TWOPASS_H_
#define TWOPASS_H_


#include <vector>
#include "UnionFind.h"

typedef vector< vector<int> > matrix;
matrix twoPassAlgorithm(const matrix & inMatrix);

#endif /* TWOPASS_H_ */


[twopass.cpp]

/*
 * twopass.cpp
 *
 *  Created on: Feb 17, 2016
 *      Author: ruikun
 */

#include "twopass.h"

matrix twoPassAlgorithm(const matrix & inMatrix)
{
 int nrow = inMatrix.size();
 int ncol = inMatrix[0].size();

 matrix label(nrow, vector<int>(ncol, -1)); // -1 indicates that there is no label in the cell


 UnionFind uf;
 // first pass
 int label_up;
 int label_left;

 for (int i = 0; i < nrow; ++i) {
  for (int j = 0; j < ncol; ++j) {

   if (inMatrix[i][j] == 1) {
    // boundary case: we can put boundary case outside the loop
    if (i == 0 && j == 0) {
     uf.add();
     label[0][0] = uf.getLatestLabel();
     continue;
    }

    if (i == 0) {
     if (label[0][j-1] != -1) {
      label[0][j] = label[0][j-1];
     } else {
      uf.add();
      label[0][j] = uf.getLatestLabel();
     }
     continue;
    }

    if (j == 0) {
     if (label[i-1][0] != -1) {
      label[i][0] = label[i-1][0];
     } else {
      uf.add();
      label[i][0] = uf.getLatestLabel();
     }
     continue;
    }

    // normal case

    // if only one of upper and left cell has label, then copy the label
    label_up = label[i-1][j];
    label_left = label[i][j-1];

    if (label_up != -1 && label_left == -1) {
     label[i][j] = label_up;
    } else if (label_up == -1 && label_left != -1) {
     label[i][j] = label_left;
    } else if (label_up != -1 && label_left != 1 && label_up == label_left) {
     label[i][j] = label_up;
    } else if (label_up != label_left) {
     label[i][j] = label_up;
     uf.unionNode(label_up, label_left);
    } else {  // in this case, neither of upper cell nor left cell has a label
     uf.add();
     label[i][j] = uf.getLatestLabel(); // get new label

    }
   }
  }
 }

 // re-labeling
 vector<int> classNumber(uf.getLabels());

 int _label;
 for (int i = 0; i < nrow; ++i) {
  for (int j = 0; j < ncol; ++j){

   _label = label[i][j];
   label[i][j] = (_label == -1 ? -1 : classNumber[label[i][j]]) + 1;
  }
 }


 return label;
}

Union-Find Datastructure C++ Implementaiont

Union-Find data structure, also known as the disjoint-set data structure is used to keep track of different disjoint subset of elements.

The following sources are good starting points to learn more about this data structure:

  1. Union-Find Lecture Note
  2. Data Structures & Algorithm Analysis in C++


Here is a simple C++ implementation of the union-find data structure.

[main.cpp]


#include <iostream>
#include <utility>


#include "UnionFind.h"

using namespace std;

int main()
{
 UnionFind uf;
 uf.add(8);

 uf.unionNode(1,2);
 uf.unionNode(2,3);
 uf.unionNode(4,5);
 uf.unionNode(0,5);

 cout << "print the parent of each node: " << endl;
 for (int i = 0; i < uf._count; ++i) {cout << uf._parent[i] << " ";}
 cout << endl;

 vector<int> out = uf.getLabels();
 cout << "print the label of each node: " << endl;
 for (vector<int>::size_type i = 0; i < out.size(); ++i) {cout << out[i] << " ";}
 cout << endl;

 return 0;
}


[UnionFind.h]


#ifndef UNIONFIND_H_
#define UNIONFIND_H_

#include <vector>
#include <list>

using namespace std;

class UnionFind
{
public:
 UnionFind();
 vector<int> _parent;
 vector<int> _rank;
 int _count;

 int find(int node);
 void unionNode(int node1, int node2);
 void unionForest(vector<int> parentArr);
 void add(int repeat=1);
 vector<int> getLabels();
};


#endif /* UNIONFIND_H_ */

[UnionFind.cpp]


#include <stdexcept>
#include "UnionFind.h"

using namespace std;

UnionFind::UnionFind(): _parent(), _rank(), _count(0)
{}

void UnionFind::add(int repeat)
{
 for (int i = 0; i < repeat; ++i) {
  ++_count;
  _parent.push_back(-1);
  _rank.push_back(0);
 }
}


int UnionFind::find(int node)
{
 // if the node is the root of the class, return -1 immediately
 if (_parent[node] == -1)
  return -1;

 int currentNode = node;

 list<int> path;
 int sum_rank = 0;

 while (_parent[currentNode] != -1) {
  path.push_back(currentNode);
  sum_rank += _rank[currentNode];
  currentNode = _parent[currentNode];
 }

 // set parent of the nodes in the path to the root
 for (list<int>::const_iterator it=path.begin(); it != path.end(); ++it) {_parent[*it] = currentNode;}
 _rank[currentNode] = sum_rank;

 return currentNode;
}


void UnionFind::unionNode(int node1, int node2)
{
 if (node1 == node2) return; // if the nodes are the same, do nothing

 int root1 = find(node1);
 int root2 = find(node2);

 if (root1 == node2 || root2 == node1) return ; // if node1 and node2 are in the same class(tree), do nothing




 if (_rank[node1] < _rank[node2]) {
  _parent[node2] = node1;
  _rank[node1] += _rank[node2] + 1;
 } else {
  _parent[node1] = node2;
  _rank[node2] += _rank[node1] + 1;
 }

}


void UnionFind::unionForest(vector<int> parentArr)
{
 // check if parentArr represents the same nodes
 if (parentArr.size() != (vector<int>::size_type)_count)
  throw invalid_argument("The number of nodes does not match");

 int _root;
 for (vector<int>::size_type i = 0; i < parentArr.size(); ++i) {
  _root = parentArr[i];
  if (_root != -1) unionNode(i, _root);

 }
}


vector<int> UnionFind::getLabels()
{
 int cLabel = 0;
 int _root = -1;
 vector<int> label(_count, -1);

 for (int i=0; i < _count; ++i) {
  _root = find(i);

  if (_root == -1) {     // if node(i) i the root
   if (label[i] == -1)   // if node(i) does not have a label
    label[i] = cLabel++;
  } else if (label[_root] == -1) {
   label[_root] = cLabel;
   label[i] = cLabel;
   ++cLabel;
  } else {
   label[i] = label[_root];
  }
 }

 return label;
}

Saturday, February 13, 2016

My First A* Search Algorithm: 9Puzzle


The principal idea of the A* search algorithm is to have a cost function which consists of two parts: the known cost and the forecast cost.  The known cost is the distance between the current status and the initial status; the forecast cost is a heuristic function that estimate the distance between the current status and the target status.

The A* search algorithm is the generalization of BFS algorithm and the pure greedy algorithm. If we set known cost to zero, we get back to the pure greedy algorithm which only relies on the heuristic function; on the other hand, if we set forecast cost to zero, we will get the classic BFS algorithm.

The key component of A* search algorithm is to construct the heuristic function. If the heuristic function nevers overestimate the cost/distance, the algorithm is guaranteed to find the optimal solution.


The following code is the implementation of the 15puzzle solver.  As in the A* search algorithm, every time it expands the nodes the program should select a node with minimum cost, we will use a priority queue to store all the information of the status. To avoid the re-visit issue, we use a set to keep track of visited node.


Here are some note of the implemenation:
  1. The heuristic function plays a crucial rule in the performance of the A* search algorithm.
  2. One of the weaknesses of the A* search algorithm and other similar algorithms is that the algorithm need to remember all the historical path. This is the price we need to pay to become less greedy.
  3. Though pointer is not highly recommended in C++, it is still very useful and flexible. In particular, when we are using container.

[main.cpp]

#include <utility>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
#include <math.h>
#include <set>
#include <stack>

// project headers
#include "Status.h"
#include "mUtility.h"

using namespace std;



int main(int argc, const char * argv[]) {

    vector<int> init_arr = {1,2,3,4,0,5,6,7,8};
    vector<int> target_arr = {1,0,8,6,4,5,7,2,3};

    Status* initStatus = new Status(init_arr);
    Status* targetStatus = new Status(target_arr);

    // set the target status
    initStatus->targetStatus = targetStatus;


    // start the A* search
    AStarSearch(*initStatus, *targetStatus);

    // release memory
    delete initStatus;
    delete targetStatus;

    cout << endl << "the end" << endl;

    return 0;
}  

 [Status.h]

/*
 * Status.h
 *
 *  Created on: Feb 13, 2016
 *      Author: ruikun
 */

#ifndef STATUS_H_
#define STATUS_H_


#include <vector>
#include <stdlib.h>

using namespace std;


class Status
{
public:
    Status();
    explicit Status(vector<int>& arr);


    vector<int> arr;      // the table is kept in this array
    int code;      // the code is used as a hash value and in our case, it is used for each status
    int existingCost;
    int forecastCost;    // this is the value of heuristic function
    int totalCost;
    int posEmpty;     // position of the empty cell in the table
    int sizeOfSide;
    const Status *prev;    // pointer to parent status. It is used when printing the solution path
    Status *targetStatus;

    void computeCode();
    void update();     // TODO: think of merge computeCode() and update()
    Status* moveToEmpty(int pos) const;   // implement a move. This will generate a new status.

};




#endif /* STATUS_H_ */


[Status.cpp]

/*
 * Status.cpp
 *
 *  Created on: Feb 13, 2016
 *      Author: ruikun
 */

#include "Status.h"
#include <stdlib.h>
#include <math.h>


Status::Status()
: arr()
, code(-1)
, existingCost(0)
, forecastCost(0)
, totalCost(0)
, posEmpty(-1)
, sizeOfSide(0)
, targetStatus(NULL)
, prev(NULL)
{}



Status::Status(vector<int>& inArr)
: code(-1)
, existingCost(0)
, forecastCost(0)
, totalCost(0)
, posEmpty(-1)
, sizeOfSide(sqrt(inArr.size()))
, targetStatus(NULL)
, prev(NULL)
{

    // copy the array of configuration
    for (int i = 0; i < inArr.size(); ++i) {arr.push_back(inArr[i]);}


    // get the position of empty square
    for (int i = 0; i < arr.size(); ++i) {
        if (arr[i] == 0) {
            posEmpty = i;
            break;
        }
    }

    computeCode();
}


void  Status::computeCode() {
    int s = 0;
    int factor = 1;
    for (int i = 0; i < arr.size(); ++i) {
        s += arr[i] * factor;
        factor *= 10;
    }
    code = s;
}

void Status::update(){

    // calculate the forecast cost
    int count = 0;
    for (int i = 0; i < arr.size(); ++i)
        if (arr[i] != targetStatus->arr[i])
            ++count;

    forecastCost = count;

    totalCost = existingCost + forecastCost;

}


Status* Status::moveToEmpty(int pos) const{
    vector<int> _arr(arr.begin(), arr.end());
    _arr[this->posEmpty] = arr[pos];
    _arr[pos] = 0;

    Status* oStatus = new Status(_arr);
    oStatus->existingCost = this->existingCost + 1;
    oStatus->targetStatus = this->targetStatus;
    oStatus->prev = this;
    oStatus->computeCode();
    oStatus->update();

    return oStatus;
}



[mUtility.h]

/*
 * mUtility.h
 *
 *  Created on: Feb 13, 2016
 *      Author: ruikun
 */

#ifndef MUTILITY_H_
#define MUTILITY_H_


#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <iostream>
#include "Status.h"

using namespace std;

// The following functions will compute the position of adjacent cells of the given position
// If the position does not exist, the function will return -1

int up(int pos, int sizeOfSide);
int down(int pos, int sizeOfSide);
int left(int pos, int sizeOfSide);
int right(int pos, int sizeOfSide);


void AStarSearch(Status& initStatus, Status& targetStatus);


class myCompare
{
public:
 bool operator()(Status* lhs, Status* rhs);
};

typedef priority_queue<Status*, vector<Status*>, myCompare> TYPE_queue;


bool addNewStatus(const Status& inStatus, TYPE_queue & inQueue, set<int>& record, int targetCode);



#endif /* MUTILITY_H_ */

[mUtility.cpp]


/*
 * mUtility.cpp
 *
 *  Created on: Feb 13, 2016
 *      Author: ruikun
 */


#include "mUtility.h"
#include <functional>

using namespace std;




bool myCompare::operator() (Status* lhs, Status* rhs) {return lhs->totalCost > rhs->totalCost;}



void AStarSearch(Status& initStatus, Status& targetStatus)
{
    TYPE_queue mQueue;
    set<int> mRecord;       // keep record of visited status

    // initialize
    mQueue.push(&initStatus);

    mRecord.insert(initStatus.code);

    int targetCode = targetStatus.code;



    cout << "searching for solution..." << endl;



    while (!mQueue.empty() && find(mRecord.begin(), mRecord.end(), targetCode) == mRecord.end()){
     cout << "the size of the queue: " << mQueue.size() << endl;
     cout << "the size of the record: " << mRecord.size() << endl;
        // pop the status with minimum cost
        const Status * ptrStatus = mQueue.top();


        for (vector<int>::size_type i = 0; i < ptrStatus->arr.size(); ++i){
         cout << ptrStatus->arr[i] << " " ;
        }
        cout << endl;

        cout << "totalCost: " << ptrStatus->totalCost << endl;
        cout << endl;

        if (addNewStatus(*ptrStatus, mQueue, mRecord, targetCode)) {
         break;
        }

        mQueue.pop();
    }

    /* TODO:
     * (1) need to handle the case where initStatus == targetStatus
     * (2) the current code does not clear all the memory
     */

    // clear the memory
    while (!mQueue.empty()) {
     delete mQueue.top();
     mQueue.pop();

    }

}


bool addNewStatus(const Status& inStatus, TYPE_queue& inQueue, set<int>& record, int targetCode)
{
    int posMove;

    int posEmpty = inStatus.posEmpty;
    int sizeOfSide = inStatus.sizeOfSide;

    bool find_solution = false;
    Status* sol = NULL;
    Status* tmp;

    //TODO: there are duplications of codes here.

    if ( (posMove = up(posEmpty, sizeOfSide)) != -1) {
     tmp = inStatus.moveToEmpty(posMove);
     if (find(record.begin(), record.end(), tmp->code) == record.end()){
      inQueue.push(tmp);
      if (tmp->code == targetCode) {
       find_solution = true;
       sol = tmp;
      } else {
       record.insert(tmp->code);
      }
     }
    }


    if ( (posMove = down(posEmpty, sizeOfSide)) != -1){
     tmp = inStatus.moveToEmpty(posMove);
     if (find(record.begin(), record.end(), tmp->code) == record.end()){
      inQueue.push(tmp);
      if (tmp->code == targetCode) {
       find_solution = true;
       sol = tmp;
      } else {
       record.insert(tmp->code);
      }
     }
    }


    if ( (posMove = left(posEmpty, sizeOfSide)) != -1){
     tmp = inStatus.moveToEmpty(posMove);
     if (find(record.begin(), record.end(), tmp->code) == record.end()){
      inQueue.push(tmp);
      if (tmp->code == targetCode) {
       find_solution = true;
       sol = tmp;
      } else {
       record.insert(tmp->code);
      }
     }
    }


    if ( (posMove = right(posEmpty, sizeOfSide)) != -1){
     tmp = inStatus.moveToEmpty(posMove);
     if (find(record.begin(), record.end(), tmp->code) == record.end()){
      inQueue.push(tmp);
      if (tmp->code == targetCode) {
       find_solution = true;
       sol = tmp;
      } else {
       record.insert(tmp->code);
      }
     }
    }


    // test if we reach the target status
    if (sol) { // reach the target status

        stack<const Status *> mStack;

        const Status *ptr = sol;

        while (ptr != NULL) {
            mStack.push(ptr);
            ptr = ptr->prev;
        }

        while (!mStack.empty()){
            ptr = mStack.top();
            mStack.pop();

            for (vector<int>::size_type i =0; i < ptr->arr.size(); ++i) {
             if (i % ptr->sizeOfSide == 0)
              cout << endl;
             int tmp = ptr->arr[i];

             if (tmp == 0) {
              cout << 'X' << " ";
             } else {
              cout << tmp << " ";
             }
            }

            cout << endl;
        }
    }
    return find_solution;

}






int up(int pos, int sizeOfSide)
{

    int row = pos / sizeOfSide;
    int col = pos % sizeOfSide;

    if (row == 0) {
        return -1;
    } else {
        return (row - 1) * sizeOfSide + col;
    }

}


int down(int pos, int sizeOfSide)
{
    int row = pos / sizeOfSide;
    int col = pos % sizeOfSide;

    if (row == sizeOfSide - 1) {
        return -1;
    } else {
        return (row + 1) * sizeOfSide + col;
    }
}

int left(int pos, int sizeOfSide)
{
    int col = pos % sizeOfSide;

    if (col == 0) {
        return -1;
    } else {
        return pos - 1;
    }
}

int right(int pos, int sizeOfSide)
{
    int col = pos % sizeOfSide;
    if (col == sizeOfSide - 1) {
        return -1;
    } else {
        return pos + 1;
    }
}



bool compare(const Status&  l_status, const Status&  r_status)
{
    return l_status.totalCost < r_status.totalCost;
}





Thursday, April 2, 2015

2015-04-02



原本以自己会利用晚上的时间好好看看,最终还是想找到一个其他的解决方案来消磨时间突然发现原来自己并没有什么特殊的兴趣爱好,这点着实让我头疼。对电影电视不感兴趣,音乐也仅仅是喜欢,没事就开着网易云音乐随便挑一个歌单就开始听着,当做所有事情的背景音乐。 今天在做饭的时候想着温习一下法语,便打开FranceInfo Direct,没想到这段时间他们那里又在闹罢工,所以节目不能正常播出。只有在整点和半点的时候才播放新闻,其余时间播放音乐。想要看看书,却不知道从何处下手。挑了本网上推荐的关于self-improvement的书,英文版,想着学习学习英语也不错。不知是因为这本书本身写的很无聊还是我英语太差,自己不能完全明白这本书究竟在讲些什么。坚持了一会儿,实在是觉得枯燥。当然我应该还是会把它读完,否则又是半途而废相当的不好。之后挑了本关于谈判的书,这回找的是中文版。阅读英文书籍的速度与阅读中文书籍的速度还是相差了一大截。

两本书都是畅销书。我发现很多畅销书都喜欢例举大量的实例来表达自己的观点,然后在每个章节的末尾有个像模像样的总结。所以,我觉得第一本书很无聊可能真的不是因为我的英语太差。虽然书本身写得很无趣,但是书中的观点倒是挺有意思。尤其是介绍谈判技巧的《优势谈判》,里面列举的一些要点和注意事项让我觉得很是熟悉。我不禁回想起自己和别人的谈判经历,真的是太过天真太过稚嫩,把书中提到的错误一个不剩的都实践了一遍。其实关于compensation就是一场谈判,只是我之前没有意识到这一点,再加上自己并没有太多的选择而且还有一些别的顾虑,所以压根就没有把和HR的对话当做谈判交易来对待。以至于当挂掉HR电话的时候就开始后悔。也是在那个时候我发现最让人难过的事实往往是自己可以做得更好。

还是应了那句老话,书到用时方恨少。自己读书量之少以至于都没有意识到有些知识可以从书本中获取。习惯了在网上搜索,但是相对于网上零散的知识以及网友们的经验,书本更能提供一套相对完整的体系。并不是说一切只是都能从书本里获得,但是至少书本可以给我们带来一些启发。遗憾的是一流的书太多,二流的书更多。往往找到一本好书需要花费一段时间,如果运气不好遇到一本二流的书,很有可能看完全本书只能获得一点点愉悦。所以说,读书是一件奢侈的事情。

如果真的可以完全放松下来,无所事事也未尝不是件好事。有时候也十分享受一个人的独处,感受着时间缓慢的从身边流淌。什么也不做,什么也不想,就这样吧,我们总会去到一个地方。

《从前慢》——木心

记得早先少年时
大家诚诚恳恳
说一句 是一句
  
清早上火车站
长街黑暗无行人
卖豆浆的小店冒着热气
  
从前的日色变得慢
车,马,邮件都慢
一生只够爱一个人
  
从前的锁也好看
钥匙精美有样子
你锁了 人家就懂了


Monday, February 9, 2015

Hackerrank: Xoring Ninja Solution in Ocaml


Problem Statement
https://www.hackerrank.com/challenges/xoring-ninja

Given a list containing N integers, calculate the XOR_SUM of all the non-empty subsets of the list and print the value of sum % (109 + 7).

XOR operation on a list (or a subset of the list) is defined as the XOR of all the elements present in it.
E.g. XOR of list containing elements {A,B,C} = ((A^B)^C), where ^ represents XOR.

E.g. XOR_SUM of list A having three elements {X1, X2, X3} can be given as follows.
All non-empty subsets will be {X1, X2, X3, (X1,X2), (X2,X3), (X1,X3), (X1,X2,X3)}

XOR_SUM(A) = X1 + X2 + X3 + X1^X2 + X2^X3 + X1^X3 + ((X1^X2)^X3)

Input Format
An integer T, denoting the number of testcases. 2T lines follow.
Each testcase contains two lines, first line will contains an integer N followed by second line containing N integers separated by a single space.

Output Format
T lines, ith line containing the output of the ith testcase.

Constraints
1 <= T <= 5
1 <= N <= 105
0 <= A[i] <= 109

let large_number = 1000000007 ;;
let compute n k =
  if k = 0 then
    0
  else
    let result = ref 1 in
    for i = 1 to (n - 1) do
      result := (!result lsl 1) mod large_number
    done;
    !result
;;

let process arr length =
  let max_elem = ref (-1) in
  for i = 0 to (length - 1 ) do
    if (arr.(i) > !max_elem) then
      max_elem := arr.(i)
  done;
  let level = ref 0
  and result = ref 0 in
  while !max_elem > 0 do

    let count = ref 0 in
    for i = 0 to (length - 1) do
      count := !count + (1 land arr.(i));
      arr.(i) <- (arr.(i) lsr 1)
    done;
    (* Printf.printf "max_elem: %d, level: %d, result: %d, count: %d\n" !max_elem !level !result !count; *)
    let res = compute length !count in
    result := (!result + (res lsl !level) ) mod large_number;
    level := !level + 1 ;
    max_elem := !max_elem lsr 1 ;
  done;
  !result
;;


(* main *)

let num_case = read_int () ;;

for i = 1 to num_case do
  let n = read_int () in
  let line = read_line () in
  let lst_string = Str.split (Str.regexp " ") line in
  let lst_int = List.map int_of_string lst_string in
  let arr = Array.of_list lst_int in
  let result = process arr n in
  Printf.printf "%d\n" result
done ;;

Sunday, February 8, 2015

Hackerrank: AND Product Solution in Ocaml


AND product


Problem Statement


You will be given two intergers A and B. You are required to compute the bitwise AND amongst all natural numbers lying between A and B, both inclusive.

Input Format


First line of the input contains T, the number of testcases to follow.
Each testcase in a newline contains A and B separated by a single space.

Constraints


1 <= T <= 200
0 <= A <= B <= 2^32

Output Format


Output one line per test case with the required bitwise AND



let read_line_int () =
  let line = read_line () in
  let lst = Str.split (Str.regexp " ") line in
  let lst_int = List.map int_of_string lst in
  let arr = Array.of_list lst_int in
  arr
;;


let number_of_bits n =
  let rec num_of_bits count n =
    match n with
    | 0 -> count
    | n -> num_of_bits (count + 1) (n lsr 1)
  in
    num_of_bits 0 n ;;


let rec process result a b =
  let n_bits_a = number_of_bits a
  and n_bits_b = number_of_bits b in
  match n_bits_a = n_bits_b with
  | false -> result
  | true ->
    let m = 1 lsl (n_bits_a - 1) in
    process (result + m) (a - m) (b - m)
;;

let process_main a b =
  process 0 a b ;;



(* main part *)

let num_case = read_int () ;;

for i = 1 to num_case do
  let arr = read_line_int () in
  let result = process_main arr.(0) arr.(1) in
  Printf.printf "%d\n" result
done;;

Friday, February 6, 2015

Generate Partitions


let rec generate start n =
  if start = 0 then
    match n with
    | 0 -> raise (Invalid_argument "n")
    | 1 -> [[1]]
    | k -> let result = generate 1 k in [k]::result
  else if start < n then
        (let result = ref [] in
          for i = start to n - start do
            let tmp_result = generate i (n - i) in
            let tmp_result_i = List.map (fun lst -> i :: lst) tmp_result in
            let tmp_result2 = tmp_result_i @ !result in
            result := tmp_result2
          done;
          !result ;)
  else
    [[n]];;


let generate_partitions n =
  generate 0 n ;;


generate_partitions 1 ;;
generate_partitions 2 ;;
generate_partitions 3 ;;