Found an issue with the book? Report it on Github.

다항식 해석(Polynomial Evaluation)

다항식 해석(Polynomial Evaluation)

첫 번째 예제는 함수를 사용하여 다항식을 해석하는 데 중점을 둘 것입니다.이 예제를 통해 함수 정의 및 사용의 기본 사항을 이해하겠습니다.

선분 계산하기(Computing a Line)

수치적 배경(Mathematical Background)

임의 순서의 다항식까지 들어가기 전에 먼저 함수를 사용하여 선(line)에서의 점(point)들을 연산하는 방법을 고민해 보겠습니다. 수학적으로 정의하고 싶은 것은 다음과 같이 적용되는 함수입니다.

y(x, x_0, y_0, x_1, y_1)

여기서 x 는 독립 변수이고, (x_0,y_0) 는 선을 정의하는 하나의 점이고 (x_1,y_1) 는 다른 하나의 점이며, 이 두 점을 통해 선을 정의 합니다. 수학적으로 이러한 함수는 다음과 같이 정의할 수 있습니다.

y(x, x_0, y_0, x_1, y_1) = \frac{y_1-y_0}{x_1-x_0}(x-x_0)+y_0

인수의 수를 줄이기 위해 x_0 y_0 을 벡터 \vec{p_0} 로 표현하는 하나의 점으로 통합하고, x_1 y_1 을 벡터 \vec{p_1} 로 표현하는 하나의 점으로 통합하여 아래와 같이 정의 합니다.

\mathtt{Line}(x, \vec{p_0}, \vec{p_1})

모델리카 표현(Modelica Representation)

앞서 살펴본 수학적 관계를 모델리카 모델 내에서 호출할 수 있는 함수로 변환하는 것 이 필요하고, 이를 위해서는 새로운 모델리카 함수를 정의해야 합니다.

아래에 보이는 모델리카의 Line 함수 정의를 보면, 함수 정의는 (최소한 구문적으로) 모델 정의와 매우 유사하다는 것을 알 수 있습니다."

function Line "Compute coordinates along a line"
  input Real x     "Independent variable";
  input Real p0[2] "Coordinates for one point on the line";
  input Real p1[2] "Coordinates for another point on the line";
  output Real y    "Value of y at the specified x";
algorithm
  y := (p1[2]-p0[2])/(p1[1]-p0[1])*(x-p0[1])+p0[2];
end Line;

함수에 대한 모든 인수에는 input , 함수의 결과에는 output 한정자가 붇습니다. 함수의 본문은 algorithm 섹션에 구현되는데, 여기에서 반환 값(이 경우 y)이 계산합니다.

따라서 이 경우는 input 값인 x, p0p1 를 통해 output 값인 y 를 계산합니다. 그리고, 이 함수에는 return 문이 없는데, algorithm 섹션의 결론에 있는 output 변수의 값은 그것이 무엇이든 자동으로 반환되는 값이 되기 때문입니다.

이전 장에서 다루었기 때문에 알고 있는 내용이겠지만 추가해서 두 가지를 설명하면, 첫번째로 함수 자체와 인수 모두에 대한 설명 문자열을 통해서 함수와 인수의 목적을 문서화하고 있습니다. 두번째로는 이 예제에서 다루는 점(point)을 배열을 사용하여 2차원 벡터를 나타내는 방법을 사용하고 해당 배열을 인덱싱하는 방법을 사용하고 있습니다.

Line 모델은 y 를 계산하는 데 사용하는 표현의 길이가 길고 복잡한데, 이러한 표현 방식을 깨뜨릴 수 있다면 좋을 것입니다.

매개 변수(Intermediate Variables)

y 에 대한 표현을 단순화하기 위해 일부 매개 변수를 도입하겠습니다. 이미 x, p0p1 이 함수 내에서 사용할 수 있는 변수라는 것은 알고 있고, 여기에 추가 변수를 도입하고 싶지만 인수가 되어서는 안 됩니다. 대신, 해당 값은 함수에 대해 "내부적으로(internally)" 계산되어야 합니다. 이 조건을 만족하기 위해 보호(protected) 되는 변수의 모임을 만드는데, 이러한 변수는 함수에 의해 내부적으로 계산되는 것으로 간주됩니다. 다음은 protected 를 사용하여 두 개의 내부 변수를 선언하고 계산하는 예입니다.

function LineWithProtected "The Line function with protected variables"
  input Real x     "Independent variable";
  input Real p0[2] "Coordinates for one point on the line";
  input Real p1[2] "Coordinates for another point on the line";
  output Real y    "Value of y at the specified x";
protected
  Real x0 = p0[1], x1 = p1[1];
  Real y0 = p0[2], y1 = p1[2];
  Real m = (y1-y0)/(x1-x0)  "Slope";
  Real b = (y0-m*x0)        "Offset";
algorithm
  y := m*x+b;
end LineWithProtected;

이 모델은 두 가지 새로운 변수를 도입합니다. 하나의 변수 m 은 선의 기울기를 나타내고 bx=0 일 때 조건에 대한 반환 값을 나타냅니다. 이 두 매개 변수를 계산하면 y 를 연산하는 표현식이 y := m*x+b 형식으로 더 쉽게 인식됩니다.

다항식 계산(Computing a Polynomial)

수치적 정의 (Mathematical Definition)

이 섹션의 목표는 임의의 다항식을 계산할 수 있는 함수를 만드는 것입니다. 이제 몇 가지 기본 기능을 살펴보았으므로 궁극적인 목표를 진행해 보겠습니다. 다음과 같이 호출되는 함수를 공식으로 표현 해보겠습니다.

p(x, \vec{c})

여기서 x 는 독립 변수이고 \vec{c} 는 다항식이 다음과 같이 해석되는 계수의 벡터입니다.

p(x, \vec{c}) = \sum_{i=1}^{N} c_i x^{N-i}

여기서 N 은 함수에 전달된 계수의 수인데, 이 시점에서 주목해야 할 두 가지 중요한 사항이 있습니다. 첫째, 첫 번째 요소 \vec{c} 는 다항식의 최상위 항에 해당합니다. 둘째, 모델리카 코드로의 전환을 더 쉽게 하기 위해 \vec{c} 의 요소가 1부터 시작하여 번호가 매겨진다(배열이 1부터 시작하여 인덱싱됨)고 가정하는 표기법을 사용하고 있습니다.

위의 p 에 대한 정의는 읽고 이해하기 쉽습니다. 하지만, 다항식을 연산하기 위해 유한한 정밀도의 부동 소수점 숫자로 계산하는 것 보다, 재귀 접근 방식을 사용하는 것이 더 효율적이고 정확합니다.:math:4^{th} 차수 다항식의 경우 연산 방법은 다음과 같습니다.

p(x, \vec{c}) = ((c_1 x + c_2) x + c_3) x +c_4

이것은 단순한 곱셈 및 덧셈 연산에 의존하고 더 비용이 많이 소모되는(연산에 시간이 소모되는) 지수 연산을 수행하지 않기 때문에 더 효율적입니다. 지수 연산은 유한 정밀도 부동 소수점 표현에서 빈번하게 반올림 또는 잘림 오차를 유발할 수 있기 때문에 오히려 이러한 방식이 더 정확합니다.

모델리카 정의(Modelica Definition)

이제 함수가 수행할 계산을 정확하게 정의했으므로 모델리카에서 함수를 정의하는 작업만 남았습니다.앞서 설명한 다항식을 해석하는 함수를 모델리카로 다음과 같이 구현합니다.

function Polynomial "Create a generic polynomial from coefficients"
  input Real x     "Independent variable";
  input Real c[:]  "Polynomial coefficients";
  output Real y    "Computed polynomial value";
protected
  Integer n = size(c,1);
algorithm
  y := c[1];
  for i in 2:n loop
    y := y*x + c[i];
  end for;
end Polynomial;

다시 말하지만 함수에 대한 모든 인수에는 input 한정자가 있고 반환 값에는 output 한정자가 있습니다. 이전 예제와 마찬가지로 계수 벡터의 길이를 편리하게 참조하기 위해 매개 변수인 n 을 정의했으며, for 루프를 사용하여 임의의 순서에 대한 다항식의 재귀적 해석 방법을 사용했습니다.

이 기능이 제대로 작동하는지 확인하기 위해 아래와 같은 모델리카 모델에서 사용해 보겠습니다.

model EvaluationTest1 "Model that evaluates a polynomial"
  Real yf;
  Real yp;
equation
  yf = Polynomial(time, {1, -2, 2});
  yp = time^2-2*time+2;
end EvaluationTest1;

c 의 첫 번째 요소는 최상위 항에 해당함을 기억해야합니다. 직접 연산한 다항식 yp 와 함수 yf 로 계산한 값을 비교하면 둘이 동일함을 알 수 있습니다.

/static/_images/Eval1.svg

미분(Differentiation)

모델리카 컴파일러에 의해 수치를 미분하는데 다항식의 해석을 사용할 수 있습니다.다음은 어떻게 다항식 모델이 미분 될 수 있는지 보여주기 위해 인위적으로 만들어진 예제 입니다.

model Differentiation1 "Model that differentiates a function"
  Real yf;
  Real yp;
  Real d_yf;
  Real d_yp;
equation
  yf = Polynomial(time, {1, -2, 2});
  yp = time^2-2*time+2;
  d_yf = der(yf); // How to compute?
  d_yp = der(yp);
end Differentiation1;

여기에서 Polynomial 함수를 사용하여 연산하는 yf 와 다항식으로 직접 연산하는 yp 가 있으며, 각각 yfyp 의 미분을 나타내는 d_yfd_yp 라는 두 개의 변수를 추가했습니다. 이때, 이 모델을 컴파일하려고 하면 컴파일러에서 d_yf 방정식과 관련된 오류를 던질 가능성이 매우 높습니다.그 이유는 yf 의 도함수를 계산할 방법이 없기 때문입니다. 간단한 식으로 계산되는 yp 와 달리 yf 가 어떻게 계산되는지에 대한 세부 정보는 Polynomial 함수에 따라서 달라지기 때문인데,일반적으로 모델리카 시뮬레이션 소프트웨어는 도함수를 계산하기 위해 함수의 구현을 살펴보지 않으며만약 내부를 본다고 해도 임의 알고리즘의 도함수를 결정하는 것은 쉬운 일이 아닙니다.

그럼 함수를 미분 해야할 때 어떻게 처리할 수 있는가에 대한 질문을 할 수 있습니다. 미분이 안된다면 모델 내에서 함수를 사용하는 것이 어려워지지 않을까요? 다행스럽게도 모델리카는 함수의 도함수를 해석하는 방법을 지정하는 문법을 제공하고, 이것은 함수 정의에 annotation 이라는 것을 추가함으로써 구현할 수 있습니다.

이 경우에 우리에게 필요한 것은 derivative 주석이며, 함수의 도함수를 해석하는 방법에 대한 정보를 모델리카 컴파일러에 전달할 수 있게 해 줍니다. 이를 위해 다음과 같이 새롭게 해석할 수 있는 함수인 PolynomialWithDerivative 를 정의합니다.

function PolynomialWithDerivative
  "Create a generic polynomial from coefficients (with derivative information)"
  input Real x     "Independent variable";
  input Real c[:]  "Polynomial coefficients";
  output Real y    "Computed polynomial value";
protected
  Integer n = size(c,1);
algorithm
  y := c[1];
  for i in 2:n loop
    y := y*x + c[i];
  end for;
  annotation(derivative=PolynomialFirstDerivative);
end PolynomialWithDerivative;

이 기능은 강조 표시된 줄을 제외하고는 동일합니다.즉, 다음 줄을 추가하기만 하면 됩니다.

  annotation ...

모델리카 컴파일러에게 이 함수의 도함수를 해석하는 방법을 설명하기 위해 함수 자체에 표현 해줍니다.이것은 PolynomialFirstDerivative 함수를 사용하여 PolynomialWithDerivative 의 도함수를 해석해야 한다는 정보를 나타냅니다.

PolynomialFirstDerivative 함수의 구현을 논의하기 전에 먼저 수학적으로 무엇이 필요한지 이해 해야 합니다.다항식 보간 함수의 원래 정의를 상기 해보면 아래를 알 수 있습니다.

p(x, \vec{c}) = \sum_{i=1}^{N} c_i x^{N-i}

p 는 두 개의 인수를 사용합니다. 어떤 임의의 변수 z p 를 미분하려는 경우, 연쇄 법칙(chain rule)을 사용하여 z 에 대한 p 의 전체 도함수를 다음과 같이 표현할 수 있습니다.

\frac{\mathrm{d}p(x, \vec{c})}{\mathrm{d}z} = \frac{\partial p}{\partial x} \frac{\mathrm{d}x}{\mathrm{d}z} + \frac{\partial p}{\partial \vec{c}} \frac{\mathrm{d}\vec{c}}{\mathrm{d}z}

p 의 원래 정의에서 다음 관계를 도출할 수 있습니다. 먼저 x에 대한 p 의 편도함수에 대해 다음을 얻습니다.

\frac{\partial p}{\partial x} = p(x, c')

여기서 c' 는 다음과 같이 정의합니다.

c'_i = (N-i)c_i

둘째, \vec{c} 에 대한 p 의 편미분에 대해 다음을 얻습니다.

\frac{\partial p}{\partial c_i} = p(x, \vec{d_i})

여기서 벡터 \vec{d_i} NxN 항등 행렬의 i^{th} 열입니다.

효율성을 높이기 위해서 모델리카 컴파일러가 \frac{\partial p}{\partial x} 그리고 \frac{\partial p}{\partial c_i} 를 해석하는 것 보다:math:frac{mathrm{d}x}{mathrm{d}z} \frac{\mathrm{d}\vec{c}}{\mathrm{d}z} 를 제공하는 것이 더 좋습니다. 따라서 수학적으로 말하면 모델리카 컴파일러에 필요한 것은 다음 인수로 호출되는 새로운 함수입니다.

df(x, \vec{c}, \frac{\mathrm{d}x}{\mathrm{d}z}, \frac{\mathrm{d}\vec{c}}{\mathrm{d}z})

다음과 같이:

df(x, \vec{c}, \frac{\mathrm{d}x}{\mathrm{d}z}, \frac{\mathrm{d}\vec{c}}{\mathrm{d}z}) = \frac{\mathrm{d}f}{\mathrm{d}z}

이러한 이유로 derivative 주석은 df 와 동일한 인수를 취하는 함수를 가리켜야 합니다. 이번 예제의 경우 PolynomialFirstDerivative 함수는 다음과 같이 정의합니다.

function PolynomialFirstDerivative
  "First derivative of the function Polynomial"
  input Real x;
  input Real c[:];
  input Real x_der;
  input Real c_der[size(c,1)];
  output Real y_der;
protected
  Integer n = size(c,1);
  Real c_diff[n-1] = {(n-i)*c[i] for i in 1:n-1};
algorithm
  y_der :=PolynomialWithDerivative(x, c_diff)*x_der +
          PolynomialWithDerivative(x, c_der);
end PolynomialFirstDerivative;

(예상한 대로)원래 함수의 인수가 반복되어 두 배의 인수를 생성하는 방식으로 구현되었음을 볼 수 있습니다.여기서 인수의 두 번째 집합은 \frac{\mathrm{d}x}{\mathrm{d}z} \frac{\mathrm{d}\vec{c}}{\mathrm{d}z} 의 수량을 나타내고, z 가 스칼라이므로 입력 인수의 자료형이 동일하다는 가정을 했습니다. 다항식의 편도함수에 대한 지식을 활용하여 다항식의 해석 기능의 결과인 파생값을 계산합니다.

다음 모델을 사용하여 이러한 모든 기능을 실행할 수 있습니다.

model Differentiation2 "Model that differentiates a function using derivative annotation"
  Real yf;
  Real yp;
  Real d_yf;
  Real d_yp;
equation
  yf = PolynomialWithDerivative(time, {1, -2, 2});
  yp = time^2-2*time+2;
  d_yf = der(yf);
  d_yp = der(yp);
end Differentiation2;

이 모델을 시뮬레이션하고 결과를 비교하면 yfyp, d_yfd_yp 사이의 결과가 일치함을 볼 수 있습니다.

/static/_images/Diff2.svg