2014년 6월 16일 월요일

design pattern

Object creation
Prototype
Factory Method
Abstract Factory
Builder
Singleton

Interface adaptation
Adapter
Bridge
Facade

Decoupling of Objects
Mediator
Observer

Abstract collection
Composite
Iterator

Behavioral extension
Visitor
Decorator
Chain of Responsibility

Algorithm encapsulation
Template method
Strategy
Command

Performance and object access
Flyweight
Proxy

State of object
Memento




Abstract factory
-switch-case는 class의 상속 관계(추상-구상)를 이용하면 없앨 수 있다. 
-client는 factory 클래스와 product 클래스의 인터페이스만 사용한다.





// Abstract factory pattern
// Coded by FunMV
class Scanner {}; // 생성할 product의 추상클래스
class Parser {};
class Codegenerator {};
class Optimizer {};

class  WindowsScanner: public Scanner {}; //product의 구상클래스
class WindowsParser: public Parser {};
class WindowsCodegenerator: public Codegenerator {};
class WindowsOptimizer: public Optimizer {};

class LinuxScanner: public Scanner {}; //product의 구상클래스
class LinuxParser: public Parser {};
class LinuxCodegenerator: public Codegenerator {};
class LinuxOptimizer: public Optimizer {};


class CompilerFactory // 추상팩토리 클래스
{
public:
virtual Scanner* CreateScanner()=0; //관련 기능들의 덩어리 생성예정
virtual Parser* CreateParser()=0;
virtual Codegenerator* CreateCodegenerator()=0;
virtual Optimizer* CreateOptimizer()=0;
};

// 구상 팩토리 클래스
// windows os에 맞는 컴파일러 관련 기능들의 덩어리 구현
class WindowsCompiler: public CompilerFactory
{
public:
Scanner* CreateScanner()
{
wscanner.reset(new WindowsScanner);
return wscanner.get();
}
Parser* CreateParser()
{
wparser.reset(new WindowsParser);
return wparser.get();
}
Codegenerator* CreateCodegenerator()
{
wcodegenerator.reset(new WindowsCodegenerator);
return wcodegenerator.get();
}
Optimizer* CreateOptimizer()
{
woptimizer.reset(new WindowsOptimizer);
return woptimizer.get();
}
private:
unique_ptr<Scanner> wscanner;
unique_ptr<Parser> wparser;
unique_ptr<Codegenerator> wcodegenerator;
unique_ptr<Optimizer> woptimizer;
};

// 구상 팩토리 클래스
// Linux os에 맞는 컴파일러 관련 기능들의 덩어리 구현
class LinuxCompiler: public CompilerFactory
{
public:

};


.....


// Abstract factory pattern
cout << endl << "Abstract factory pattern: Windows compiler creation" << endl;
// 구상 클래스를 규정하는 일 없이, 상호의존적이거나 관련있는 객체들의 그룹(덩어리)
// 을 생성하는 인터페이스를 제공
// [예제] Windows 타입인지 Linux타입인지만 정해서 객체 생성만 해주면 됨
// 컴파일러의 세부 기능들(OS타입에 따른)은 추상팩토리를 상속받은 구상팩토리에서 결정

unique_ptr<CompilerFactory> wCompiler(new WindowsCompiler); // 팩토리 객체 생성
Scanner *wscanner = wCompiler->CreateScanner(); // product 생성
Parser *wparser = wCompiler->CreateParser();
Codegenerator *wcodegenerator = wCompiler->CreateCodegenerator();
Optimizer *woptimizer = wCompiler->CreateOptimizer();


....





Factory method
-product를 직접 생성하지 않고, creator에 의해 생성한다.
  product *pt = new product; // (X)



-두 factory패턴은 구조가 비슷하다.
-구상 팩토리에서 product를 생성하고 리턴한다는 것은 동일
-템플릿메서드 패턴을 활용한 객체 생성패턴
-abstract factory는 유사클래스의 덩어리를 생성




// Factory method pattern for document creation
// Coded by FunMV
class Docu // 생성할 객체(product)의 추상클래스
{
public:
virtual void Print()=0;
};
class HwpDocu: public Docu
{
public:
void Print()
{
cout<<"Hangul~"<<endl;
}
};
class DocDocu: public Docu
{
public:
void Print()
{
cout<<"Docx~"<<endl;
}
};

// 생성해 주는 Factory 클래스
// product(doc)를 직접 생성하지 않고
// Interface를 통해 생성
class InterfaceDocu
{
public:
Docu* CreatProduct()
{
return CreateFactory();
}

private:
virtual Docu* CreateFactory() = 0;
unique_ptr<Docu> pDoc;
};

template <typename T> // 생성 객체 타입 결정은 구성 클래스에서 함
class InterfaceTemplate: public InterfaceDocu
{
public:
Docu* CreateFactory()
{
pd.reset(new T);
return pd.get();
}
private:
unique_ptr<T> pd;
};

.....

// Factory method pattern
cout << endl << "Factory method pattern as object creation" << endl;
// 객체 생성은 추상클래스에서, 타입결정은 구상클래스에서 수행
// 만일 이렇게 하지 않으면 생성할 객체의 타입이 추가될 때마다
// 중복된 코드를 가지는 구상클래스들을 만들어야 함

// Factory method by using template
cout << endl << "Factory method by template" << endl;
unique_ptr<InterfaceDocu> hwpDoc(new InterfaceTemplate<HwpDocu>); //팩토리 객체 생성
unique_ptr<InterfaceDocu> docDoc(new InterfaceTemplate<DocDocu>);
Docu *phwp = hwpDoc->CreatProduct(); //product 생성
Docu *pdoc = docDoc->CreatProduct();
phwp->Print();
pdoc->Print();

.....

Factory method by template
Hangul~
Docx~





Prototype 
-그래픽 편집기에서 각 그래픽 요소들이 객체로 미리 생성되어져 있고, 사용자가 특정 그래픽 요소를 선택하면 해당객체는 복제됨.



- 즉, 상기한 구조가 객체 복제를 사용한 구조로 바뀜



 Facade 
-client가 서브시스템의 클래스들을 직접 사용하는 것을 막지는 않는다.
-Facade 객체는 하나만 존재하면 될 경우가 많으므로, 주로 singleton 패턴 형태로 구현하는 경우가 많다.

-C++에서는 namespace와 유사
namespace
{
    class Y
   {
        static int a;
    public:
        void f();
   };
   class Z;
   void foo();
}

int X::Y::a=0;
class X::Z
{
    int u, v, w;
public:
   Z(int b);
   int g();
};



Builder
-RTF 문서를 읽는다고 하였을 때, 보통 RTF 문서를 parsing하는 알고리즘은 변경될 필요가 없다.  



Bridge(=handle/body)
-client에 구현을 숨기거나 lib의 version upgrade를 위해 사용 시에 유용하다.
-아래 그림에서 왼쪽은 os에 독립적으로 icon, menu등을 그릴수 있다.
-또한 오른쪽을 lib upgrade로 보면 upgrade와 독립적으로 그릴 수 있다. 이것은 lib갱신을 독립적으로  할 수 있음을 의미.



Command
(1) command 생성(실제 실행할 명령(receiver)을 인자로 넘겨줌). callback함수의 역할
(2) 생성된 command 저장(callback함수를 저장하는 역할)
     Invoker는 callback함수(등록함수)를 저장하고 호출해줌
(3) Invoker에서 어떤 event(예, 마우스 클릭)가 들어오면 해당 callback함수(command)가 실행
     command의 Excute()함수 실행
(4) Excute에 의해 receiver의 action실행




State
상태기계(state machine)를 설계할 때 사용
context class 내에 정의된 것들:
     상태 객체
     초기 상태
     상태를 지정할 수 있는 함수 정의:   void setState(State *);
     user가 발생시키는 행위에 대응하는 함수(이 함수가 상태의 handle()를 호출)

State클래스는 인터페이스 역할
     가능한 여러 상태가 구상 클래스로 하위에 정의됨
     가능한 여러 handle 함수의 인터페이스를 정의
     구상 상태 클래스에서 실제 handle함수를 정의 함
               handle함수 내에서 상태 변경이 발생
              (context의 setState를 호출하고, 인자로는 다음 상태를 넘겨줌)

 




// State pattern
// 알갱이(candy) 뽑기 기계
// Coded by FunMV
//=======================================
// Current state    Event    Next state   
//---------------------------------------
//     empty      refillCandy    noCoin    
//     noCoin    insertCoin    coin
//     noCoin    ejectCoin     noCoin
//     coin        ejectCoin     noCoin
//     coin        turnCrank     ready
//     coin        insertCoin     coin
//     ready       outCandy     empty (candy 수=0)
//     ready       outCandy     noCoin (candy 수>0)
//========================================
class GumballMachine;
class State // 상태노드를 나타내는 인터페이스
{           // 상태노드는 Action을 내부 함수로 가져야 함
public:
virtual void insertCoin() = 0; //동전 삽입
virtual void ejectCoin() = 0; // 동전 배출
virtual void turnCrank() = 0; // 레버 회전
virtual void refillCandy(int candy) = 0; // candy 리필
virtual void outCandy() = 0; // candy 배출
virtual void printState() = 0; // 상태 출력
};


// 상태 1: 캔디 Ready
// 각 상태에서는 외부로 나가는(상태를 바꾸는) Action에 대해서만 구현 필요
// Candy ready 상태에서는 outCandy()이 상태를 바꾸는 Action이다.
class readyState: public State
{
public:
readyState(GumballMachine *gMachine): gbMachine(gMachine)
{}
void insertCoin() {}
void ejectCoin() {}
void turnCrank() {}
void  refillCandy(int candy) {}
void outCandy(); // state를 변경시키는 action
void printState() { cout<< "현재 상태: readyState" <<endl << endl; }
private:
// 각 상태는 context객체의 pointer를 가지고 있어야 함
GumballMachine *gbMachine;
};

// 상태 2: 캔디 매진
class emptyState: public State
{
public:
emptyState(GumballMachine *gMachine): gbMachine(gMachine)
{}
void insertCoin() {}
void ejectCoin() {}
void turnCrank() {}
void refillCandy(int candy); // state를 변경시키는 action
void outCandy() {}
void printState() { cout<< "현재 상태: emptyState" <<endl<<endl; }

private:
GumballMachine *gbMachine;
};


// 상태 3: 동전 투입
class coinState: public State
{
public:

coinState(GumballMachine *gMachine): gbMachine(gMachine), countCoin(0)
{}
void insertCoin() { countCoin++; cout << "동전 삽입: " << countCoin << endl; }
void ejectCoin();
void turnCrank(); // state를 변경시키는 action
void refillCandy(int candy) {}
void outCandy() {}
void printState() { cout<< "현재 상태: coinState" <<endl<<endl; }
private:
GumballMachine *gbMachine;
int countCoin;
};

// 상태 4: 동전 부족
class noCoinState: public State
{
public:
noCoinState(GumballMachine *gMachine): gbMachine(gMachine)
{}
void insertCoin(); // state를 변경시키는 action
void ejectCoin() { cout << "동전 없음" << endl; }
void turnCrank() { cout << "동전 없음" << endl; }
void refillCandy(int candy) {}
void outCandy() {}
void printState() { cout<< "현재 상태: noCoinState" <<endl<<endl; }

private:
GumballMachine *gbMachine;
};




// 뽑기 기계 class로 내부에 정의되어야 하는 것들:
// (1) 이 기계에서 사용하는 Actions 
// (2) 현재 state를 저장하기 위한 pointer
// (3) 존재하는 state 객체 모두 생성
// (4) 현재 기계가 가진 candy의 갯수
class GumballMachine
{
public:
GumballMachine(int candy): _candy(candy), _ready(new readyState(this))
{
_noCoin.reset(new noCoinState(this));
_coin.reset(new  coinState(this));
_empty.reset(new emptyState(this));
//_ready.reset(new readyState(this));

currentState = _noCoin.get(); // 초기 상태는 no_coin
}
void setState(unique_ptr<State> &inState)
{
currentState = inState.get();
}

// Action 1: 동전 삽입
void insertCoin()
{
currentState->insertCoin();
}

// Action 2: 동전 반환
void ejectCoin()
{
currentState->ejectCoin();
}

// Action 3: 캔디 충전
void refillCandy(int candy)
{
currentState->refillCandy(candy);
}

// Action 4: 레버 회전
void turnCrank()
{
currentState->turnCrank();
}

// Action 5: 캔디 배출
void outCandy()
{
currentState->outCandy();
}

// 현재 상태 출력
void printState()
{
currentState->printState();
}

// 상태 객체 Get 함수
unique_ptr<State>& getNoCoin() { return _noCoin; }
unique_ptr<State>& getCoin() { return _coin; }
unique_ptr<State>& getEmpty() { return _empty; }
unique_ptr<State>& getReady() { return _ready; }

        // 기타 Get 함수
int getNumCandy() { return _candy; }
void setNumCandy(int candy) { _candy = candy; }
private:
unique_ptr<State> _noCoin; // 가능한 상태 객체 선언
unique_ptr<State> _coin;
unique_ptr<State> _empty;
unique_ptr<State> _ready;

State* currentState;
int _candy;
};




MVC
Model, View, 그리고 Controller 패턴(모형)으로 UI 설계에 많이 사용된다.


UI(User Interface)에서 사용자가 발생시키는 event는 controller(전략 패턴 사용)를 통해 model의 변수(parameters)를 변경시키고, model은 notify(observer 패턴)에 의해 view를 갱신한다.

.Controller는 view의 전략 객체로 이것을 바꾸면 view의 행동이 바뀜
.View(특히 GUI에서)는 여러 단계로 겹쳐져 있는 window, panel, button, text, label 등으로 구성된다. 각 출력 항목은 복합 객체(window 등) 또는 Leaf(버턴 등)이 될 수 있다.  화면 갱신 시에는 최상위 구성 요소한테만 화면을 갱신하라고 요청한다.  나머지는 composite 패턴에 의해 자동으로 처리된다.

따라서 MVC 모델은 내부에 3가지 패턴을 적용하는데, observer, strategy, composite이다.




Composite
추상클래스를 하나 만들고 상속받은 다양한 자식클래스를 만들어 다양한 자식클래스들을 동일 클래스 다루듯 사용하는 패턴이다.

컴포지트 패턴이란 객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한다.

#include <iostream>
#include <vector>
#include <string>
 
using std::cout;
using std::vector;
using std::string;
 
class Component
{
  public:
   virtual void list() const = 0;
   virtual ~Component(){};
};
 
class Leaf : public Component 
{
  public:
   explicit Leaf(int val) : value_(val) 
   {
   }
   void list() const 
   {
      cout << "   " << value_ << "\n";
   }
  private:
   int value_;
};
 
class Composite : public Component 
{
  public:
   explicit Composite(string id) : id_(id) 
   {
   }
   void add(Component *obj)
   {
      table_.push_back(obj);
   }
   void list() const
   {
      cout << id_ << ":" << "\n";
      for (vector<Component*>::const_iterator it = table_.begin(); 
       it != table_.end(); ++it)
      {
         (*it)->list();
      }
   }
  private:
   vector <Component*> table_;
   string id_;
};
 
int main()
{
   Leaf num0(0);
   Leaf num1(1);
   Leaf num2(2);
   Leaf num3(3);
   Leaf num4(4);
   Composite container1("Container 1");
   Composite container2("Container 2");
 
   container1.add(&num0);
   container1.add(&num1);
 
   container2.add(&num2);
   container2.add(&num3);
   container2.add(&num4);
 
   container1.add(&container2);
   container1.list();
   return 0;
}

Leaf이나 Composite모두 Component에서 상속 받아 만든 동일 구상 클래스이다. 
container1은 2개의 Leaf노드를 가진다.
container2는 3개의 Leaf노드를 가진다.

container1은 container2도 가지므로 container1 밑에 2개의 Leaf와 3개의 Leaf를 가진 container2를 가진 Tree구조가 형성된다.

Composite클래스의 list명령으로 Tree를 모두 출력해 볼 수 있다.






Reference
장세찬, GoF 디자인 패턴 활용, 한빛 미디어
서완수 역, Head first Design Patterns, O'Reilly



2014년 6월 14일 토요일

일목균형표

주봉, 월봉에서도 그려볼 수 있어야 함

추세 파악이 중요함


1) 기준선

-기준을 나타내는 선

-최근 26개 캔들 중에 최고가, 최저가를 찾아서 센터 값 이은 것

-마지막에서 1봉씩 우측으로 shift해 가면서 생각해 볼 필요 있음

-26개 캔들 중에 최고점이 올라가든지, 최저점이 올라가면 기준선을 올라갈거다

 (저점이 올라가기는 힘든 상황에서는 고점이 올라가서, 선행스팬을 돌파하면 올라갈거다)


2) 전환선

-기준선의 가이드 역할을 해주는 선

-기준선이 따라오도록 미리 가이드 해줌

-9개의 캔들 중에 최고, 최저 중심 선 이은 것

-전환선이 위에 있으면 기준선이 따라 올라감

-전환과 기준선이 만나서, 전환선이 아래로 내려가면 기준선도 따라서 내려감

-미래를 예측하기 위해 전환선을 1봉씩 shift해보면 전환선이 올라가는지 내려오는지 알수 있음. 

-전환선이 선행스팬을 돌파 못하면 당연히 기준선도 돌파 안됨

-그래서 캔들이 전고점을 뚫는 것이 중요함


3) 후행스팬

-뒤에서 따라오는 선

-현 위치에서 26개 봉(캔들) 이전까지 그려질 수 있음

-현 위치의 종가가 26개의 봉 전 후행스팬 값이 됨

-일목균형표를 만든 사람은 이 지표가 가장 중요하다고 함

-변곡점을 가장 잘 잡아줌. 이 라인이 캔들라인을 (하향)돌파할 때 추세가 바뀜

 (youtube 51:00를 참고. 26봉 후에 캔들 종가가 하향 되었음을 의미함)

-즉 상승이 하강으로 바뀌거나 역 추세가 발생함


-26개 캔들이 형성되는 순간까지는 방향(추세)을 판단하지 않고 지켜봄. 후행스팬이 아직 안왔으니.

 (즉, 주가가 횡보하는 동안, 상향일지 하향일지 고민하게 되는데, 26개봉을 지켜보고, 그때 추세를 판단함)

 (일봉이 아니고, 주봉차트에서 일목을 보는게 중요함. 잘 맞음. 26개봉은 6개월. 52봉은 1년.)


4) 선행스팬 1

-현 전환선과 기준선의 센터값을 구하고, 이를 26봉 앞으로 가서 표시한 값

-단기 이평선 같은 역할

-적색으로 표기


5) 선행스팬 2

-현 캔들에서 52봉 뒤로 가서, 포함된 캔들 최고점, 최저점의 중앙값을 구하고, 이 값을 현 캔들에서 26봉 앞으로 가서 표시한 값.

-장기 이평선 같은 작용

-청색 표기


-선행1이 위, 2가 아래 있으면 양운(상승추세)

-선행2가 위, 1이 아래 있으면 음운(하락추세)


-1(단기)이 위, 2(장기)가 아래면 정배열 

-2(장기)가 위, 1(단기)가 아래면 역배열


-양음운이 바뀌면 추세전환 신호. 이는 26봉 뒤로 가서 보고 판단해야 함

-youtube 1:06분을 보면, 26봉 뒤로 간 시점에서 오래 동안 하강하다가 바닥을 다지고 있어서, 이제 오를거다라고 예상했는데,

그 시점에서 26봉 후를 보면 양음운이 교차하면서 양운이 음운으로 바뀌고 있음. 이는 상승이 끝나고 하락 추세로 전환된다는 의미임.

이 때는 오히려 주식을 팔아야 할 시점임. 

-충분한 전환이 일어나지 않은 상태에서는 함부로 판단하면 안됨

-한참의 시간을 두고 변화가 발생 하는지 확인해야 변화가 있음을 확신할 수 있음.


-추세전환을 이루기 위해 2(장기)가 아래로 내려오는 것보다 1(단기)이 오르는 것이 쉬움. 

 (이는 전환선과 기준선이 같이 올라야 함. 전환,기준선이 오르려면 또 선행스팬 1 돌파가 필요함. 캔들이 구름대를 뚫어야 함)



-1:06:30보면 이의 적용 예가 있음. 갭 하락 시점인데, 주가가 대대적 하락기로 예측. 왜냐하면 캔들이 아래로 구름대를 완전히 이탈하였음. 

몇 봉 앞을 보면 전환선이 캔들 아래, 기준선은 캔들 위라 역배열 상태. 후행스팬은 캔들 한참 아래에 위치하여 언제 돌아갈지 모름. 또한 갭하락 시점에서

전환선, 기준선은 아래로 하향. 

이 때, 앞으로 26봉을 가서 선행지표인 구름을 보면 이미 추세 전환하여 음운으로 바뀌어져 있음. 따라서, 확실한 시세 하락의 징후임.


-1:08:40에서 월봉으로 바꾸어서 보면, chart가 양운을 깨고, 구름대를 벗어남. 후행스팬은 캔들 아래에 있음. 이격이 크서 언제 붙일지 감감함. 

전환선은 기준선 아래에 있음. 오르기만 하던 기준선은 아래로 꺽끼기 시작했고, 

아직 음운으로의 전환은 나오지 않았지만 시간문제, 


6) 5가지 추세전환 신호

-캔들의 기준선 돌파

-전환선 기준선 돌파

-후행스팬 캔들 돌파

-캔들의 구름대 돌파

-음운->양운 전환



(참고) https://www.youtube.com/watch?v=oXs_WyOq1L0



2014년 6월 12일 목요일

Hallasan

한라산 정상

올라가는 길

내려가는 길

백록담 정경*



* 인용: http://www.hallasan.go.kr/hallasan/
           http://blog.daum.net/wjdgns70/8880532


2014년 6월 3일 화요일

TBB tutorials

TBB설치 (VS 2008)

○ www.threadingbuildingblocks.org
    접속->Download메뉴->안정화버전(Stable Release) 선택. 최신버전링크 클릭.
○ 원도 운영체제의 경우: tbb40_20110809oss_win.zip선택
○ 20MB파일을 받아 폴더에 압축 해제. 이 폴더 위치를 잘 기억함.
○ 환경변수 설정: TBB_INSTALL_DIR을 사용. 내컴퓨터->속성->시스템보호->고급->환경변수설정->새로만들기: 변수이름(TBB_INSTALL_DIR), 변수값(d:\tbb\tbb40_20110809oss) 등 설정



실행 디렉토리 설정
○ 속성->구성속성->디버깅->명령->찾아보기. 생성되는 파일, dll 등의 위치 설정.


DLL부분:
○ 속성->구성속성->C/C++->일반->추가 포함 디렉토리: 여기에
\(TBB_INSTALL_DIR)\include , 단 tbb설치가 되어 있고, TBB_INSTALL_DIR키워드는 미리설정, Release/Debug모드 별로 설정

○ 속성->구성속성->링커->일반->출력파일: ../Release/tbbMatch_Parallel_Dll.dll  (모드별로 설정)
○ 속성->구성속성->링커->일반->추가 라이브러리 디렉토리:
\$(TBB_INSTALL_DIR)\lib\ia32\vc9 (VC++9버전의 경우)
○ 속성->구성속성->링커->입력->추가종속성: tbb.lib (release), tbb_debug.lib(debug모드)


Run부분:
○ 속성->구성속성->C/C++->일반->추가 포함 디렉토리: 여기에 $(TBB_INSTALL_DIR)\include, 단 tbb설치가 되어 있고, TBB_INSTALL_DIR키워드는 미리설정, Release/Debug모드 별로 설정
○ 속성->구성속성->링커->일반->추가 라이브러리 디렉토리: $(TBB_INSTALL_DIR)\lib\ia32\vc9 (VC++9버전의 경우)
○ 속성->구성속성->링커->입력->추가종속성: ../Release/tbbMatch_Parallel_Dll.lib tbb.lib(Release모드),  ../Debug/tbbMatch_Parallel_Dll.lib(Debug모드), (release), tbb_debug.lib(debug모드)

배포시 Debug/Release모드에 맞는 dll/lib파일 생성방법
○ DLL프로젝트부분에서 속성->구성속성->링커->일반->출력파일: ../Debug/visOCV_debug.dll(Debug모드), 또는 ../Release/visOCV.dll(Release모드) 입력하면 해당명의 dll생성



Solution을 통한 DLL과 Run프로젝트 동시 작성
○ 파일->새로만들기->프로젝트->기타프로젝트형식->Visual Studio 솔루션:
빈솔루션/이름(적당한 이름으로 설정해 준다)/위치(적당한 위치로 설정해 준다)

○ 솔루션탐색기의 솔루션을 오른쪽 마우스로 클릭->추가->새프로젝트->Visual C++->Win32->Win32콘솔응용프로그램(이름, 위치 설정), 다음 누르고 옵션에 Dll(D)과 빈프로젝트(E) 선택후 마침

○ 솔루션탐색기의 솔루션을 오른쪽 마우스로 클릭->추가->새프로젝트->Visual C++->Win32->Win32콘솔응용프로그램(이름, 위치 설정), 다음 누르고 옵션에 콘솔응용프로그램(O)와 빈프로젝트(E) 선택후 마침


솔루션에 딸린 두 프로젝트 생성이 되었다면 개별 프로젝트의 설정을 시작한다:
○ Dll 프로젝트의 속성->구성속성->링크->일반->출력파일: 모드별로 ../Release/파일이름.dll과 ../Debug/파일이름_debug.dll 입력. 이 두 파일이 생성된 dll파일들로 모드별로 생성함. 생성된 dll을 사용할 때도 모드에 마추어 사용하여야 한다.

○ Run용 프로젝트 속성->링커->입력->추가종속성: 모드별로 ../Release/파일이름.lib와 ../Debug/파일이름_debug.lib입력.  dll이 아니고 lib이다. 즉, Dll프로젝트에서 생성한 dll파일을 실행 프로젝트에서 사용할 것이라는 점을 명시하는 부분이다.


종속성을 설정한다:
○ 솔루션->프로젝트종속성: Run프로젝트가 Dll프로젝트에 종속되어야 한다(왜냐하면 Run프로젝트가 먼저 생성된 dll을 사용하여야 하기 때문). 따라서 프로젝트(R):에 Run프로젝트 선택, 다음에 종속(D):에 Dll프로젝트 체크

○ 코딩후 빌드->전체다시빌드 한다. (debug모드, release모드 각각 실행)
○ 솔루션->Dll프로젝트->속성->구성속성->디버깅->명령: 찾아보기 눌러 솔루션/debug밑에 생성되어 있는 실행파일(debug모드)을 선택, 솔루션/release밑에 생성되어 있는 실행파일(realse모드)을 선택해 준다.

○ 다시 리빌드 하면 완료.


프로그램의 작성
○ Dll 프로젝트 디렉토리 내에 필요한 파일을 다 넣고, Run 디렉토리에는 Run 프로그램만 넣는다.
예를 들면, Dll 프로젝트 내에 header파일과 cpp파일이 있다면, Run 부에는 Dll부의 cpp를 호출하기 위해 Dll부의 header파일을 include하는 Run 프로그램 파일만 넣는다.

// Dll프로젝트 내의 header파일
#define DLLEXPORT
#ifdef DLLEXPORT
#define DLL_MODE __declspec(dllexport)
#define EXPIMP_TEMPLATE
#else
#define DLL_MODE __declspec(dllimport)
#define EXPIMP_TEMPLATE extern
#endif

#pragma once

#include <iostream>
#include <vector>
#include <math.h>
#include <time.h>
#include <conio.h>

using namespace std;
class DLL_MODE visTestDll
{
public:
 visTestDll(int a, float b);
 visTestDll();
 ~visTestDll();
};

상기한 header파일의 선행연산자 부분은 그대로 사용하면 된다. 다만 나중에 DLL생성 후, Dll 프로젝트 부분의 소스를 제거하고 사용할 때에는 첫줄의 #define DLLEXPORT 만 제거한 후 사용한다.


// Dll 프로젝트 내의 실행소스 코드
#include "TestDll.h"

visTestDll::visTestDll() {}

visTestDll::visTestDll(int a, float b)
{
 printf("%4d,  %8.4f\n", a, b);
}
visTestDll::~visTestDll()
{
 printf("Destructing...\n");
}

특별한 연산은 하지 않으며 객체 생성 후 인자를 화면에 출력하는 작업을 한다.




Run 프로젝트 내에 존재하는 실행(호출) 파일은 다음과 같다.

// Run 프로젝트 내의 Dll 호출(실행) 파일
#include "../TestDll/TestDll.h"

int main()
{
 visTestDll a(10, 20.0f);
 return 0;
}

2014년 5월 12일 월요일

FFT (Fast Fourier Transform)

작성 중...

fft를 기저함수의 입장에서 살펴 본다.


어떤 함수 $f$가 두 벡터의 선형 결합으로 표시된다고 하자.

$f=c_1v_1+c_2v_2$

<그림 1>

예를 들면 <그림 1>에서

$f= \begin{bmatrix}
2 \\
3
\end{bmatrix}
=2 \begin{bmatrix}1 \\ 0 \end{bmatrix}+3\begin{bmatrix}0 \\ 1 \end{bmatrix}
=2v_1+3v_2$

이다. 여기서 $v_1$과 $v_2$는 상호 수직이고 크기가 1인 어떤 벡터이다.  함수 $f$와 이 벡터의 내적을 취하면

$<f,v_1>=(c_1v_1+c_2v_2)\cdot v_1=c_1<v_1,v_1>+c_2<v_2,v_1>=c_1$
$<f,v_2>=(c_1v_1+c_2v_2)\cdot v_2=c_1<v_1,v_2>+c_2<v_2,v_2>=c_2$

가 된다. 확인해보면

$<f,v_1>=[2, 3][1, 0]^T=2$
$<f,v_2>=[2, 3][0, 1]^T=3$

이다. 여기서 $v_1$과 $v_2$를 정규직교벡터(orthonormal vector) 또는 정규직교기라고 한다.

연속 함수 $f(t)$를 일정한 간격으로 샘플링을 해서 얻은 데이터의 벡터를 $f=[c_1,c_2,...,c_N]^T$라 하자.  이 벡터는 샘플링된 데이터의 형태로 함수를 표현한다.
만일 샘플 수를 무한히 크게하면 이 벡터는 함수 $f(t)$가 되고 이 추상적인 공간을 함수공간이라고 한다.

이때 함수 벡터를 $N$차원의 공간에서 나타낸다면 하나의 점이 된다.  그리고, 이 고차 공간에서 각 축의 방향을 $v_i$벡터로 표현한다고 하자.

<그림 2>

<그림 2>의 샘플된 함수 값을 정규직교기로 표현해 보자. 함수의 샘플 값이 모두 $N$개라면 정규직교벡터를

$v_1=\begin{bmatrix}1\\0\\0\\ \vdots \\0\\0 \end{bmatrix}$, $v_2=\begin{bmatrix}0\\1\\0\\ \vdots \\0\\0 \end{bmatrix}$, $\cdots$,  $v_N=\begin{bmatrix}0\\0\\0\\ \vdots \\0\\1 \end{bmatrix}$

와 같이 정의한다면

$f=c_1v_1+c_2v_2+\cdots+c_Nv_N$

가 된다. 즉, 정규직교기의 선형 결합으로 샘플된 어떤 함수 값의 표현이 가능하다. 
여기서 $c_i$ 값은 함수 값과 기저벡터 $v_i$의 내적으로 얻을 수 있다.

$c_i=<f,v_i>$

이다. 


$f=[f_1,f_2,\cdots,f_N]^T$라고 하고
$f$의 크기(norm)를 생각해보면

$\lVert f \rVert=\sqrt{{f_1}^2+{f_2}^2+\cdots+{f_N}^2}$

이다. 그런데 sample의 갯수 $N$가 많아지면 $\lVert f \rVert$가 커지므로 갯수에 대해 정규화를 하면

$\lVert f \rVert=\sqrt{{{1}\over{N}}({f_1}^2+{f_2}^2+\cdots+{f_n}^2)}=\sqrt{{1 \over N} \sum_{i} {f_i}^2 }$

이다.   

이를 연속함수로 확장하면

$\lVert f \rVert=\sqrt{{1 \over b-a} \int_{a}^{b} {f(t)}^2 dt}$

이다.




또한 두 vector $f$와 $g$의 내적을 취하면

$<f,g>=f_1g_1+f_2g_2+\cdots+f_Ng_N=\sum_{i} f_ig_i$

이다. 차원 $N$에 좌우되지 않게 하면

$<f,g>={1 \over N} \sum_{i} f_ig_i$

이고, 연속 공간에서 표현하면

$<f,g>={1 \over b-a} \int_{i} f(t)g(t) dt$

이다.








이상에서 살펴본 벡터 공간의 정규직교기를 함수공간으로 도입해 보자.

크기가 1이고 서로 직교하는 함수의 집합(함수족이라 하자)이 있다고 가정하자.
그러면 어떤 함수 값은 함수족 요소의 합으로 표시 가능하다.

다시 말하면 임의의 함수는 미리 성질을 알고 있는 많은 함수 성분으로 분해할 수 있다는 것을 의미한다.

어떤 함수 집합 $\phi_k(t), k=1,2,\cdots$를 생각하자. 함수들의 내적이

$<\phi_{m}(t),\phi_{n}(t)>={1 \over b-a} \int_{a}^{b}\phi_{m}(t) \phi_{n}(t) dt =0, (m \neq n)$

$<\phi_{m}(t),\phi_{m}(t)>={1 \over b-a} \int_{a}^{b}\phi_{m}^2 (t)dt =1, (m = n)$

인 성질을 만족하면 정규직교함수라고 한다.
이를 이용하면 임의의 함수 $f(t)$는

$f(t)=c_0\phi_{0}(t)+c_1\phi_{1}(t)+\cdots=\sum_{k=0}^{\infty} c_k\phi_{k}(t)$

이다.  각 계수 값의 결정은

$<f(t),\phi_k (t)>=(c_0\phi_{0}(t)+c_1\phi_{1}(t)+\cdots)\cdot \phi_k (t)$
$=c_0<\phi_{0}(t),\phi_k (t)>+c_1<\phi_{1}(t),\phi_k (t)>+\cdots$
$=c_k<\phi_k,\phi_k>=c_k$

이다. 따라서,

$c_k=<f(t),\phi_k (t)>={1 \over b-a}\int_{a}^{b} f(t) \phi_k (t) dt$

이다.









(예) 함수계 $\{1, \sin t, \sin 2t, \cdots \}$가 $-\pi \sim \pi$ 구간에서 직교함수계인지 확인하시오.

$<1,\sin nt>={1 \over {2\pi}}\int_{-\pi}^{\pi} \sin nt dt =-{1 \over {2n\pi}}[\cos nt ]_{-\pi}^{\pi}=0$

$<\sin mt,\sin nt>={1 \over {2\pi}}\int_{-\pi}^{\pi} \sin mt \sin nt dt
=-{1 \over {2\pi}} \int_{-\pi}^{\pi} {1 \over 2} (\cos (m+n)t-\cos (m-n)t) dt$
$=-{1 \over {4\pi (m+n)}} [\sin (m+n)t ]_{-\pi}^{\pi}+{1 \over {4\pi (m-n)}}[\sin (m-n)t ]_{-\pi}^{\pi}=0$

$<\sin nt, \sin nt>={1 \over 2\pi} \int_{-\pi}^{\pi} \sin^2 nt dt
={1 \over 2\pi} \int_{-\pi}^{\pi} {1 \over 2}(1-\cos 2nt) dt$
$={1 \over 4\pi}[t]_{-\pi}^{\pi} -{1 \over {4\pi 2n}}[\sin 2nt]_{-\pi}^{\pi}={1 \over 2}, (n=1, 2, 3, \cdots)$


위 함수계는 직교는 맞는데 정규는 아니므로 (즉, 동일 함수의 내적이 ${1 \over 2}$이므로) 각 함수에 $\sqrt 2$를 곱해 준다.

따라서

$\{1, \sqrt 2 \sin t, \sqrt 2 \sin 2t, \cdots \}$

가 정규직교 함수계가 된다.



$\circ$ 예제에서 삼각함수의 반각의 공식이 사용되었다:

$\sin^2 {\alpha \over 2}={ {1-\cos \alpha} \over 2}$
$\cos^2 {\alpha \over 2}={ {1+\cos \alpha} \over 2}$








2014년 4월 26일 토요일

Collaborative filtering

협업 필터링이라고도 부른다.   행렬 분해(matrix decomposition)를 활용한 상품 추천 시스템(recommendation system)에 사용된다.  또는 아주 큰 데이터(big data)에 내재되어 있는 내부 성질을 파악하기 위한 마이닝(mining) 알고리즘으로도 사용될 수 있다.


웹 Market에서 상품을 팔면서 구매자의 만족도를 조사하였다.

6명의 구매자에 대해 5개의 상품을 0~5점으로 나누어 만족도가 높을수록 5점에 가까운 점수를
주게 하였더니 아래와 같은 행렬이 얻어졌다.

>>A=[2 3 5 0 0; 1 2 4 0 0; 4 5 4 0 0; 0 1 0 3 4; 1 0 0 4 5; 0 0 0 5 4];
>> A

A =
     2     3     5     0     0
     1     2     4     0     0
     4     5     4     0     0
     0     1     0     3     4
     1     0     0     4     5
     0     0     0     5     4

행렬에서 행(row)은 구매자이고 열(column)은 개별 상품에 해당한다.

행렬을 보고 대략 추정해보면 1~3번 상품에 대해 호의적인 사용자들과
4~6번의 상품에 호의적인 사용자들의 두 그룹으로 나누어진다는 것을 알 수 있다.


A행렬을 특이값 분해(SVD, singular value decomposition)해보면

>>[u,d,v]=svd(A)

u =
   -0.4719    0.3337   -0.4308    0.0716    0.1067   -0.6810
   -0.3382    0.2434   -0.5548    0.1188   -0.0594    0.7078
   -0.5811    0.3908    0.6720   -0.1899   -0.0353    0.1436
   -0.3004   -0.3804    0.0835    0.4957   -0.7101   -0.0901
   -0.3610   -0.5078    0.1044    0.3629    0.6803    0.0801
   -0.3234   -0.5235   -0.1927   -0.7532   -0.1299   -0.0100

d =
   10.6983         0         0         0         0
         0   10.1159         0         0         0
         0         0    2.4316         0         0
         0         0         0    1.1504         0
         0         0         0         0    0.9895
         0         0         0         0         0

v =
   -0.3709    0.1944    0.5659   -0.1171    0.7005
   -0.4952    0.3026    0.4284   -0.0013   -0.6925
   -0.5643    0.4157   -0.6929    0.0641    0.1564
   -0.3704   -0.5724   -0.1216   -0.7190   -0.0592
   -0.4020   -0.6084    0.0349    0.6821    0.0419

세개의 행렬 u, d, v가 얻어진다.

d행렬 내의 특이값을 보면 2개의 성분이 크고 나머지는 작다.
즉, A행렬의 내재된 성분이 2개가 중요하다는 의미이다.


2개의 성분과 그에 해당하는 u, v행렬의 값만을 이용하여 A행렬을 다시 재생해 보면

>> vt = v';
>> u(:,1:2)*d(1:2,1:2)*vt(1:2,:)

ans =
    2.5285    3.5220    4.2523   -0.0619   -0.0241
    1.8206    2.5374    3.0657   -0.0693   -0.0437
    3.0741    4.2755    5.1518    0.0396    0.0935
    0.4441    0.4272    0.2140    3.3931    3.6334
    0.4338    0.3579    0.0438    4.3709    4.6782
    0.2538    0.1107   -0.2491    4.3124    4.6127

이고 A행렬과 비교해 보면 값이 비슷하다(잘 재생된다).

내재된 성분의 의미를 파악해 보자.

>> u(:,1:2)*d(1:2,1:2)

ans =
   -5.0490    3.3752
   -3.6186    2.4625
   -6.2169    3.9535
   -3.2142   -3.8482
   -3.8621   -5.1373
   -3.4597   -5.2956

행렬의 행은 사용자를 표현하고, 열은 두개의 내재된 성질에 대한 것이다. 즉, 사용자는 2개의 그룹으로 나누어지며
1~3번 사용자는 첫번째 성질에 속하고, 4~6번 사용자는 두번째 성질에 속하는 정도가 크다 (행렬 요소값의 절대치 크기만 보자).

>> vt(1:2,:)

ans =
   -0.3709   -0.4952   -0.5643   -0.3704   -0.4020
    0.1944    0.3026    0.4157   -0.5724   -0.6084

5개의 상품(각 열)에 대해 첫번째 성질(사용자 그룹)은 1~3열의 상품에 대한 선호도가 높고, 2번째 성질은 4~5열의 상품에 대한 선호도가 높다.


이상과 같이 행렬을 분해해 주는 방법인 SVD를 이용하면 데이터에 내재되어 있는 의미 파악이 가능하다. 이를 이용하면 상품 추천시스템을 만들 수 있다.




이제 어떤 사람의 구매 만족도를 조사하였더니 아래와 같은 데이터가 주어졌다.

B=[3 ? 4 ? 2]

이 사용자는 상품 2, 4를 아직 구매하지 않았다.
이 사람에게 상품 2와 4 중에서 어떤 것을 추천할 것인지 계산해 보자.

먼저 평가가 있는 세개의 상품에 대해 평균을 구해 '?'위치에 대치하자.
(3+4+2)/3=3이므로 3을 대입한다.

>>B=[3 3 4 3 2];


이 사용자를 A행렬의 마지막 행에 추가하고 SVD를 다시 수행한다.

>> C=[A; B]

C =
     2     3     5     0     0
     1     2     4     0     0
     4     5     4     0     0
     0     1     0     3     4
     1     0     0     4     5
     0     0     0     5     4
     3     3     4     3     2

>> [u,d,v]=svd(C)

u =
   -0.4049    0.3207    0.4210   -0.1967   -0.0883    0.7109   -0.0642
   -0.2900    0.2341    0.5467   -0.2343    0.0295   -0.6759   -0.2227
   -0.4980    0.3749   -0.6820   -0.0475    0.1547   -0.0733   -0.3388
   -0.2424   -0.3885   -0.0945   -0.6518    0.4371    0.0039    0.4068
   -0.2938   -0.5175   -0.1111   -0.1982   -0.7383   -0.0344   -0.2190
   -0.2644   -0.5321    0.1912    0.4180    0.4667    0.1088   -0.4540
   -0.5376    0.0046    0.0290    0.5151   -0.1157   -0.1394    0.6418

d =
   12.6750         0         0         0         0
         0   10.1164         0         0         0
         0         0    2.4328         0         0
         0         0         0    1.4264         0
         0         0         0         0    1.0250
         0         0         0         0         0
         0         0         0         0         0

v =
   -0.3943    0.1850   -0.5604    0.3711   -0.5988
   -0.4844    0.2896   -0.4361   -0.2823    0.6416
   -0.5781    0.4011    0.6907   -0.0352   -0.1635
   -0.3816   -0.5814    0.1295    0.6218    0.3360
   -0.3606   -0.6188   -0.0456   -0.6282   -0.3004



이제 내재된 2개의 성질을 이용하여 원래 행렬을 재생해 보면

>> vt=v';
>> u(:,1:2)*d(1:2,1:2)*vt(1:2,:)

ans =
    2.6239    3.4256    4.2679    0.0722   -0.1568
    1.8875    2.4663    3.0746    0.0254   -0.1403
    3.1904    4.1556    5.1695    0.2037   -0.0706
    0.4845    0.3498    0.1994    3.4574    3.5400
    0.5003    0.2878    0.0530    4.4650    4.5828
    0.3258    0.0642   -0.2220    4.4083    4.5394
    2.6959    3.3143    3.9577    2.5738    2.4292


마지막 사용자의 2, 4번째 상품에 대한 평가치는 3.3143>2.5738이므로 2번째 상품을 추천한다.



References

[1] 한국정보처리학회, Tutorial(빅데이터 분석 및 소셜 컴퓨팅), 2014.



2014년 4월 17일 목요일

FastSLAM

EKF SLAM의 문제점
- 2차원 평면상에서 $K$개의 landmark 존재.  LM 파라미터: $(x_i, y_i)$
- robot pose: $(x, y,  \phi)$
- 합하면 $2K+3$개의 인자
- Kalman filter를 통해 이것들을 추정하면 mean값을 $2K+3$개를 유지
  Covariance matrix는 $(2K+3)^2$크기가 요구
- LM의 수가 늘어 감에 따라 유지해야 하는 파라메터의 수가 급격히 증가(계산량 증가)

FastSLAM에서의 개선
- Landmark는 로봇의 pose가 주어진다면 상호 독립이라 가정
- 각 landmark에 대해 $2\times2$ covariance matrix
  전체 인자의 수: $K(2+2\times2)+3$


Robot poses: $s^t=s_1, s_2, ...,s_t$
Robot actions: $u^t=u_1,u_2,...,u_t$
Observations: $z^t=z_1,z_2,...,z_t$
Landmarks: $\boldsymbol{\theta}=\theta_1,...,\theta_k$
Correspondence: $n^t=n_1,n_2,...,n_t$
- $n_t=k$는 $z_t$가 $\theta_k$의 관찰 값임을 의미
- landmark는 한번에 하나씩 관찰된다고 가정

그림에서 shade영역은 $t_1\sim$현재까지의 로봇의 경로이다.
만일 로봇의 실제 경로를 안다면(즉 shade영역) LM $\theta_1$과 $\theta_2$는 서로 독립이다.


SLAM 문제
- action model: $p(s_t|u^t,s^{t-1})$
- sensor model: $p(z_t|s_t,\boldsymbol{\theta},n_t)$

SLAM 문제는 $z^t, u^t, n^t$가 주어질 때 $\boldsymbol{\theta},s^t$를 추정하는 문제이다.  Bayes theory를 이용하면

$p(s^t,\boldsymbol{\theta}|z^t,u^t,n^t)=
{{p(\boldsymbol{\theta},s^t,z^t,u^t,n^t)} \over {p(z^t,u^t,n^t)}}={{p(\boldsymbol{\theta}|s^t,z^t,u^t,n^t)p(s^t,z^t,u^t,n^t)} \over {p(z^t,u^t,n^t)}}$
$=p(\boldsymbol{\theta}|s^t,z^t,u^t,n^t)p(s^t|z^t,u^t,n^t)$

landmark의 독립가정$^{주1}$에 따라
$p(s^t,\boldsymbol{\theta}|z^t,u^t,n^t)
 =p(s^t|z^t,u^t,n^t)\prod_k^{}p(\theta_k|s^t,z^t,u^t,n^t)$

- trajectory 추정 $p(s^t|z^t,u^t,n^t)$
- robot의 자세 추정은 particle filter를 이용하고, 각 particle에 대한 landmark위치와 분산의 갱신의 EKF를 사용
- particle당 $K$개의 Kalman filter가 있으므로 particle의 수가 $M$개라면 갱신과정의 시간 복잡도는 $O(MK)$이다.



(주1) 독립가정에 따라
$p(\boldsymbol{\theta}|s^t,z^t,u^t,n^t)=...$



References
[1] M. Montemerlo, FastSLAM: A Factored Solution to the Simultaneous Localization and Mapping Problem With Unknown Data Association, CMU-CS-03, Ph.D. thesis, 2003.
[2] Benjamin Kuipers, FastSlam, lecture notes, CS 344R/393R: Robotics.