C++에서 Boost ASIO를 사용하여 TCP 동기화(Blocked) 통신 프로그래밍

공대생의 팁 2019.07.21 19:58

 지난 포스팅에서 C++에서 제공하는 Boost 라이브러리의 통신 라이브러리인 ASIO를 사용하여 비동기 통신 프로그래밍을 하는 방법에 대해 소개를 하였던 적이 있었습니다.



C++에서 Boost ASIO를 사용하여 TCP 비동기(Unblocked) 통신 프로그래밍

https://elecs.tistory.com/314


 서버-클라이언트 통신 시스템을 구축하던 도중 Java에서 사용하던 객체 통신 프로그래밍 방식이 상당히 편했던 기억이 있어 이를 C++에서도 편하게 사용할 수 있는 방법을 찾았던 것이어서 이를 정리하였던 글이었는데 생각보다 많은 분들께서 도움을 받으셨다는 답변을 받았습니다.


 그래서 이번에는 ASIO 통신 프로그래밍에서 다룰 만한 내용으로 동기화(Synchronization, Blocked) 프로그래밍 방식에 대해 이야기 해보고자 합니다.





 위 그림은 ASIO 프로그래밍의 동기화 통신 방식의 흐름도를 나타낸 것입니다. 이전 포스팅에서 다루었던 비동기화 통신 방식과는 달리 동기화 통신은 상대로부터 response를 대기하는 과정이 추가됩니다.

 비동기 모드의 경우 Handler를 등록해두면 response의 수신 여부와 관계 없이 서버는 프로그램의 동작을 멈추지 않고 별개의 동작을 수행할 수 있습니다. 반면 동기화 통신의 경우 상대방의 response가 들어오고 나서 동작하는 방식이므로 서로가 통신이 확인이 되었는지의 여부를 확인할 수 있다는 장점이 있습니다.


 먼저 프로세스는 socket에 자신의 IP 정보를 기록한 후 이를 io_service(Boost 1.66 버전 이후는 io_context)를 통해 운영체제 커널에 정보를 등록합니다. 이후 운영체제가 다른 컴퓨터로부터 응답을 수신하게 되면 이를 프로세스의 socket에게 전달하고 프로세스는 전달 받은 정보를 가공하는 방식으로 통신이 이루어집니다.


자세한 내용은 아래의 소스코드를 통해 알아보도록 하겠습니다.



 프로그램을 실행하기에 앞서 자신의 컴퓨터에 Boost 라이브러리를 설치합니다. Ubuntu를 기준으로 다음과 같이 실행합니다.


$ sudo apt install libboost-all-dev



 이제 어러분의 컴퓨터에는 Boost 라이브러리가 설치되었습니다. 다음으로 아래의 소스코드를 작성해줍니다.


sync_server.cc


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include<cstdlib>
#include<iostream>
#include<boost/asio.hpp>
 
using namespace std;
using boost::asio::ip::tcp;
 
class session
{
public:
    session(tcp::socket& sock)
    //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
    //session(boost::asio::io_context& io_service)
    : socket_(sock){
        start();
    }
 
    void start(){
        try{
            while(1){
                boost::system::error_code error;
                size_t length = socket_.read_some(boost::asio::buffer(data_), error);
                if(error == boost::asio::error::eof){
                    //클라이언트로 부터 정보를 모두 받았으므로 종료한다.
                    break;
                }else if(error){
                    throw boost::system::system_error(error);
                }
                cout << "Message from client: " << data_ << endl;
                boost::asio::write(socket_, boost::asio::buffer(data_, length));
            }
        }catch(exception& e){
            cerr << "Exception in server: " << e.what() << endl;
        }
    }
 
    tcp::socket& socket(){return socket_;}
 
private:
    tcp::socket& socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};
 
class server
{
public:
    server(boost::asio::io_service& io_service, short port)
    //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
    //server(boost::asio::io_context& io_service, short port)
    : io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
    {
        while(1){
            //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
            //new session(acceptor_.accept());
 
            //sever의 소켓 생성
            tcp::socket sock(io_service);
            //client로부터 접속 대기
            acceptor_.accept(sock);
            new session(sock);
        }
    }
private:
    boost::asio::io_service& io_service_;
    //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
    //boost::asio::io_context &io_service_;
    tcp::acceptor acceptor_;
};
 
int main(int argc, char* argv[]){
    try{
        if(argc != 2){
            cerr << "Usage: server <port>" << endl;
            return 1;
        }
        boost::asio::io_service io_service;
        //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
        //boost::asio::io_context io_service;
        server s(io_service, atoi(argv[1]));
 
    }catch(exception& e){
        cerr << "Exception: " << e.what() << endl;
    }
 
    return 0;
}
cs



sync_client.cc


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<cstdlib>
#include<iostream>
#include<boost/asio.hpp>
 
using boost::asio::ip::tcp;
using namespace std;
 
class client
{
public:
    client(boost::asio::io_service& io_service,
    //client(boost::asio::io_context& io_service,
    const string& host, const string& port) : socket_(io_service)
    {
        tcp::resolver resolver(io_service);
        //서버에 접속을 시도한다.
        boost::asio::connect(socket_, resolver.resolve({host, port}));
 
        string msg = "Hello, world!";
        size_t msg_length = msg.length();
 
        //서버로 데이터를 전송
        boost::asio::write(socket_, boost::asio::buffer(msg, msg_length));
 
        char reply[max_length];
        //서버로부터 데이터를 수신
        size_t reply_length = boost::asio::read(socket_, boost::asio::buffer(reply, msg_length));
        cout << "Reply is: " << reply << endl;
        
    }
 
private:
    tcp::socket socket_;
    enum { max_length = 1024 };
};
 
int main(int argc, char* argv[]){
    try{
        if(argc != 3){
            cerr << "Usage: client <host> <port>" << endl;
            return 1;
        }
 
        //boost 1.66이후 (Ubuntu 18.10 이후) 버전의 경우 io_context를 사용
        //boost::asio::io_context &io_service;
        boost::asio::io_service io_service;
        client c(io_service, argv[1], argv[2]);
 
    }catch(exception& e){
        cerr<<"Exception: " << e.what() << endl;
    }
 
    return 0;
}
cs



CMakeLists.txt


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
cmake_minimum_required(VERSION 3.0)
add_compile_options(-std=c++11)
 
project(asio_sync)
find_package(Boost REQUIRED system)
find_package(Threads)
 
include_directories(${Boost_INCLUDE_DIR})
 
add_executable(client
    sync_client.cc
)
 
add_executable(server
    sync_server.cc
)
 
target_link_libraries(client
    ${Boost_LIBRARIES}
    ${CMAKE_THREAD_LIBS_INIT}
)
 
target_link_libraries(server
    ${Boost_LIBRARIES}
)
cs



Linux 환경에서 다음과 같이 프로그램을 컴파일합니다.


$ mkdir build

$ cd build

$ cmake ..

$ make


 이제 우리가 만든 프로그램을 실행하여봅니다.



Server

1
2
$ ./server 2222
Message from client: Hello, world!
cs



Client


1
2
$./client 127.0.0.1 2222
Reply is: Hello, world!
cs



 축하합니다! 이제 여러분들도 Boost 라이브러리의 ASIO를 사용하여 동기화 통신 프로그래밍을 만들 수 있게 되었습니다!

무더운 여름날 김유정역 강촌레일파크 [2019.07.17]


 평소에 레일바이크를 타보고 싶었던 적이 있었는데 마침 친구와 단둘이 여행을 할 수 있는 기회가 생겨 친구와 함께 레일바이크에 도전해 보게 되었습니다. 마침 춘천 인근에 있는 김유정역에 레일바이크가 있다는 이야기를 듣고 찾아가 보았습니다.




레일바이크의 시작점에서..



자전거 타듯이 페달만 열심히 저어주면 됩니다.



레일바이크 옆으로 펼쳐지는 풍경이 정말 대단합니다.



레일바이크 종착지에는 이렇게 쉼터가 마련되어 있습니다.

여기서 바라보는 풍경도 상당히 좋더군요.



종착지에서 강촌역까지는 특수열차를 타고 이동합니다.



열차에 올라서 바라보는 풍경도 꽤 장관입니다.



무궁화호를 타고서는 보기 힘든 광경들이 이렇게 지붕 없는 객차에서는 새로운 풍경으로 비쳐집니다.



어느덧 강촌역 인근에 도착



바닥을 보니 생각보다 높은 위치더군요



오랜만에 본 옛 강촌역의 모습

비록 열차는 정차하지 않지만 그 당시의 모습만은 고이 간직하고 있군요.



또오리 강촌!


바다가 보이는 간이역 월내역에서 기차가 서던 마지막날 [2019.07.14]


 지난 달에 동해선 덕하역을 다녀간지 한 달만에 동해선 부산 구간은 또 한번의 격변기를 맞이하게 되었습니다. 오늘로써 일광역부터 태화강역까지 기존의 철길에서 새로운 철길로 이사를 가게 되면서 이제는 지금까지 기차가 지나다니던 그 모습들은 역사속으로 사라졌기 때문이지요.


 오늘은 그러한 역사속 모습을 마지막까지 간직하고 있던 월내역 인근을 돌아다녀 보았습니다. 지금의 월내역은 기존역 역을 철거하고 임시로 세워져 있지만 여전히 무궁화호가 정차하던 역이었는데 오늘을 끝으로 더이상 무궁화호는 정차하지 않게 됩니다. 다만 앞으로 이설될 새로운 월내역은 고가역이 되어 바다가 훨씬 더 잘 보일 것으로 보입니다!



지난달에 방문하였던 덕하역 인근 구간을 지날 때 였는데

놀랍게도 이번에는 새로 이설한 고가 구간을 통과하는 겁니다!

아래의 이설 전 고가는 벌써부터 철거에 들어가 있더군요.


혹시 이설 바로 전날 이 곳의 모습이 궁금하시다면 아래의 포스팅을 확인해주세요!


철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16]

https://elecs.tistory.com/327




5개월만에 다시 월내역에 방문하는군요. 승강장에는 벌써 잡초가 무성합니다.



승강장 너머 고가철로 끝에는 새로운 월내역이 건설중입니다.



아직 광역전철이 개통하기까지 1년 넘게 남았는데 벌써 폐쇄된다니



새로운 월내역과 기존의 철길 모습입니다.

역 내에는 굴삭기가 개통 준비를 서두르고 있습니다.



남창역 방향을 향하여 찍은 모습입니다. 아마 내일이면 더이상 열차는 다니지 않습니다.



고가와 건널목.. 공존할 수 없는 관계일까요?



저 멀리 월내역의 임시승강장이 보입니다.



기존 철교와 새로 지어지고 있는 철교 사이의 자전거도로입니다.

한적하게 낚시를 하시는 분이 보입니다.



옛 철교 뒤로 내일부터 새로 개통될 철교가 보입니다.

이런 구도 쉽지 않은데!



넓디넓은 4차선 도로에 건널목 하나가 떡하니 서 있습니다.



원래 여기는 2차선 작은 도로였는데 인근에 아파트가 건설되면서 4차선으로 확장되었습니다.



아마도 이 철길이 이설될 예정이라서 불편해도 미리 길을 확장해둔 듯 합니다.



그 덕에 기존의 관리원님들이 계시던 건물을 허러내고 저렇게 컨테이너로 건물이 대체된 상황입니다.



아마 이보다 더 큰 길에 건널목이 있던게 9년전 경춘선 이설 직전 화랑대역 인근 건널목이었을겁니다.

그땐 아마 6차선이었을겁니다.



어느덧 건널목은 우렁차게 울리기 시작하고



도로위를 부지런히 다니던 차량들이 잠시 정차합니다.



장안2건널목의 마지막날에도 이렇게 기차는 순식간에 지나갑니다.



이제 관리원님들께서도 내일부터는 이 곳에서 더이상 볼 수 없게 됩니다.



다시 월내역을 돌아옵니다.

아까 고가 위에 보았던 굴삭기가 여전히 분주히 작업을 진행하고 있습니다.



내일부터는 이 출입구도 폐쇄되겠지요



앞으로 이 곳에 오기 위해서는 좌천역에서 운행하는 대체 버스를 타고 와야 할 듯 합니다.



마지막날인 오늘도 승객들은 이 곳에서 열차를 기다립니다.



지금은 사라졌지만 광역전철이 개통하면 서생역에도 열차가 정차하게 됩니다.



어느덧 열차는 월내역으로 들어옵니다.



이 역의 마지막을 아는지 탑승객들이 기차를 바라보며 셀카를 찍습니다.



이제 열차에 탑승합니다.



방금전에 들렀던 곳을 이렇게 사진으로 님기기는 처음입니다.



방금 뵙고 갔던 관리원님도 마지막날까지 열심히 일을 하고 계시는군요.



덕하역 인근에 이설된 고가 인근의 모습입니다.

저 곳에서 이 열차가 달리는 임시철교를 만들고 있던게 떠오르는군요.


과연 다음 여행지는 어디가 될까요?




리눅스(우분투)에서 USB가 동작하지 않을 때 수동으로 연결하기(Failed to open the USB device!)

공대생의 팁 2019.07.05 14:45


 PrimeSense사에서 제작한 RD 1.09 RGB-D 카메라를 USB 3.0에 꽃아서 openni2 환경에서 실행을 해보려 하던 도중 다음과 같은 문제가 발생하였습니다.


No matching device found.... waiting for devices. Reason: openni2_wrapper::OpenNI2Device::OpenNI2Device(const string&) @ /tmp/buildd/ros-indigo-openni2-camera-0.2.2-0trusty-20141015-0837/src/openni2_device.cpp @ 74 : Initialize failed


    Could not open "1d27/0609@1/12": Failed to open the USB device!


보아하니 RD 1.09 버전에서는 USB 2.0 버전만 지원이 되서 발생하는 문제로 추측됩니다. 즉, 디바이스 노드를 생성하지 못하는 상황으로 추측할 수 있습니다. 이 경우 USB 기기를 수동으로 설정하기 위해서는 다음과 같이 진행해줍니다.


 1. 먼저 현재 리눅스(우분투)에 연결된 USB 드라이버의 리스트를 출력합니다.


$ lsusb


 위의 명령어를 입력하시면 다음과 같이 현재 컴퓨터에 연결된 USB 기기들의 리스트가 나타납니다.



 위 목록을 보았을 때 자신의 기기가 어떤 것인지를 파악합니다. 저의 경우 1d27:0609로 써있는 부분으로 추정됩니다.


 2. udev를 사용하여 USB 드라이버를 수동으로 연결하는 규칙을 만들어줍니다. 여기서 .rules의 이름은 자신이 파악하기 쉬운 이름으로 붙여줍니다. (ex: 40-libopenni2-0.rules)


$ sudo vi /etc/udev/rule.d/my_rule.rules


3. 다음과 같이 입력해 주시고 ':wq'를 입력하여 저장해줍니다. ATTR의 'idProduct'와 'idVendor'는 위에서 lsusb를 입력하였을 때 나왔던 ID를 각각 입력해주시고 GROUP의 경우 자신에 맞는 그룹을 설정해줍니다. 저의 경우 카메라를 사용하므로 'video'로 설정하였습니다.


SUBSYSTEM=="usb", ATTR{idProduct}=="0609", ATTR{idVendor}=="1d27", MODE:="0666", OWNER:="root", GROUP:="video"


4. 여기까지 진행하신 후 다시 기기를 사용해보신다면 정상적으로 연결되는 것을 확인하실 수 있습니다.


 혹시 udev에 대해 자세히 알고 싶으신 분은 아래의 블로그 글을 읽어보시기를 추천드립니다!

https://mokga.tistory.com/54

C++에서 Graphviz로 그래프 이미지 그리기

공대생의 팁 2019.07.04 01:04


 자료구조를 공부하거나 특정한 환경을 그림으로 표현하고자 하는 경우가 있습니다. 특히 위상수학 같이 이산수학이 사용되는 분야에서는 각 객체들의 상호관계를 나타내야 하는 것이 중요하지요. 이러한 특성을 이미지로 나타낸 것을 흔히 그래프(Graph)라고 부릅니다.



 위의 그림은 같은 Depth를 유지하는 것을 목적으로 설계된 B+ 트리를 나타냅니다. 각 노드(혹은 Vertex)가 화살표(혹은 Edge)로 연결되어 있습니다. 특정한 프로그램의 알고리즘을 위와 같이 그림으로 표현한 것을 그래프라고 합니다.


 그렇다면 과연 우리들이 직접 설계한 프로그램을 바로 그림으로 나타낼 수 있는 방법이 있을까요? C++의 Boost library에서는 그래프를 생성할 수 있는 Graphviz를 지원합니다. 이산수학의 그래프 이론을 잘 알고 계시다면 Graphviz를 사용 하는 것이 상당히 쉬워질 것입니다.


 Graphviz를 사용하기에 앞서서 간단한 그래프 이론에 대해 설명을 드리겠습니다. 예를들어 다음과 같은 그래프가 있다고 가정합니다.




 위 그래프는 Graphviz로 생성한 4개의 Vertex와 4개의 Edge를 가지고 있는 그래프입니다. 한 눈으로 봐도 각 vertex인 A, B, C와 D가 각각 edge로 어떻게 연결되었는지 한 번에 알 수 있습니다. 이를 인접 행렬(Adjacency matrix)로 나타내면 다음과 같습니다.



 각 행과 열의 첫 번째 부터 A, B, C, D로 보았을 때 나타낸 인접 행렬의 모습입니다. 첫째 열의 경우 [0 1 0 1] 로 나타내어졌는데 각각 A는 두 번째인 B와 4 번째인 D와 연결된 부분을 1로 나타낸 것입니다. 나머지 열의 경우는 직접 위의 그림과 비교해 보신다면 쉽게 아실 수 있으실 겁니다!


 지금까지 우리는 무방향 그래프(Undirectional graph)를 설명하였습니다. 다음으로는 Edge에 방향성이 포함되어 있는 방향 그래프(Directional graph)를 보도록 하겠습니다.



 위에서 보았던 그래프에 화살표로 방향이 추가된 그래프입니다. 이 그래프 또한 인접 행렬로 다음과 같이 나타낼 수 있습니다.



 위에서 보았던 인접 행렬과 다른 점은 각 열은 출발 vertex, 각 행은 도착 vertex를 나타낸 것입니다. 즉 A의 경우 B와 D의 방향으로 향하고 있기 때문에 첫 번째 열의 경우 [0 1 0 1] 순서로 나타나는 것입니다. 반면, C의 경우 무방향 그래프의 경우 A와 같은 [0 1 0 1]이었으나 B로는 연결 방향이 존재하지 않기 때문에 [0 0 0 1]로 나타내는 것입니다. 또한 방향 그래프는 인접 리스트(Adjacency list)로 아래와 같이 나타낼 수 있습니다.



 위에서 보았던 방향 그래프를 생각하시면 이해하기 쉬우실 겁니다. 각각의 Vertex인 A와 B, C, D를 생성한 후 각 Vertex가 향하는 방향의 Vertex를 연결 리스트(Linked list)로 이어주는 것이지요. 연결되는 순서는 상관 없습니다. 즉 [A → B → C] 로 표기하거나 [A → C → B]로 표기하여도 모두 같은 값을 나타낸다고 보시면 되겠습니다. 여기서 D로부터 시작하는 방향은 존재하지 않으므로 D는 그 어떤 Vertex와 연결되있지 않음을 위에서 보실 수 있습니다.


 그러면 이번에는 위에서 설명한 그래프들을 직접 소스코드로 구현해봅시다. 먼저 Boost library를 컴퓨터에 설치해 줍니다.


$ sudo apt install libboost-all-deb graphviz


 다음으로 아래와 같은 소스코드를 입력합니다.


graphviz.cc


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <cstdio>
 
using namespace std;
 
struct VertexP { string tag; };
struct EdgeP { string symbol; };
struct GraphP { string orientation; };
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexP, EdgeP, GraphP, boost::listS> ListGraph;
 
int main()
{
    ListGraph g(GraphP{"Example"});
    boost::dynamic_properties dp;
    dp.property("node_id", get(&VertexP::tag,g));
 
    ofstream dot_file("graph.dot");
    string dcmd = "dot -Tpng graph.dot -o graph.png";
 
    // Create the vertexes
    ListGraph::vertex_descriptor a = add_vertex(VertexP{"A"},g);
    ListGraph::vertex_descriptor b = add_vertex(VertexP{"B"},g);
    ListGraph::vertex_descriptor c = add_vertex(VertexP{"C"},g);
    ListGraph::vertex_descriptor d = add_vertex(VertexP{"D"},g);
 
    // Create the edges
    // A → B
    add_edge(a, b, g);
    // B → D
    add_edge(a, d, g);
    // B → C
    add_edge(b, c, g);
    // C → D
    add_edge(c, d, g);
 
    // Print graph
    write_graphviz_dp(dot_file, g, dp);
 
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(dcmd.c_str(), "r"), pclose);
    if (!pipe) {
        throw runtime_error("popen() failed!");
    }
 
    return 0;
}
 
cs



 여기서 소스코드의 중요한 부분을 하나씩 설명해 드리겠습니다.



typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexP, EdgeP, GraphP, boost::listS> ListGraph;


 위에서 설명드렸던 인접 리스트(Adjacency list)를 만들수 있도록 해주는 Boost library입니다. Graphviz로 그래프를 만들어주기 위해 사용됩니다.


14
15
16
    ListGraph g(GraphP{"Example"});
    boost::dynamic_properties dp;
    dp.property("node_id", get(&VertexP::tag,g));
cs


하나의 인접 리스트 변수 g를 선언합니다. 인접 리스트의 이름은 "Example" 입니다. dynamic_properties는 Graphviz에서 Adjacency list의 내용을 설정해 주기 위해 사용되는 변수입니다. 각 vertex의 이름은 VertexP 구조에 저장되므로 16번 줄을 작성하여 Adjacency list 변수 g에 선언해줍니다.


18
19
    ofstream dot_file("graph.dot");
    string dcmd = "dot -Tpng graph.dot -o graph.png";
cs


 Graphviz를 생성해 주기 위해 파일을 생성합니다. 파일의 이름은 "graph.dot"입니다. Graphviz를 이미지로 생성시켜주는 과정은 Terminal의 명령어로 이루어지므로 명령어를 설정해 줍니다. 명령어는 다음과 같습니다.


$ dot -Tpng graph.dot -o graph.png


 위 명령어는 생성되는 이미지의 확장명은 png로 설정하며 파일명은 graph.png로 저장하겠다는 의미입니다.


21
22
23
24
25
    // Create the vertexes
    ListGraph::vertex_descriptor a = add_vertex(VertexP{"A"},g);
    ListGraph::vertex_descriptor b = add_vertex(VertexP{"B"},g);
    ListGraph::vertex_descriptor c = add_vertex(VertexP{"C"},g);
    ListGraph::vertex_descriptor d = add_vertex(VertexP{"D"},g);
cs


 Vertex들을 생성해줍니다. vertex_descriptor에 해당 vertex를 저장해 줍니다.


27
28
29
30
31
32
33
34
35
// Create the edges
// A → B
add_edge(a, b, g);
// B → D
add_edge(a, d, g);
// B → C
add_edge(b, c, g);
// C → D
add_edge(c, d, g);
cs


 바로 이 부분이 제가 위에서 말씀드렸던 인접 리스트의 방식을 나타낸 것입니다. 각 vertex와 연결하고자 하는 vertex를 위의 순서대로 입력하시면 우리가 원하는 방식대로 edge가 연결됩니다.


37
38
    // Print graph
    write_graphviz_dp(dot_file, g, dp);
cs


 지금까지 우리들이 만들었던 그래프를 Graphviz로 만듭니다. 이를 실행하면 dot 파일이 생성됩니다.


1
2
3
4
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(dcmd.c_str(), "r"), pclose);
    if (!pipe) {
        throw runtime_error("popen() failed!");
    }
cs


 dot 파일로 생성된 Graphviz를 이미지로 만들기 위해 실행되는 부분입니다. 이 과정은 Graphviz 프로그램에서 직접 실행되기 때문에 위와 같이 설정해 주시면 직접 사용자가 dot 명령어를 입력하지 않고도 이미지가 생성됩니다.


여기까지 완성되었다면 이제 컴파일을 해줍니다. 다음과 같은 파일을 만들어줍니다.


Makefile

1
2
3
4
5
CC = g++
CFLAGS = -g -Wall -std=c++11
 
output:graphviz.cc
    $(CC) $(CFLAGS) -o output graphviz.cc
cs


make로 컴파일을 해줍니다.


$ make


이제 컴파일이 실행된 폴더를 확인해보시면 'output' 이라는 이름의 실행파일이 생성됩니다. 이제 실행해봅니다.


$ ./output


 그러면 다음과 같은 이미지 파일이 생성되 있는 것을 확인하실 수 있습니다.



 다음으로 이번에는 방향 그래프를 만들어 보겠습니다. 위 코드에서 다음 부분만 바꿔주시면 되겠습니다.




typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexP, EdgeP, GraphP, boost::listS> ListGraph;


 그러면 다음과 같은 방향 그래프가 생성됩니다.



 이번에는 생성된 그래프를 회전 시켜보겠습니다. 다음과 같은 코드를 추가시켜주세요.


14
15
16
17
    ListGraph g(GraphP{"Example"});
    boost::dynamic_properties dp;
    dp.property("node_id", get(&VertexP::tag,g));
    dp.property("rankdir", boost::make_constant_property<ListGraph*>(string("LR")));
cs


그러면 다음과 같이 그래프가 90도 회전합니다.



만약 위의 vertex의 순서를 반대로 하고자 하시는 분이라면 소스코드를 다음과 같이 고쳐주세요.


14
15
16
17
    ListGraph g(GraphP{"Example"});
    boost::dynamic_properties dp;
    dp.property("node_id", get(&VertexP::tag,g));
    dp.property("rankdir", boost::make_constant_property<ListGraph*>(string("RL")));
cs


 그러면 vertex의 순서가 좌우 반전으로 다음과 같이 출력됩니다.




철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16]


 2019년도 벌써 절반이 지나가고 또다시 무더운 여름이 다가오고 있습니다. 올해는 부디 좋은 날씨에서 여행을 많이 돌아다니고 싶네요.

 이번 포스팅에서는 지난번에 이어서 덕하역 인근 철길 이설 전날의 모습들을 사진으로 남겨보았습니다.


철길도 이사를 간다? 덕하역 이설 전날 풍경(2) [2019.06,16]

https://elecs.tistory.com/326





건널목 너머에는 셀프빨래방과 카페가 있습니다.

카페의 이름이 '기차길옆에서'라고 되어있군요.



덕하역 방면의 모습입니다.

여기서 좀만 더 나아가면 덕하역이 나타납니다.



남창역 방향을 바라본 모습입니다. 저 멀리 끊어진 교각이 보입니다.



건널목 바로 인근에는 아파트가 들어서 있습니다.

소음이 상당했을 것으로 보입니다.



새로 지어지는 덕하역 방향에서 바라본 모습입니다.

내일부터 모든 열차는 이 곳으로 운행됩니다.



내일부터 운행될 교각임에도 옛 철길과 교차하는 이 부분만 다리가 없습니다.



가까이 와서 보아도 절묘하게 이 부분만 다리로 연결되어 있지 않습니다.



내일부터 연결할 예정인지 인부들이 상당히 바쁘게 개통을 준비하고 있습니다.



보통 이설될 때 기존선에서 다소 떨어진 위치에서 새로운 철길을 만드는데

이 구간은 희안하게 기존부터 사용되어온 철길과 가깝게 교차하는 구간입니다.



그와중에 열차는 그 사이를 통과합니다.



자세히 보니 기존 철교와 높이가 너무 가까워서 미리 만들어서 연결할 수는 없는 상황인것 같습니다.



연결될 부분의 레일이 삐죽 나와있습니다.



교차하는 다리 사이에는 임시로 기둥이 올라와 있습니다.

이 기둥은 지난번에 영주 이설준비중인 구간에서 본 적이 있습니다.



아직 만들어지지 않은 구간을 뺀다면 다리는 거의 다 만들어져 있습니다.



한편 그 아래에서는 인부들의 작업이 한창입니다.



자세히 보니 임시로 올린 기둥에 임시로 철길을 이으려는 모양입니다.



그 때 덕하역 방향에서 열차가 들어옵니다.



이제 이 임시철교가 올라가게 된다면.

이제 이 광경은 내일부터 볼 수 없게 됩니다.



과연 새로 이설될 부분으로 다니는 열차의 모습은 어떠한 모습일까요?



임시철교는 생각보다 꽤 정교하게 만들어져 있습니다.

그래도 이 위로 열차가 다닐것이라는게 조금은 신기해 보입니다.



아마도 오늘 밤 열차가 운행되지 않는 시간에 곧바로 이 다리를 올려서 설치할 모양입니다.



이제 이 건널목도 내일부터는 울리지 않겠지요.



건널목 인근 벤치에 앉아 쉴 수 있는 그늘이 있습니다.

잠시 쉬고 계신 할아버지께서 건널목을 바라보고 계십니다.



이 건널목은 이설 이후 2차선의 도로로 확장될 예정입니다.



이제 이 길은 앞으로 어떤 모습으로 바뀌게 될까요?



꼬불꼬불 철길을 달리던 열차도 이제 내일부터는 쭉 뻗은 교량 위로 달려나갈 것입니다.



철길 너머에는 새로운 덕하역이 건설되고 있습니다.



현재의 덕하역 앞길은 흔한 시골에서 볼 수 있는 풍경입니다.



잠시 읍내를 돌아다니고 오는 사이 안내문이 새로 만들어졌습니다.



아담한 느낌의 이 역사도 이제는 시한부 인생이 되었습니다.



그래도 새로운 역사가 건설이 완료될 때 까지는 계속 사용될 것으로 보입니다.



지금 당장은 임시승강장을 가는 길이 보이지는 않습니다만

내일이면 완성되어 있겠지요?



그 사이에 동대구행 열차가 들어옵니다.



내일부터는 이 모습도 볼 수 없게 됩니다.



열차 마주편에서 부전방면 열차가 들어옵니다.

이제 열차를 타고 동대구역으로 향합니다.



 세월이 지날수록 주변에는 항상 있을거라 생각해왔던 것들이 하나둘씩 추억속으로 사라집니다. 앞으로도 이렇게 추억들을 사진으로 하나둘 담아두는 여행을 계속 이어가고자 합니다!



이 장소를 Daum지도에서 확인해보세요.
울산 울주군 청량읍 상남리 522-7 | 덕하역
도움말 Daum 지도

철길도 이사를 간다? 덕하역 이설 전날 풍경(1) [2019.06.16]


 마침 부산 벡스코에서 철도 박람회를 다녀오는 김에 현재 이설중인 동해선 일광~태화강 구간을 다녀와보고자 했었는데 마침 제가 방문한 날 남창~덕하 구간 선로가 이설되기 직전의 날이었습니다. 여러모로 절묘한 타이밍이 되어 마지막 순간을 사진으로 담을 수 있어 다행이라 생각됩니다.

 이번 포스팅에서는 이설 전날 덕하역 소재지의 읍내를 둘러보며 이설될 구간을 돌아다녀 보았습니다.





남창역에서 덕하역으로 넘어가던 도중 건너편에 있는 신선로의 모습입니다.

내일부터는 이 고가선로로 열차가 통행하게 됩니다.



오늘로서 승강장의 역할이 마지막인 덕하역 플랫폼.

달대형 타는곳이 철도청 시절의 검은색인 것으로 보아 바뀐것이 거의 없는 듯 보입니다.



그래도 지주식 역명판은 코레일 양식을 쓰는군요.



이 사진이 내일(2019년 6월 17일)부터는 역사속에만 존재하게 된다는 것이 믿어지지 않습니다.



이렇게 승강장에 서있는 무궁화호의 모습도 이제는 볼 수 없습니다.



열차가 떠나간 후 덕하역의 모습입니다.

고객대기실도 굉장히 오래된 듯 보입니다.



열차는 뒷꽁무니만 빼꼼 보이는 채로 점점 멀어져갑니다.



오늘 처음으로 덕하역에 방문하였는데 다음날이 이설일이라니

정말이지 오늘은 운이 억세게 좋은 것 같습니다.



흔한 간이역의 풍경입니다.

요즘 지어지는 역들은 으리으리 해져서 이런 분위기는 보기 어렵습니다.



오시는 승차권도 미리 사시면 편리합니다.

날짜와 시간을 꼭 확인하십시오.



역 안에는 온갖 공사가 한창입니다.

선로 이설로 인한 승강장 이전 안내판을 붙이는 작업입니다.



마치 임시 승강장을 마련한 좌천역보다 더 멀어보입니다.



덕하역의 모습입니다. 설마 이것도 우리의 기억에서 사라질까요?



역 바깥의 풍경은 생각보다 한산합니다.



이설된다면 이 안내판도 사라질 듯 보입니다.



비록 모습은 비슷하지만 조그마한 간이역도 나름 제게는 볼거리 중 하나입니다.



역에서 읍내 방향으로 걸어가봅니다.



청량읍 주민자치센터의 모습입니다.

청량면에서 읍으로 승격한지 갓 1달이 되어서 '읍' 글자만 이질적으로 느껴집니다.



역앞 거리는 전형적인 면소재지 분위기의 자그마한 가게들이 뭉쳐 있습니다.



덕하 5일장이 열리는 장소입니다. 보아하니 이 곳에서 새로 이설될 덕하역까지 직선도로가 생깁니다.



위의 사진에서 버스정류장 위치에서 반대편을 바라보면 저 멀리 덕하역이 건설되는 모습이 살짝 보입니다.



새로 만들어지는 길 근처의 가게들은 차단되어 있습니다.

철거 후 길을 정돈하려는 것으로 보입니다.



그렇게 걷고 걷다가 끊어진 철교가 눈에 들어옵니다.



자세히 보니 기존의 철길과 끊어진 철교과 서로 교차하고 있는 듯 보입니다.



바로 인근에는 건널목이 있습니다. 과연 이 곳은 어떤 곳이길래 이런 풍경이 펼쳐지고 있는 것일까요?



 다음 포스팅에서 2부가 이어지겠습니다.


철길도 이사를 간다? 덕하역 이설 전날 풍경(1) [2019.06.16]

https://elecs.tistory.com/327



이 장소를 Daum지도에서 확인해보세요.
울산광역시 울주군 청량읍 |
도움말 Daum 지도

도심속 작은 간이역 사상역의 흔적들 [2019.06.16]


 지난 무더운 여름 부산을 방문하기 위해 사상역에서 하차하였던 기억이 있습니다. 불과 1년도 지나지 않았지만 사상역의 모습은 지금과는 완전히 달라져 있었습니다. 그 모습을 기록하기 위해 경부선 사상역을 방문해봅니다.


 작년 방문 당시의 경부선 사상역의 모습을 보고 싶으신분들은 아래 링크를 참조해주세요.


 도심속 작은 간이역 사상역의 마지막 모습[2018.08.04]

 https://elecs.tistory.com/272






도시철도 사상역에서 내려 경부선 사상역 인근에 가보았습니다.



뭔가 허전하다 했더니 역사는 흔적도 없이 헐렸습니다.



임시역사 옆에서는 새로운 역 건물을 열심히 올리고 있었습니다.



구역사 바로 앞에는 시내버스 정류장이 위치해 있습니다.

도시철도 역과 구분을 위해 '코레일사상역'으로 표기하고 있었습니다.



기초 공사는 완료가 되었는지 벌써 공사가 여기까지 진행되었습니다.



작년에 임시역사를 찍었던 그 각도에서 다시 한 번 찍어 보았습니다.



역 주변이 공사중이다 보니 인부들께서 주변 정리를 하고 계십니다.

고생이 많아 보이십니다.



사상역 주차장 입구에서 바라본 승강장의 모습입니다.



임시역사 뒷부분의 모습입니다. 안전을 위해 팬스고 막아두고 있습니다.



역사 안에서 운행대기중인 김포경전철이 너머에 보입니다.

생각보다 가까운 위치에 있습니다.



작은 역임에도 출입문은 두 개나 달려 있습니다.



열차 도착 5분전 즈음 직원분들이 문을 열어주었습니다.



불과 작년까지 이 위치에 구 역사가 있었는데 감쪽같이 사라졌습니다.



경부선에는 수많은 열차들이 수시로 지나가기 때문에 건너기 전에 주변을 조심히 살펴야 합니다.



상행선은 2번 승강장만 여객을 취급하는 듯 보입니다.

여기서도 서울 방면의 열차를 탈 수 있군요.



반면 하행선의 경우 부산 방면과 부전 방면으로 나뉘어져 있습니다.



새로운 역사가 완공된다면 이 위험한 건널목은 사라지겠지요.



이 트럭은 어떻게 여기까지 들어온 걸까요?



잠시후 순천발 포항행 열차가 4번 승강장으로 들어옵니다.



부전역을 시종착하지 않고 정차만 하고 바로 포항으로 향하는 열차입니다.

이 차 이외에 부전역을 정차만 하는 열차로 신해운대행 ITX-새마을이 있을겁니다.



열차에 오르기전 구 역사 바로 옆에 있떤 건물의 모습입니다.

과연 이 건물은 완공 이후 어떤 운명을 맞게 될까요?



 

이 장소를 Daum지도에서 확인해보세요.
부산 사상구 괘법동 429-1 | 사상역
도움말 Daum 지도

싱싱한 해산물들을 맛볼 수 있는 곳 - 해운대 전통시장 [2019.06.15]


 매년 내일로 시즌 때마다 부산을 방문하면 해운대를 항상 방문해 바닷가를 감상해왔습니다. 그런데 매번 아름다운 바닷가에만 매료되어 인근에 전통시장이 있다는 사실을 이제서야 알게 되었습니다.

 그래서이번에는 해안도시 부산에 위치한 해운대 전통시장을 방문해 보았습니다.





해운대 시장은 해운대역에서 해운대 방향으로 계속 걷다보면 떡볶이를 파는 골목 즈음에 위치해 있습니다.



입구 인근에 도달하자마자 호떡 가판대가 보입니다.



확실히 부산의 랜드마크 인근에 있는 시장이다 보니 유동인구는 많습니다.



해운대 시장에서 가장 큰 특징이라면 곰장어를 파는 집이 많다는 점입니다.



어떤 시장에서는 누에를 팔고 있습니다. 누에를 실물로 보는건 처음이군요.



거리에 앉아 해물을 파는 상인 분도 계십니다.



말로만 듣던 독도꽃새우를 처음으로 봅니다. 무슨 맛일까요?



부산하면 횟집은 빼놓을 수 없는 곳이죠!



호떡이 굉장히 맛있어보입니다. 치즈 호떡도 맛이 좋더군요.



시장 한가운데에서는 청과물을 파는 시장도 존재합니다.



밤 시간대가 되면 시장은 또다른 모습으로 손님을 맞이합니다.



어항의 물고기들도 밤이 되니 좀 더 분주히 움직이는것 같아 보입니다.



시장을 돌아다니던 중 사람을 좋아하는 고양이 한 마리가 보입니다.



낮선 사람을 가리지 않고 놀아달라는 듯히 바라보는군요.



꼼장어의 껍질을 벗겨낸 모습입니다. 조금은 징그럽네요.



밤이 되니 손님들이 훨씬 많아졌습니다.



물고기 뿐 아니라 전복이나 개불과 같은 것들도 팔고 있습니다.



조금은 단촐하지만 3만원 어치의 막썰어회에 도전해 보았습니다.

광어, 우럭, 도다리로 구성되어 있는데 굉장히 맛이 좋더군요.



다음날 아침 해운대의 모습입니다.

슬슬 여름을 준비하는지 파라솔이 설치되어 있습니다.



이 큰 길을 지나 끝부분까지 걸어가면 구 해운대역이 있습니다.

이 거리에 관광객들이 많이 지나다니고 했었는데

광화문처럼 중앙에 보도를 둔 것은 상당히 좋은 아이디어인 듯 합니다.



바로 뒤편에서 바라본 해운대 바다의 모습입니다.



해운대를 떠나기 전 마지막으로 바라본 해운대 전통시장의 모습입니다.

다음에도 해운대에 놀러와 보고 싶네요!






이 장소를 Daum지도에서 확인해보세요.
부산 해운대구 중동 1394-193 | 해운대시장
도움말 Daum 지도

2019 부산국제철도기술산업전 [2019.06.15]


 전에 모터쇼 전시회를 다녀오면서 장래희망을 꿈꾸었던 적이 있었습니다. 이번에 사회에 제 자신이 어떤 공헌을 할 수 있을지를 고민하면서 부산 BEXCO에서 주최하는 부산국제 철도기술산업전에 다녀와 보았습니다.




마침 벡스코 앞에서는 수제맥주 페스티벌도 동시에 열리더군요.



행사장 입구에서부터 기대감이 오르기 시작합니다.



철도 기술 박람회 답게 철도에 쓰이는 다양한 요소들이 전시되고 있습니다.



둘러보다 보니 인천공항 셔틀트레인의 모형이 보이는군요.



경춘선을 절찬리에 달리고 있는 ITX-청춘도 등장합니다.



철도계의 대기업인 현대로템 답게 다양한 볼거리를 제공하고 있었습니다.



심지어는 실제 전동차의 일부를 박람회에 가져다 놓기도 하더군요.



이 전동차는 튀니지로 수출이 예정되어 있다고 합니다!



열차 천장에서만 보던 팬터그래프를 이렇게 가까이 볼 수 있는것이 참으로 신기했습니다!



은하철도999에 등장하던 차장님이 현실에서도 나타났습니다.

머리가 없는 모습이 너무나 무서웠는지 지나가던 어린 아이들이 종종 이 모습을 보고 놀라기도 합니다.



돌아다니던 도중 다원시스 부스를 지나가게 되었습니다.



이번에 들어가게 된 7호선 열차라고 하네요.

얼핏 보고 최근 투입된 2호선과 헷갈렸습니다. 디자인은 비슷한 듯 하면서 다릅니다.



부스 한 켠에서는 동해선 연결을 기원하며 침목을 기증하는 자리가 있었습니다.

강릉에서 제진까지 험한 산지를 과연 어떻게 철길을 놓을지 조금은 궁금하기도 합니다.



철도 모형을 만드는 부스도 참가하였더군요.

어린 아이들이 많이 방문하여 모형을 주문해갑니다.



전차선이 늘어지지 않도록 잡아주는 역할을 하는 카테너리 시스템입니다.



손잡이의 디자인이 다양하게 전시되어 있는게 신기하네요.



심지어 건널목 아래에 깔리는 고무보드도 있습니다.

그러고보니 요즘 건널목에는 나무보다는 고무가 쓰이는 듯 하지요.



조만간 중앙선 구간을 달릴 열차입니다. 과연 어던 모습으로 나타날지 기대되네요.



다원시스에서 전시하였던 7호선 열차 내부에 들어가 보았습니다.

벌써 내부에는 노선도 스티커도 붙여놓았더군요.



과연 7호선에서 달릴 이 열차는 어떤 모습일지 벌써부터 기대됩니다.




 이날 부스는 전체적으로 볼거리는 괜찮았습니다. 다만 일반인들 입장에서는 VR이나 실물모형을 보는 정도면 충분히 만족할 만 하겠지만 열차에 대해 좀 더 자세히 알고 싶은 사람 입장에서는 중소기업 전시관이 마지막날이어서 짐을 싸고 있어서 충분히 구경을 다 하지 못한게 상당히 아쉬웠습니다.


 다음 전시는 2년후라고 합니다. 과연 2년 후의 우리나라의 철도 환경은 얼마나 달라져있을까요?




Extreme Learning Machine(극학습기계)

공대생의 팁 2019.05.15 02:57


 인공지능 분야가 발전하면서 다양한 구조의 알고리즘들이 발굴되고 있으며 이는 조금씩 발전되고 있습니다. 물론 각 알고리즘들이 제시하는 다양한 제안들이 하나둘씩 쌓여가다 보면 언젠가는 알파고를 뛰어넘는 새로운 알고리즘이 나타나리라 기대합니다.

 이번 포스팅에서는 2006년 난양공대(NTU)의 Guang-Bin Huang이 투고한 2019년 5월 15일 현재 피인용수 7044회의 논문인 Extreme Learning machine에 대해 보도록 하겠습니다.



 Neural Network(인공신경망)의 구조는 거의 대부분이 다음과 같은 모습을 가지고 있습니다.


 위의 그림에서 x는 input, b는 bias, w는 input layer와 hidden layer를 연결해주는 weight vector, N는 hidden layer의 node, β는 hidden layer와 output layer를 이어주는 weight vector, t는 output을 의미합니다. 위 그림의 neural network를 식으로 다음과 같이 나타낼 수 있습니다.



 이 때 함수 g()는 무한으로 미분이 가능한 함수로 흔히 알려진 삼각함수 sin() 혹은 cos()와 자연함수 e^x가 있습니다.


 위 구조의 Neural Network를 기존의 방식대로 학습을 시킬때는 다음과 같은 방법으로 흔히 사용합니다.



 흔히 사용되는 알고리즘은 forward propagation으로 계산을 하여 기존의 출력값과 비교하여 오차를 구한 후 back propagation 과정을 통해 weight값을 조정합니다. 가장 보편적으로 사용되는 알고리즘이지만 다음과 같은 이슈가 존재합니다.


 1) learning rate인 η의 값이 너무 작으면 학습 속도가 매우 느려진다. 그러나 η의 값이 너무 클 경우 학습 속도가 불안전해 지면서 심할 경우 값이 수렴되지 않고 발산하는 경우가 발생한다.

 2) back propagation을 하는 과정에서 값이 local minima에 빠질 가능성이 존재한다. 이 경우 global minimum에 도달하지 못하고 local minima에 갇혀버릴 수 있다.

 3) back propagation에 의해 오버트래이닝이 되면 over-fitting이 되어 학습 결과물이 더 좋아지지 않을 가능성이 있다.

 4) 위의 알고리즘 자체에서 가지고 있는 핵심 수단인 gradient-base 학습은 시간이 매우 많이 걸리는 방법이다.


 가장 많이 사용되는 gradient-base 알고리즘의 단점들을 좀 더 효율적인 방법을 찾아보기 위해 만들어진 알고리즘이 이번에 소개하는 Extreme Learning Machine입니다.


 그럼 위에서 보았떤 Neural Network의 구조를 다시 한 번 보도록 하겠습니다.



 Neural Network의 입력에서 hidden layer까지의 과정을 H로 가정하고 이를 식으로 나타내면 다음과 같이 나타낼 수 있습니다.



이 때 위의 식에서 나타낸 부분들은 아래와 같이 나타낼 수 있습니다. 





 위에서 주어진 행렬 H를 사용하여 최적의 값을 찾기 위해 다음과 같은 식으로 나타낼 수 있습니다.



 기존의 출력값 T를 행렬 H와 β의 최소값을 찾아 결과값이 최소로 나오게 한다면 우리는 최적의 weight vector를 얻을 수 있습니다. 위 식에서 β의 최소값은 다음과 같은 식으로 찾을 수 있겠습니다.



 이 식을 사용함으로서 기존의 알고리즘에서 사용하던 back propagation 과정을 거치지 않고 적합한 값을 빠르게 찾을 수 있는 방법입니다. 여기서 †는 Dagger(칼표)로서 Moore-Penrose generalized inverse(Pseudo inverse, 의사역행렬)로서 행렬 H가 정사각행렬이 아닐 때 유사 역행렬을 구하는 방식입니다. pseudo inverse에 대해 자세히 알고 싶으신 분들께서는 아래의 사이트를 참조 하시면 큰 도움이 될 것입니다.


https://darkpgmr.tistory.com/108


 이러한 방식의 Extreme Learning Machine을 좀 더 발전시켜 auto encoding을 사용하는 OS-ELM알고리즘과 OR-ELM알고리즘으로 발전하게 됩니다. OR-ELM의 알고리즘에 대해 다루는 사이트를 소개하면서 글을 마치도록 하겠습니다.


Online Recurrent Extreme Learning Machine

https://github.com/chickenbestlover/Online-Recurrent-Extreme-Learning-Machine




출저 : HUANG, Guang-Bin; ZHU, Qin-Yu; SIEW, Chee-Kheong. Extreme learning machine: theory and applications. Neurocomputing, 2006, 70.1-3: 489-501

https://www.sciencedirect.com/science/article/pii/S0925231206000385



바닷가가 보이는 동해선 도보여행기(좌천역~월내역)(2)[2019.03.09]


 어느덧 2019년 4월이 지나 5월이 되어가고 있습니다. 4월 중순부터 작년 여름이 생각날 정도의 초여름이 이어지는 듯 하더니 비가 내린 후에는 밤이면 쌀쌀한 날씨가 이어지고 있습니다. 부디 이번 여름에는 작년처럼 밖에 나가기가 무섭지 않을 정도로 덥지 않기를 바라고 있습니다.

 이번 포스팅에서는 지난달에 다녀왔던 동해선 도보여행기 이야기를 이어서 올리도록 하겠습니다.



앞으로 이설될 동해선 철도의 모습입니다.

아직은 공사중이지만 개통된다면 열차 안에서 바다를 훤히 볼 수 있을 것으로 보입니다.



다리 밑으로 지나던 건널목은 개통된다면 자연스레 사라지겠지요.



길을 걷던 도중 저 멀리 왠 고양이 한마리가 보입니다.



불러봤더니 사람 곁으로 금새 다가오는 걸 보니 주인이 있는 고양이로 보입니다.



확실히 바닷가 근처의 길은 경치를 구경하기 참 좋습니다.



월내리 효마을



길을 지나던 도중 열차가 빠르게 통과합니다.



현재 철길과 새로 이설될 철길의 모습



원래 있던 철길 바로 옆으로 높게 철도를 깔고 있기 때문에

바다를 바라볼 수 있는 지점이 많이 늘어나고 있습니다.



철길 바로 옆으로 바다가 펼쳐집니다.

저 멀리 고리 원자력 발전소가 보입니다.



바다가 바로 눈 앞에 보이는 월내건널목

이 건널목도 곧 사라질 예정입니다.



월내리 구간은 인도가 비좁아 걸어다니기가 많이 불편힜습니다.

만약 이설된다면 기존 철길을 도보로 바꾸어도 좋을것같습니다.




길 바로 옆에 붙어있는 건널목이다 보니 도보로 건너기가 애매합니다.



그래도 바다가 눈앞에 보이는 건 볼만하네요.



드디어 월내역 인근까지 걸어오는데 성공하였습니다.



월내역은 이설을 준비하기 위해 임시역을 건설하여 운영되고 있습니다.



월내역은 인근에서 5분 거리에 이설될 예정이기 때문에 이 삼거리도 변화가 있을 것으로 보입니다.



임시역이지만 갗출 것은 모두 가지고 있습니다.



월내역 임시승강장 너머로는 새로운 복선전철이 건설중에 있습니다.



이 곳에서 바닷가 쪽으로 걸어가보니 저 멀리 발전소가 생각보다 가까이 있음을 알 수 있습니다.



지금은 무궁화호를 탈 수 있지만 이설 이후에는 전철 전용역이 될 것으로 보입니다.



승강장에서 바라본 월내역의 모습입니다.



열차에 오르기 전 바닷가 옆에 있었던 건널목으로 다시 와보았습니다.



잠시후 건널목에서 경고등이 켜지고



그 사이 열차가 빠르게 건널목을 통과합니다.



그렇게 열차는 희미하게 멀어져만 갑니다.



앞으로 이 곳에서 볼 수 없게 될 풍경이기에 더욱 아쉬워지는 듯 합니다.



다시 열차를 타기 위해 승강장으로 돌아왔습니다.



다음역인 서생역은 현재 열차가 정차하지 않습니다.

그러나 광역전철이 개통된 후에는 전철역으로 부활할 예정입니다.



부산 방면에서 동대구로 가는 열차를 열심히 기다리고 있습니다.



그 때 갑자기 반대편에서 왠 열차 한 대가 들어옵니다.



태화강발 동대행 열차가 왜 이곳으로 올라온 것일까요?

아무래도 부전역 쪽으로 회송중인 차량인 것으로 보입니다.



열차가 들어오더니 잠시후 들어오는 동대구행 열차와 교행을 위해 기다리는 중입니다.



월내역이 이설된다면 이 자리에는 어떤 것이 생길까요?


그렇게 사람들은 열차에 오르내립니다. 이제 저도 돌아가기 위해 동대구행 열차에 올라탑니다.


 


 차후 동해선은 영덕에서 삼척을 거쳐 정동진까지 개통이 준비중입니다. 앞으로도 이렇게 바닷가를 볼 수 있는 구간이 더 생겼으면 좋겠습니다!