구조체는 개별적인 데이터를 하나로 묶는 자료형이며 Scilab에서도 이것을 지원한다. 예를 들어서 어떤 사람의 이름, 나이, 시력을 각각 name, age, sight 라는 이름으로 저장하고 싶다면 다음과 같이 struct()함수를 사용한다.


[그림 1] 구조체의 생성


구조체의 각각의 데이터를 필드(field)라고 칭한다. 이 예에서 person1 구조체의 필드는 name, age, sight 이다. 함수 struct() 은 반드시 짝수 개(0도 가능함)의 입력 인수를 가져야 하고 홀수 번째의 인수는 구조체의 필드 이름으로서 반드시 문자열이어야 한다. 짝수 번째 입력 인수는 진전에 입력된 필드명을 가지는 값으로서 Scilab 객체(행렬, 문자열, 등등)가 온다.


 위와 같은 구조체를 정의하는데 있어서 또 다른 방법은 개별적인 요소를 하나하나 직접 생성/입력하는 방법이 있다. 두 가지 문법이 있는데 다음과 같다.


structName(‘fieldName’)
structName.fieldName

    

두 가지 방법에는 큰 차이점이 있다. 전자의 경우는 필드명에 임의의 문자열을 사용할 수 있으나 후자의 경우는 일반적인 식별자 규칙을 따라야 한다는 것이다.


[그림 2] 구조체의 생성 (다른 방법)


구조체의 필드를 접근한다던가 아니면 추가하는데 있어서도 위에서 설명한 바와 같이 두 가지 방법이 있다. 예를 들어서 age필드를 접근하려면


a = person1.age // 읽기
person1.age = 43 // 변경
a = person1(‘age’) // 읽기
person1(‘age’) = 43 // 변경


새로운 필드도 자유롭게 추가할 수 있다.


person1.height = 170  // height라는 새로운 필드 추가
person1(‘height’)=170 //위와 동일함


 만약 두 개 이상의 구조체가 서로 같은 필드 이름들을 가지고 있다면 이것들을 하나의 행렬로 묶을 수 도 있다.


[그림 3] 구조체를 요소로 가지는 행렬


이 예제에서 구조체 sA와 sB는 똑같은 필드명을 가지고 있으므로 하나의 행렬로 묶을 수 있다. 필드의 값은 데이터형이 서로 달라도 상관없으며 중요한 것은 필드명이다. 필드명이 다른 두 구조체를 하나의 행렬로 묶으려고 한다면 에러를 발생한다.


 한 가지 알아야 할 것은 한 구조체에서 다른 구조체로 대입을 할 때 Scilab에서는 구조체의 내용물이 복사되는 것이지 참조가 되는 것은 아니라는 것이다. 위의 예에서


sC = sA


라고 하면 sC 변수에는 sA의 모든 구조체 필드들이 “복사된” 새로운 구조체가 생성되는 것이다. 따라서 이후에


sA.c = [1 0]


이라고 sA에 새로운 필드를 추가한다고 해서 sC에 영향을 미치지는 않는다. 이것은 구조체를 함수에 넘길 때도 마찬가지로 적용되는데 함수 내부에서 넘겨받은 구조체를 변형시킨다고 해도 원래의 구조체와는 아무런 상관이 없다는 것을 알아두어야 한다.


 구조체와 관련된 함수들은 다음과 같다.


[표 1] 구조체와 관련된 함수들

함수명

기능

struct(...)

구조체 생성

isstruct(s)

s가 구조체인지 테스트

isfield(s,f)

f가 s의 필드인지 테스트

length(s)

사용자 필드 수 + 2

fieldnames(s)

getfield(n, s)

구조체 s의 필드명을 문자열 행렬로 반환

구조체 s의 n번째 필드값을 반환

setfield

(사용 빈도가 매우 낮을 것 같음)

s = null()

구조체 s 삭제


여기서 getfiled() 함수는 구조체의 필드명을 문자열벡터로 반환하는데 3번째 요소부터 사용자 필드라는 것에 유의해야 한다. 아래 예를 보자.


[그림 4] getfiled()함수의 반환 객체


이 예에서 getfield()함수의 첫 번째 인자는 s1의 자료형이 구조체임을  나타내는 문자열이고 (내부적으로 구조체는 mlist 임.) 두 번째 인자인 dim은 Scilab에서 자동으로 생성하는 필드이다. 따라서 사용자 필드는 세 번째부터 마지막까지이다. 사용자 필드명만 뽑아내려면 다음과 같이 하면 될 것이다.


>> fields = getfield(1, s1)
>> fields = fields(3:$)


또는 간단하게 fieldnames()함수를 사용하면 된다.


>> fields = fieldnames(s1)


만약 사용자의 첫 번째 필드인 s1.A 의 값을 읽어내려면 다음과 같이 하면된다.

    

[그림 5] getfield()함수


이 내용은 혼동하기 쉬운데 이렇게 이해하면 될 것 같다. getfield(n, s) 함수는 구조체 s의 내부적인 필드”값”를 반환하는데 내부적으로 s구조체의 첫 번째 필드는 모든 필드명의 문자열벡터, 두 번째 필드는 dims, 세 번째 필드부터가 사용자 필드이다. 따라서 해당되는 것을 반환하는 것이다. 만약 위에서 예를 든 s1의 경우에는 다음 표와 같이 내부적인 데이터를 가진다.


[표 2] getfiled() 함수 반환 객체의 내부 인덱스

내부 인덱스

필드명

필드값

(getfield 함수의 반환값)

1


[ ‘st’ , ‘dims’, ‘A’, ‘b’ ]

2

‘dims’

[1 1]

3

‘A’

[1 2; 3 4]

4

‘b’

[0 1]


따라서 getfield(3, s1) 이라고 하면 s1구조체의 3번째 필드의 필드값이 반환된다고 이해하면 된다.


 하지만 구조체의 필드를 접근하는 데에는 getfield()함수나 setfield()함수를 이용하는 것 보다는 dot(.) 연산자나 문자열키로 읽거나 쓰는 방식이 더 일반적이다.


Posted by 살레시오
,

 지금까지는 명령창에 명령어들을 직접 한두 개씩 입력해서 결과를 확인하는 식으로 사용하였는데 많은 경우에 명령어들을 묶어서 파일로 저장하여 한꺼번에 실행시키는 방법을 사용한다. 명령창에 명령을 직접 입력하면 Scilab 종료시 그것들이 사라지지만 파일에 저장하여 놓으면 이후에 언제라도 불러서 사용할 수 있다.

 이러한 명령어들의 집합(프로그램)을 편집하고 저장하는데 사용하는 도구가 SciNote 이다. 메뉴에서 Applications > SciNotes 항목을 실행시키면 SciNote가 실행된다. 이제 다음과 같이 간단한 프로그램을 작성한 후 적당한 폴더에 저장시키자. 필자는 test02.sce 라는 화일명으로 저장시켰다.(캡션바에 전체 경로가 표시된다.)

[그림 1] SciNote


프로그램은 3x3 난수 행렬 두 개를 생성시킨 후 그 결과를 disp()함수로 화면에 표시하도록 하는 간단한 것이다. 첫 두 줄의 끝은 세미콜론(;)을 넣어놓았다.


 이제 이것을 실행시키기 위해서 Execute 메뉴를 보면 다음 그림과 같이 여러가지 옵션이 있다.


[그림 2] sce파일 실행 옵션

그 중  ..file with echo (ctrl-L) 을 선택하거나 단축키를 누르면 다음과 같이 명령창에 표시된다. 이것은 명령창에 한 줄씩 수동으로 입력하는 것과 완전히 동일하게 작동하며 각 프로그램의 줄이 화면에 표시된다. 또한 세미콜론(;)으로 끝나면 그 결과를 표시하지 않고 그렇지 않으면 표시한다.

[그림 3] [ctrl]+[L] 단축키로 스크립트 파일을 실행한 결과

이에 반해서 Save and execute (단축키 F5) 를 실행하면 먼저 저장하고 실행한다. 이것은 명령이 화면에 표시되지도 않으며 세미콜론(;)의 유무와 상관없이 그 결과도 화면에 표시되지 않는다. 다만 이 예제의 경우 disp()함수가 사용되었으므로 이 함수의 실행결과만이 화면에 표시된다.

[그림 4] [F5] 단축키로 실행한 결과


이때 사용되는 명령어가 exec()함수이다. 이 함수는 sce파일(그리고 나중에 나올 sci파일)을 실행시키는 기능을 수행하며 다양한 실행 옵션을 줄 수 있다. SciNote에서는 -1옵션이 지정되었음을 알 수 있다. 이것에 대해서는 다른 포스트에서 더 자세히 설명하도록하고 일단 여기에서는 SciNote에서 실행시키는데 [Ctrl]+[L] 단축키나 [F5] 단축키가 사용된다는 것을 알아두도록 하자.

특수한 기능들

 명령창과 SciNote가 분리되어 있다면 프로그램 작업 시에 몇 가지 번거로운 점들이 있다. 매번 창들 사이를 클릭해서 왔다 갔다 해야된다던가, 아니면 실행 결과나 프로그램이 다른 창에 가려서 보이지 않는다던가 하는 점들이다. 이러한 불편함을 해소하기 위해서 SciNote와 콘솔창을 하나로 결합할 수 있는 기능이 있다.

[그림 5] SciNote의 위치 조절

위 그림에 표시된 막대 부분을 마우스로 드래그 하여 콘솔창에 놓으면 해당 위치에 결합이 된다. 그래프 창도 마찬가지로 도킹시킬 수 있으며 반대로 SciNote 창에 콘솔창을 도킹시킬 수도 있으므로 자유롭게 작업 환경을 설정할 수 있다.



Posted by 살레시오
,

 Scilab명령어를 담은 문자열을 실행시킬 수 있는 명령어들이 있다. 세 개가 있는데 다음 표에 정리하였다.


[표 1] 문자열을 실행시키는 함수들

함수명

기능

execstr

Scilab 명령 문자열을 실행한다.

eval

evstr

Scilab expression 실행(행렬 반환)

위와 기능은 동일하나 에러를 traping할 수 있음

 먼저 execstr()은 Scilab 명령을 담은 문자열을 실행하는 것이다. (MATLAB의 eval 함수의 기능에 해당됨.)

>> execstr('a=1+sin(%pi/2)')
>> a
a  =
    2.  

이 예에서 보듯이 execstr()함수는 세미콜론이 붙지 않은 명령이라도 그 결과를 콘솔창에 표시하지 않는다. 만약 문자열에 명령 에러가 있다면 execstr()함수는 실행이 멈추게 된다. 다음 예를 보자.

>> execstr('a=2#4'), c=%i
 a=2#4
     !--error 276
Missing operator, comma, or semicolon.
in  execstr instruction    called by :  
execstr('a=2#4'), c=%i

이 예에서 ‘a=2#4’라는 명령은 문법 오류가 있으므로 거기서 실행이 멈춰버리고 에러메서지를 밷는다. 따라서 c=%i 라는 그 뒤의 명령은 실행되지 않는다.


만약 실행을 멈추지 않고 에러의 발생 여부를 처리하고 싶다면 다음 예와 같이 옵션을 사용하면 된다.


>> ier = execstr(['a#2','b=%pi'], 'errcatch','n'), c=%i
ier  =
   4.  
c  =
   i    

   

두 번째 인수로 ‘errcatch’ 를 주었는데 이것은 에러가 발생하면 실행을 멈추지 말고 단순히  ier에 그 결과를 반환하라는 것이다. 세 번째 인수가 ‘n’ 이라면 에러의 개수를 ‘m’ 이라면 에러메세지를 반환하다. 이 경우는 execstr()함수 뒤의 c=%i 가 실행된다는 점이 앞으 경우와 다르다. execstr()함수에는 두개의 명령 ‘a#2’ 와 ‘b=%pi’ 가 들어갔는데 두 번째 명령은 오류가 없음에도 첫 번째 명령에 에러가 있으면 두 번째 것이 실행되지 않고 에러를 캐치하고 넘어가 버린다. 따라서 변수 b도 생성되지 않고 c만 생성이 된 것이다.

 함수 eval()과 evstr()은 문자열 행렬의 값을 구해서 행렬로 반환해 주는 함수이다. 두 함수의 차이점은 에러를 캐치할 수 있느냐(evstr 함수), 없으냐(eval)이다. 예를 들면 다음과 같다.

>> a=%i; b=%e;
>> A=eval(['a' 'b'; 'a+b' 'a-b'])
A  =
   i                  2.7182818        
   2.7182818 + i    - 2.7182818 + i  


 evstr()함수는 두 번째 출력 인수를 지정해 주면 그것에 에러의 번호를 반환하고 함수 자체는 실행이 멈추지 않고 정상적으로 종료된다.


>> A=eval(['a' 'c'; 'a+b' 'a-b']); d=10;
!--error 4
Undefined variable: c
at line       3 of function %eval called by :  
at line      20 of function eval called by :  
A=eval(['a' 'c'; 'a+b' 'a-b']); d=10;

 

이 예에서 eval()함수 내부의 c변수는 없는 변수이므로 에러를 발행하고 실행이 거기서 멈춰버린다. 따라서 뒤에 있는 d=10; 이라는 명령은 실행되지 않는다. 반면에 다음 예를 보자.

>> [A,ier]=evstr(['a' 'c'; 'a+b' 'a-b']); d=10;
>>d
d  =
   10.

이 예에서 evstr()은 eval()과 같은 일을 수행하지만 만약 에러가 발행한다면 두 번째 출력인수 ier에 에러의 코드를 반환하고 정상적으로 종료한다. 따라서 그 뒤에 오는 명령인 d=10;도 정상적으로 수행된다.



Posted by 살레시오
,

 함수  part() 는 문자열의 일부분을 추출하는 기능을 수행한다.

       ❶ part(str, n) // 문자열 str의 n번째 문자 추출

       ❷ part(str, n1:n2) // 문자열 str의 n1번째 부터 n2번째 까지 추출

       ➌ part(str,[n1, n2, n3…]) // 문자열 str의 n1, n2, n3… 번째 문자들을 추출하여 단일 문자열로 반환

예를 들면 다음과 같다.


>> str = "This is a sample string."
str  =
This is a sample string.  

>> strp1 = part(str, 4)
strp1  =
 s  

>> strp1 = part(str, 6:9)
strp1  =
 is a  

>> strp1 = part(str, [11 13 15 19])
strp1  =
 smlt  

만약 입력문자의 크기가 넘어가는 문자열의 범위를 지정하면 공백 문자로 채워진다. 이 예제에서 str의 길이는 24이다. 다음 예는 24를 넘어가는 인덱스에 대해서는 공백문자로 채워짐을 보이고 있다.

>> '|'+part(str,20:30)+'|'
ans  =
|ring.      |

 함수 grep(vstr1, str2)은 문자열 벡터 vstr1 의 요소(문자열) 중에서 str2가 포함된 것의 인덱스를 반환한다. 예를 들어서 다음과 같이 문자열 벡터가 정의되었다고 하자.


>> str1 = ['abcdefghijk', 'xyz', 'jklm']

이후에 grep()함수를 사용했을 때의 결과는 다음과 같다.


>> grep(str1, 'jk')
ans  =
   1.    3.  

 

즉, str1의 첫 번째와 세 번째 요소(문자열)에 ‘jk’라는 문자열이 포함되었다는 것이다. 검색할 문자열이 두 개 이상이라면 이것들을 요소로 하는 문자열 벡터를 두 번째 인수로 넣어주면 된다.

>> grep(str1, ['jk','y'])
ans  =
     1.    2.    3.  


이 예에서는 str1 문자열 벡터의 요소 중에서 ‘jk’ 나 ‘y’ 를 포함하는 것의 인덱스를 구한다.

 함수 strindex(str1, vstr2)는 문자열 str1에서 vstr2 가 시작되는 지점의 인덱스를 구해준다.


>> str1 = '[12.34;56.789;10.123]'
str1  =
 [12.34;56.789;10.123]  

>> strindex(str1, ';')
ans  =
    7.    14.  

>> strindex(str1, [';', '.', ']'])
ans  =
    4.    7.    10.    14.    17.    21.  

 

이 함수 strindex()의 첫 번째는 반드시 단일 문자열이어야 하며 결과 값은 이 문자열의 첫 문자를 1로 보았을 때의 인덱스 값이다. 위의 예들 중 마지막 예에서는 str1 문자열에서 앞에서부터 ‘;’ 또는 ‘.’ 또는  ‘]’ 인 것의 인덱스를 차례로 찾아서 반환해 준다.

 함수 sci2exp()는 입력을 Scilab 명령의 문자열로 변환시켜 준다.

>> A=[1 2;%i, %pi]
A  =
   1.     2.        
   i      3.1415927  

>> str3 = sci2exp(A)
str3  =
 [ 1, 2;%i, 3.1415927]  

>> typeof(str3)
ans  =
 string  



Posted by 살레시오
,

  Scilab에서 문자열은 큰따옴표 “ “ 로 묶거나 작은 따옴표 ‘ ‘ 로 묶을 수 있으며 숫자와 마찬가지로 변수에 대입할 수 있다. 큰 따옴표로 묶었다면 반드시 큰 따옴표로 끝나야 하며 작은 따옴표로 시작했다면 작은 따옴표로 마쳐야 한다.

>> x = ”Hello ” ; // 큰 따옴표 사용
>> y = ’world.’ ; // 작은 따옴표 사용

다른 프로그래밍 언어(예를 들어 C/C++/JVAV 등)의 경우에는 작은 따옴표가 하나의 문자를 표시하는데 이것과 혼동하지 말아야 한다. Scilab에는 하나의 문자를 저정하는  char형이라는 데이터형 자체가 없으며 작은 따옴표도 큰 따옴표와 똑같이 문자열을 만들 때 사용된다.

 두 문자열을 하나로 묶을 때에서는 덧셈(+) 기호를 사용할 수 있으므로 매우 직관적이고 편하게 사용할 수 있다.

>> z = x + y
ans=
   Hello world.

드물긴 하지만  만약 문자열 자체에 큰따옴표나 작은 따옴표가 포함되어 있다면 두 개를 연달아 써주면 된다. 예를 들면 다음과 같다.


>> s1 = 'He said ""Hello"".'
s1  =
     He said "Hello".
>> s2 = "She thinked ''It''s him!''"
s2  =
     She thinked 'It's him!'

 

위의 예는 문자열 자체에 큰 따옴표나 작은 따옴표가 포함된 경우이다.

 한 가지 더 언급할 것은 Scilab에서 문자열은 ‘문자의 배열’이 아니라 숫자와 마찬가지로 단일 데이터형으로 이해하는 것이 좋다. 뒤에 언급하겠지만 숫자가 1x1 행렬인 것처럼 단일 문자열도 1x1 크기의 행렬(더 정확히 표현하면 cell 이지만 편의상 행렬로 지칭하기로 하겠다.)로 취급된다.

기본적인 문자열 관련 함수

 함수 length()는 문자열의 길이를 반환해 준다.

>> length(s1)
ans  =
     16.

 

문자열은 숫자처럼 벡터나 행렬의 요소가 될 수도 있다. 이 경우 size()함수는 문자열 배열의 크기를  반환한다.



이 예에서 변수 sm은 2x3크기의 행렬인데 각각의 요소는 문자열로 채워져 있다. 문자열의 행렬이 length()함수의 입력이 되면 같은 크기의 행렬에  각각의 요소의 문자열의 크기를 반환한다. 어떤 행렬의 한 요소가 문자열이라면 다른 모든 요소도 문자열이어야 한다.

 문자열 합성 연산자 +는 단일 문자열뿐만 아니라 문자열 행렬에 대해서도 유사하게 사용된다.

>> cost = string([10 20; 100 110])
cost  =
        !10   20   !
        !100  110  !

>> scost = '$'+cost+'.00'
scost  =
        !$10.00   $20.00   !
        !$100.00  $110.00  !


이 예에서 string()함수는 숫자 행렬을 문자열 행렬로 바꿔주는 함수이다. 주의할 점은 + 연산자의 두 피연산자가 모두 문자열 행렬일 때에는 크기가 같아야 한다는 점이다. 두 피연산자 중 하나가 단일 문자열일 때는 그것이 다른 행렬의 모든 요소에 더해지게 된다. (이 점은 덧셈 연산자의 기본적인 성질에 부합된다. 스칼라과 행렬의 덧셈을 생각해 보라.)

함수 emptystr(r,c)은 rxc 크기의 빈문자열 행렬을 생성해준다.



이 함수를 이용하면 같은 문자열을 모든 요소로 가지는 문자열 행렬을 쉽게 생성할 수 있다. 예를 들어서 모든 요소가 ‘hello’라는 문자열인 5x3크기의 행렬을 생성하려면 다음과 같이 하면 된다.


>> samestr = emptystr(5,3)+'hello'
samestr  =
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !
       !hello  hello  hello  !

  문자열의 각각의 문자를 아스키(ASCII) 값의 벡터로 바꿔주는 ascii()라는 함수가 있다.


>> ascii('01ABab')
ans  =
     48.    49.    65.    66.    97.    98.

 

이 예에서 문자 ‘0’의 아스키값은 48, 대문자 ‘A’는 65 임을 알 수 있다.

 이전 포스트에서 문자열들을 하나의 문자열로 합치는데 +연산자를 사용한다고 했는데 strcat()함수도 유사한 기능을 수행한다. 기본적으로 문자열의 벡터(행벡터 혹은 열벡터 상관없음) SM에대해서 함수 strcat(SM)은 모든 요소를 하나의 문자열로 합쳐준다. 기본적으로 첫 번째 요소는 문자열 벡터이다.

만약 문자열 사이에 어떤 문자열을 추가시키고 싶다면 두 번째 인자로 그 문자열을 주면 된다. 아래 예는 문자열 사이에 공백문자 ‘ ‘와 ‘+’를 추가시킨 것이다.




Posted by 살레시오
,

 프로그램을 작성하다 보면 빈행렬(empty matrix)을 생성할 필요가 가끔씩 생긴다. 즉, 요소가  없는 0x0크기의 빈행렬를 생성하려면 다음과 같이 하면 된다.


>> A = []

 

만약 행렬 A가 이전에 어떤 요소들을 가지고 있었다면 빈행렬을 대입하는 순간 그것들은 지워지고  그 요소를 저장하기 위해 할당되었던 메모리는 반환된다.

특수한 행렬을 생성하는 기본적인 함수들은 다음 표와 같다.


[표 1] 특수 행렬을 생성하는 함수들

eye(), eye(r, c), eye(M)

주대각 요소가 1인 행렬을 생성한다.

zeros(), zeros(r, c), zeros(M)

모든 요소가 0인 행렬 생성

ones(), ones(r, c), ones(M)

모든 요소가 1인 행렬 생성

linspace(c1, c2 [, n])

c1부터 c2까지 n개의 등간격 행벡터 생성. (n이 생략되면 기본적으로 100임) c1, c2 : 복소수 가능

testmatrix(‘magi’, n)

testmatrix(‘frk’, n)

testmatrix(‘hilb’, n)

nxn 매직행렬 생성

nxn Franck행렬 생성

nxn Hilbert행렬의 역행렬 생성

rand(“seed”), rand(“seed”, s)

rand(r, c [ , strKey] )

rand(M [ , strKey] )

seed값을 얻거나 설정한다. (초기에 s=0임)

r x c 크기 혹은 M행렬과 같은 크기의 난수 행렬 생성

strKey : “uniform”, “normal”, “info”

grand

더 다양한 옵션으로 난수행렬 생성

eye(M)은 M행렬과 같은 차수이고 주대각 요소가 1인 행렬을 생성하며 행렬M이 꼭 정방행렬일 필요는 없다. 주의할 점은 eye(10)이라고 입력하면 10x10 행렬이 생성되는 것이 아니라 1x1행렬이 생성된다는 것이다. (10이라는 숫자가 1x1행렬이기 때문) 그리고 덧셈과 뺄셈에서 사용될 때는 더해지는 행렬과 자동으로 같은 차수의 행렬을 생성한다. ones()와 zeros()도 같은 특성을 가진다.

 linspace(c1, c2 [,n])함수는 c1부터 c2까지 등간격으로 n개의 요소를 가지를 행벡터를 생성하는 자주 사용되는 함수이다. 예를 들어서 0부터 2π 까지 100개의 요소를 가지는 행벡터를 생성헤서 vX변수에 대입하려면 다음과 같이 하면 된다.

>> vX =  linspace(0, 2*%pi)

1000개로 개수를 늘리려면 다음과 같이 한다.


>> vX =  linspace(0, 2*%pi, 1000)

 

 한 가지 특이한 것은 c1, c2는 복소수도 가능하다는 것이다. 예를 들어서 c1=1+%i, c2=2+3*%i, n=5라면 간격을 나눌 때 실부부는 실수부끼리, 허수부는 허수부끼리 나눈다. 즉 다음 두 명령은 같은 것이다.

>> linspace(1+%i, 2+3*%i, 5)
>> linspace(1, 2, 5) + linspace(1, 3, 5)*%i


후자 보다는 전자가 더 간단하므로 이것을 사용하면 된다

.

 함수 rand()는 난수행렬을 생성시킨다. 이때 균일분포/정규분포를 strKey로 지정할 수 있다.


위 예제에서 histplot()은 히스토그램을 그리는 함수이다.



Posted by 살레시오
,

(A) 덧셈과 뺄셈

 두 행렬의 덧셈/뺄셈은 크기(행수와 열수)가 같아야 수행되며 다르면 에러가 발생한다. 한 가지 주의할 것은 <스칼라±행렬> 의 연산인데 수학적으로는 정의되지 않지만 Scilab 에서는  (Matlab 와 마찬가지로) 스칼라를 모든 요소와 각각 더하는 연산을 한다는 것이다.

>> A=[1 2;3 4]; B=[5*%i %pi;%e %e^2]; C=[1 2 3]; d=-2;
>> A+B
ans  =
   1. + 5.i     5.1415927  
   5.7182818    11.389056  
>> B-C
    !--error 9
 Inconsistent subtraction.
>> C+d
ans  =
 - 1.    0.    1.

위 의 예에서 보듯이 행렬 A와 B는 크기가 둘 다 2x2로 같으므로 덧셈/뺄셈이 가능하지만 B와 C는 크기가 다르다. 따라서 B와 C의 덧셈/뺄셈은 허용되지 않는다. 다만 d는 스칼라이므로 이것과 행렬과의 연산은 가능하며 모든 요소에 이 스칼라를 더하거나 빼는 연산을 수행한다.

(B) 곱셈

 행렬의 곱셈에 사용되는  연산자들은 다음 표와 같다.

[표 1]  행렬의 곱셈

A*B

일반적인 곱셈. A의 행과 B의 열의 개수는 같아야 함.

A.*B

요소간 곱셈. A와 B는 같은 크기여야 함.

A.*.B

Kronecker 곱셈.

A^n, A**n

A행렬의 n승. 즉, A*A*A*...*A. A는 정방행렬이어야 함.

A.^B

요소간 거듭제곱. A와 B는 같은 크기여야 함.

단순한 A*B 연산은 행렬의 곱셈으로서 피연산자의 한 쪽이 스칼라 이거나 아니면 A의 행 수와 B의 열의 개수는 같아야 계산이 성립한다.

>> A=[1,2+3*%i;%pi %e^2]
A  =
   1.           2. + 3.i  
   3.1415927    7.3890561

>> %i*A
ans  =
    i           - 3. + 2.i    
  3.1415927i    7.3890561i  

>> A*[1 2 3;4 5 6]
ans  =
   9. + 12.i    12. + 15.i    15. + 18.i  
   32.697817    43.228466     53.759115

>> [1 2 3]*A
         !--error 10
Inconsistent multiplication.

위의 예들에서 마지막 것은 행렬의 차수가 맞지 않아서 에러가 발생하는 것이다.


 이에 반해서 A.*B 연산은 행렬의 같은 위치에 있는 요소끼리 곱하는 연산으로서 A행렬과 B행렬의 크기가 같아야 한다.


>> P=[1 2 ; 3 4]
P  =
    1.    2.  
    3.    4.  

>> Q= [%i %pi; %e %T]
Q  =
    i            3.1415927  
    2.7182818    1.        

>> P.*Q
ans  =
    i            6.2831853  
    8.1548455    4.        

이 연산의 결과도 같은 크기의 행렬이다. 만약 크기가 서로 다른 행렬에 대해서 이 연산을 수행하려고 한다면 에러를 발생할 것이다.


>> [1 2].*[3;4]
         !--error 9999
inconsistent element-wise operation

 

그리고 A.*.B 연산은 Kronecker 곱셈으로서 수학기호로는 ⊗로 표시 한다. 즉 A⊗B는 다음과 같은 연산을 수행한다.



따라서 행렬 A와 B에 대한 크기 제약 조건은 없으며 예를 들면 다음과 같다.


>> [1 2].*.[10 20;30 40]
ans  =
   10.    20.    20.    40.  
   30.    40.    60.    80.

 

 행렬의 거듭제곱에는 ^, **, .^ 연산자가 있다. A^n, 또는 A**n 은 행렬의 거듭제곱 연산자로서 예를 들어서 A^3 또는 A**3은 A*A*A 와 결과가 같다. 따라서 이 연산이 수행되려면 A행렬은 반드시 정방행렬이어야 한다. 이에 반해서 A.^n 은 행렬의 각각의 요소를 n승 하는 것이다. 따라서 A행렬의 크기에 대한 제한 조건은 없다.

>> A=[2,3;4,5];
>> A^3
ans  =
    116.    153.  
    204.    269.  
>>A.^3
ans  =
    8.     27.  
   64.    125.  

행렬의 거듭 제곱과 요소간 거듭 제곱은 반드시 구분해야 한다. 한 가지 특이한 (혼동하기 쉬운)점은 만약 A가 벡터라면 A^n 이나 A.^n 이나 결과가 같다는 것이다. (개인적인 생각으로는 A가 벡터일 때 A^n 연산은 에러를 뱉는 것이 더 일관성이 있는 것 아닌가 하는 아쉬움은 있는데 어쨌든 Scilab은 그렇게 동작한다.(

(C) 나눗셈

 행렬의 나눗셈에 대해서 다음 표에 정리하였다. 나눗셈은 보통의 나눗셈과 좌나눗셈으로 나뉜다는 점이 특이하다.

[표 2]  행렬의 나눗셈

A/B

행렬의 나눗셈. A*inv(B)와 같다.

한 쪽이 스칼라이거나 크기가 같아야 한다.

A./B

요소간 나눗셈. A와 B는 같은 크기여야 한다..

A\B

행렬의 좌나눗셈 inv(A)*B와 같다.

한 쪽이 스칼라이거나 크기가 같아야 한다.

A.\B

요소간 좌나눗셈. A와 B는 같은 크기여야 한다.

이 경우에도 요소간 연산자가 따로 정의되어 있으며 dot(.)으로 시작한다. 또한 행렬의 나눗셈의 경우는 역행렬과 관계되어 있으며 A/B는 A*inv(B)와, A\B는 inv(A)*B와 동일한 연산을 수행한다. inv()함수는 정방행렬의 역행렬을 구하는 함수이다.

(D) 기타 연산자

  행렬의 복소전치행렬은 작은 따옴표(‘)를 행렬의 끝에 붙여주면 구할 수 있고 단순 전치 행렬은 점 작은 따옴표 (.’)를 붙이면 된다. 복소전치행렬은 행과 열의 위치를 바꾸고 켤레복소수로 변환된 행렬을 의미하며 단순 전치 행렬은 그냥 위치만 바꾼 행렬은 의미한다.

>> A=[1, 2*%i; 3+4*%i, 5]
 A  =
    1.          2.i  
    3. + 4.i    5.  

>> B=A'
B  =
    1.     3. - 4.i  
 - 2.i    5.        

>> C=A.'
C  =
   1.     3. + 4.i  
   2.i    5.      

 

이 결과를 잘 살펴보면 B행렬은 A행렬의 복소 전치 행렬이고 C행렬은 단순 전치 행렬이라는 것을 알 수 있다.


 정방행렬의 역행렬을 구하는 함수는 inv()이고 행렬식(determinant)을 구하는 함수는 det()이다. 직전의 A행렬에 대해서 역행렬과 행렬식을 구하는 예는 다음과 같다.


>> inv(A)
 ans  =
    0.3170732 + 0.1463415i    0.0585366 - 0.1268293i  
   - 0.0731707 - 0.3414634i    0.0634146 + 0.0292683i  

>> det(A)
   ans  =
      13. - 6.i  



Posted by 살레시오
,

 생성된 행렬의 개별 요소를 접근하려면 행렬에 괄호 안에 행과 열의 번호를 콤마(,)로 구분하여 써주면 되는데 예를 들어 A행렬의 r행 c열 요소는 다음과 같이 접근한다.


 A(r, c)

 

여기서 r과 c를 인덱스(index)라고 한다. 사용 예를 들면 다음과 같다.

>> A = [ 1 2 3; 4 5 6]
>> b = A(1, 2) // 2가 변수 b에 저장된다.
>> A(2,3) = 3*%i // 2행 3열의 요소가 6에서 3i 로 변경된다.

만약  B가 벡터라면 다음과 같이 두 가지 방법으로 인덱싱을 할 수 있다.


>> B = [2 3 5 7 11 13 17 19]
>> c = B(1, 5)  // 1행 5열 요소이므로 11이 변수 c에 저장된다.
>> d = B(5) // 위와 같다.
>> E = (1:100)’
>> f = E(5,1) // 5행 1열의 요소이므로 5가 변수 f에 저장된다.
>> g = E(5) // 위와 같다.

 

이 예제와 같이 벡터의 인덱싱은 하나만 지정할 수 있다.


 사실 행렬은 내부적으로 1차원 배열로 관리되며 따라서 인덱스를 하나만 지정할 수는 있다. 예를 들어 다음과 같이 H행렬이 있다고 가정할 때


>> H = [ 10, 20, 30; -40, -50, -60,]

 

H(1)은 H(1,1)과 같이 10이고 H(2)는 H(2,1)의 요소인 -40이다. H(3)은 H(2,1)과 같다.

H(1) == H(1,1)

H(3) == H(1,2)

H(5) == H(1,3)

H(2) == H(2,1)

H(4) == H(2,2)

H(6) == H(2,3)

[ 그림 1] H행렬의 인덱싱

하지만 행렬의 경우 이런 방식으로 인덱싱하는 것을 추천하지 않으며 사용 빈도도 낮다.

 하나의 행 또는 하나의 열 전체를 선택하고자 할 때는 콜론(:)을 인덱스로 사용한다. 예를 들어서 H행렬의 1행 전체와 2열 전체를 선택해서 J1과 J2에 대입하고자 하면 다음과 같이 한다.


>> J1=H(1,:) // 1행, 전체 (즉 그냥 1행)
J1  =
    10.    20.    30.  
>> J2=H(:,2) // 전체. 2열 (즉 그냥 2열)
J2  =
    20.  
  - 50.  

이와 같이 콜론(:)이 인덱싱에서 단독으로 쓰이면 전체(all)의 의미를 갖는다. 혼동의 여지가 있는 것은 이전 포스트에서 설명한 콜론(:)연산자의 경우이다. 예를 들어서 2x100 행렬 K를 다음과 같이 생성했다고 가정해 보자.

>> K = [1:100; 100:-1:1]

이 행렬의 1열부터 10열까지 동시에 선택해서 변수 L에대입하려면 다음과 같이 하면 된다.


>> L = K(:, 1:10)

 

두 번째 열인덱스에 1:10 이라고 콜론 연산자를 사용했다. 따라서 이 명령은 다음과 완전히 동일하다.

>> L = K(:, [1 2 3 4 5 6 7 8 0 10])


이렇게 하는 것 보다는 전자가 훨씬 간단하므로 전자를 사용할 것이다. 하지만 콜론 연산자를 사용하는 것은 연속되거나 등간격의  행이나 열을 선택하는 경우에만 사용할 수 있다. 예를 들어서 2열, 4열, 6열… 20열을 동시에 취하려면 다음과 같이 하면 된다..

>> M = K(:, 2:2:20)


하지만 등간격이 아닌 경우에는 행벡터로 각각을 직접 지정해 주어야 한다. 예를 들어서 1열, 2열, 3열 5열 7열 11열 을 동시에 취하려면 다음과 같이 하면 된다.


>> M = K(:, [1 2 3 4 5 11])

등간격이 아니므로 이렇게 직접 지정해 주어야 한다.


 만약 어떤 행렬의 가장 마지막 행(또는 열)을 선택하고 싶다면 $지정자를 이용하면 된다.(MATLAB의 경우에는 end 지정자가 있다.) 예를 들어 K행렬의 가장 마지막 열을 N변수에 대입하고 싶다면다음과  같이 하면 된다.


>>N=K(:,$)
N  =
   100.  
   1.  

 

다른 예로 P라는 100x100는 행렬이 있다고 하고 이 행렬의 마지막 행의 1열부터 50열까지를 선택하고 싶다면

>> P($, 1:50)

라고 지정하면 된다. 마지막행 전체를 선택하려면 P($ , :)라고 하면 될 것이다.

 한 가지 특이한 점은 이 $ 지정자는 특정한 값을 가지지 않는데도 불구하고  마치 특수 상수처럼 사용된다는 점이다. 이 말은 이 지정자가 자유롭게 변수에 저장될 수 있다는 말이며 다음과 같은 명령이 가능하다.


>> x = $
>> y = [ 3 5 7 $]
>> z = 5:$
>> Q = P(:, z)

이 예의 마지막 명령은 P행렬의 5열부터 마지막 열까지를 취해서 Q변수에 대입하는 것이다.




Posted by 살레시오
,

 Scilab의 기본 데이타형은 행렬(matrix)이며 스칼라도 내부적으로는 1x1행렬로 취급된다. 벡터도 마찬가지로 nx1 행렬 (열벡터) 혹은 1xn 행렬 (행벡터) 로 취급된다. 행렬의 요소는 숫자, 불리언, 문자열, 다항식 등 일반적인 Scilab 객체가 될 수 있다. 일 반적으로 그냥 벡터라 하면 열벡터(column vector)를 의미하는 경우가 많으므로 앞으로 그냥 벡터라고 하면 열벡터를 지칭하며 행벡터는 명시적으로 표기하도록 하겠다.


 함수에 넘겨주는 입력 파라메터도 행렬이고 함수의 수행 결과 생성되는 출력값도 역시 행렬이다. 편의상  다음과 같이 구분한다.

❶ 스칼라 : 1x1 차원의 행렬

❷ 벡터 : nx1 차원의 행렬 (행벡터는 1xn 행렬), n ≥ 1 인 정수(스칼라 포함)

❸ 행렬 : mxn 차원의 행렬, m,n ≥ 1 인 정수 (스칼라, 벡터포험)

 행렬을 입력할 때는 대괄호 [ ] 를 사용하며 콤마(,)나 공백을 이용하여 요소 간을 구별한다. 세미콜론(;) 혹은 다음 줄이 행들을 구분한다. (이것은 Matlab 이나 Octave와 동일하다.) 따라서 다음 네 가지가 완전히 동일한 2x3 행렬을 생성한다.

>> A = [1, 2, 3; 4, 5, 6]
>> A = [1 2 3; 4 5 6]
>> A = [1,2,3
4,5,6]
>> A = [1 2 3
4 5 6]

행이 두 개 이상일 때는 반드시 행들의 요소 갯수가 같아야 함에 유의해야 한다. 예를 들어서 다음과 같은 입력은 에러를 발생시킬 것이다. 왜냐하면 1행의 크기는 3인데 2행의 크기는 2이기 때문이다.


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

행렬의 요소는 복소수도 가능하고 문자열도 가능하다. 예를 들어 다음과 같다.

복소행렬을 생성할 때 주의할 점은 실수부와 허수부사이에 공백문자가 있으면 안된다는 것이다. 다음의 C행렬과 D행렬은 크기가 다른 행렬이 되버린다.(왜?)


>> C = [2+3*%i, 4]
>> D = [2 +3*%i, 4]

 

문자열을 요소로 하는 행렬도 가능하다. 예를 들면 다음과 같다.

>> E = [“abc” “def”]
>> F = [“hello”, “world”; “My name is”, ‘Salecio’]    

그러나 한 행렬의 요소들이 숫자나 문자열이 섞일 수는 없다. 또한 정수형과 실수형은 데이터형이 다르기 때문에 한 행렬에 섞일 수도 없다. 따라서 다음과 같은 입력은 에러를 발생시킨다.


>> G = [ 1 2; ‘abc’, 4]
>> K = [int8(1) 2; 3 4]

 

첫 번째 G는 숫자와 문자열을 한 행렬에 섞어서 입력했기 때문에 에러를 발생하며 두 번째 K는 정수형과 실수형이 섞여있기 때문에 에러를 발생한다.

 반면에 진리값을 나타내는 %T(혹은 %t) 와 %F( 혹은 %f)는 특수한 상수이지만 내부적으로 (더블형) 실수 1과 0으로 취급된다. 따라서 이들 값을 숫자형과 섞어서 사용할 수 있다.

이미 생성된 행렬을 이용하여 새로운 행렬을 생성할 수도 있다.

>> A = [ 1 2; 3 4]
>> B = [ A; 5 6]
>> C = [ A [5 6; 7 8] ]
>> D = [A A]
>> E = [A; A]

두 행렬을 옆으로 연결할 때에는 행의 수가 같아야하고 위아래로 연결할 때는 열의 수가 같아야 에러가 발생하지 않는다.

콜론(:) 연산자

 행벡터 혹은 열벡터를 입력하거나, 생성시켜야 하는 경우에 각 벡터 요소들의 증가분이나  감소분이 일정한 경우가 있다. 이 경우에는 콜론(:) 연산자를 이용하면 된다. 이 연산자는 사용 빈도가 높으므로 잘 숙지해 두어야 한다. 입력형식은 아래와 같다.


>> 변수 = 초기값:증감값:최종


이 명령은 초기값으로부터 최종값까지 증감값만큼 증감시킨 수열을 요소로 갖는 행벡터를 생성하여 변수에 저장하게 된다. (행벡터를 생성한다는데 주의하자!) 예를 들어, 변수 a에 0부터 100까지 10의 간격으로 행벡터를 만들고자 한다면 다음과 같이 입력하여 실행한다.



만약 증가분이 1이라면 이것은 생략할 수 있다. 만약 0부터 20까지 1씩 증가시킨 값들을 요소로 갖는 행벡터를 만들고 싶다면 다음과 같이 한다.


>> b=1:20

 

10부터 1씩 감소시켜서 0까지의 값을 요소로 갖는 행벡터는 다음과 같이 생성할 수 있다.

>> c = 10:-1:0

콜론 연산자는 사용 빈도가 굉장히 높으므로 잘 숙지하고 있어야 한다.



Posted by 살레시오
,

 허수는 Scilab에서 %i 로 입력하므로 복소수도 이것을 이용하여 입력할 수 있다. 예를 들어서 복소수 3i, 2-4i 는 다음과 같이 입력한다.

>> a=3*%i
>> b=2-4*%i

허수부와 허수사이에 곱셈(*) 기호를 빠트리지 않도록 주의하자. 또한 실수부와 허수부의 데이터형은 같아야 에러를 발생시키지 않는다.


 복소수를 생성하는 다른 방법으로 complex()함수를 사용하는 방법이 있다. 위의 예와 동일한 입력은 다음과 같다.


>> a=complex(0, 3)
>> b=complex(2, -4)

 

함수 complex(a, b) 에서 a는 실수부 b는 허수부인데 일반적으로 행렬이 될 수 있다. 둘 중 하나라도 스칼라일 경우 나머지가 행렬일 경우는 에러를 발생시키지 않는다.

그러나 만약 a와 b 둘 다 스칼라가 아니라면 서로 차수가 같아야 에러를 발생시키지 않는다.

위 그림의 예에서는 두 행렬의 차수가 같지 않아서 에러를 발생시킨 것이다.

 복소수 관련 함수는 다음 표와 같다.


[표 1] 복소수 관련 함수들

real(z)

복소수 z의 실수부 반환

imag(z)

복소수 z의 허수부 반환

imult(z)

z*%i 결과 반환

isreal(z)

z가 복소수라면 %F 반환

abs(z)

z의 크기를 반환

z’

z의 켤레복소수를 구한다. 만약 Z가 행렬이라면 복소전치행렬을 구한다.

다음 그림에 사용 예를 들었다.

한 가지 유의할 것은 isreal()함수의 결과는 행렬의 모든 요소가 실수일 경우에만 %T 이고 하나라도 복소수가 있다면 %F라는 것이다. 즉, 각각의 요소에 대해서 논리연산을 한 결과를 반환하지 않는다.



Posted by 살레시오
,