Advertisement
skelantros

Wat

Jun 2nd, 2021
1,014
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 6.85 KB | None | 0 0
  1. // реализация обобщенной составной ИКФ
  2. trait IntegralMethod {
  3.   // "шаг": ИКФ на заданном отрезке
  4.   def methodStep(x1 : Double, x2: Double): Double
  5.  
  6.   // АСТ метода (3 для Ньютона-Котса, 5 для Гаусса)
  7.   def m: Int
  8.  
  9.   // составная ИКФ с заданным шагом step на отрезке [x1; x2]
  10.   def method(x1: Double, x2: Double, step: Double): Double = {
  11.     var curX = x1
  12.     var result = 0.0
  13.     while(curX + step < x2) {
  14.       result += methodStep(curX, curX + step)
  15.       curX += step
  16.     }
  17.     result + methodStep(curX, x2)
  18.   }
  19.  
  20.   // поиск оптимального шага на двух исходных шагах step1 и step2
  21.   def optimalStep(epsilon: Double, step1: Double, step2: Double): Double = {
  22.     val s1 = method(a, b, step1) // значение интеграла при шаге step1
  23.     val s2 = method(a, b, step2) // при шаге step2
  24.     val error = rungeError(s1, s2, step1 / step2)
  25.     // вычисление оптимального шага по формуле из методички
  26.     step2 * pow(epsilon / error, 1.0 / m)
  27.   }
  28.  
  29.   // ошибка по Рунге (см. методичку)
  30.   def rungeError(s1: Double, s2: Double, L: Double): Double = abs((s2 - s1) / pow(L, m))
  31.  
  32.   // вычисление интеграла с точностью epsilon, исходным шагом initStep и уменьшением шага в L раз
  33.   // метод возвращает результат, оптимальный шаг и число итераций (последнее хз, зачем, это необязательно вроде)
  34.   def apply(epsilon: Double, initStep: Double, L: Double): (Double, Double, Int) = {
  35.     var curValue = method(a, b, initStep)
  36.     var prevValue = 0.0
  37.     var curStep = initStep / L
  38.     var iterations = 0
  39.     do {
  40.       prevValue = curValue
  41.       curValue = method(a, b, curStep)
  42.       curStep /= L
  43.       iterations += 1
  44.     } while(rungeError(prevValue, curValue, L) > epsilon) // цикл продолжается, пока ошибка по Рунге больше epsilon
  45.     (curValue, curStep * L, iterations)
  46.   }
  47. }
  48.  
  49.  
  50. // Ньютон-Котс
  51. object NewtonCatsMethod extends IntegralMethod {
  52.   // АСТ == 3
  53.   override val m: Int = 3
  54.  
  55.   def newtonMoments(x1: Double, x2: Double): (Double, Double, Double) = (newM0(x1, x2), newM1(x1, x2), newM2(x1, x2))
  56.  
  57.   override def methodStep(x1: Double, x2: Double): Double = {
  58.     val (m0, m1, m2) = newtonMoments(x1, x2)
  59.     val xMid = (x1 + x2) / 2
  60.     val A1 = (m2 - m1 * (xMid + x2) + m0 * xMid * x2) / (xMid - x1) / (x2 - x1)
  61.     val A2 = -(m2 - m1 * (x1 + x2) + m0 * x1 * x2) / (xMid - x1) / (x2 - xMid)
  62.     val A3 = (m2 - m1 * (xMid + x1) + m0 * xMid * x1) / (x2 - xMid) / (x2 - x1)
  63.     A1 * f(x1) + A2 * f(xMid) + A3 * f(x2)
  64.   }
  65. }
  66.  
  67. // Гаусс
  68. object GaussMethod extends IntegralMethod {
  69.   type GaussMoments = (Double, Double, Double, Double, Double, Double)
  70.   val solver = new LaguerreSolver
  71.  
  72.   // АСТ == 6
  73.   override val m: Int = 6
  74.  
  75.   def gaussMoments(x1: Double, x2: Double): GaussMoments =
  76.     (newM0(x1, x2), newM1(x1, x2), newM2(x1, x2), newM3(x1, x2), newM4(x1, x2), newM5(x1, x2))
  77.  
  78.   // решение кубического уравнения (в numpy вроде есть функция типа np.roots или np.solve для этого)
  79.   def solveCubicEquation(a0: Double, a1: Double, a2: Double, a3: Double): (Double, Double, Double) = {
  80.     val coeffs = Array(a3,a2,a1,a0)
  81.     val roots = solver.solveAllComplex(coeffs, 0)
  82.     assert(roots.forall(_.getImaginary == 0))
  83.     val Array(r1, r2, r3) = roots.map(_.getReal)
  84.     (r1,r2,r3)
  85.   }
  86.  
  87.   // поиск необходимых коэффициентов (см. методичку)
  88.   def findPolyCoeffs(x1: Double, x2: Double): (Double, Double, Double) = {
  89.     val (m0,m1,m2,m3,m4,m5) = gaussMoments(x1, x2)
  90.     val col = new ColumnMatrix(Array(-m3,-m4,-m5))
  91.     val matrix: SquareMatrix =
  92.       m0 c m1 c m2 r
  93.       m1 c m2 c m3 r
  94.       m2 c m3 c m4
  95.     val solution = SLAEUtils.solveNonDegSLAE(matrix, col)
  96.     (solution(0), solution(1), solution(2))
  97.   }
  98.  
  99.   // поиск коэффициентов, необходимых для вычисления интеграла (см. методичку)
  100.   def findCoeffs(x1: Double, x2: Double): ((Double, Double, Double), (Double, Double, Double)) = {
  101.     val (a0, a1, a2) = findPolyCoeffs(x1, x2)
  102.     val (r1, r2, r3) = solveCubicEquation(1, a2, a1, a0)
  103.     val (m0, m1, m2, _, _, _) = gaussMoments(x1, x2)
  104.     val col = new ColumnMatrix(Array(m0,m1,m2))
  105.     val matrix: SquareMatrix =
  106.       1         c   1         c   1       r
  107.       r1        c   r2        c   r3      r
  108.       r1 * r1   c   r2 * r2   c   r3 * r3
  109.     val sol = SLAEUtils.solveNonDegSLAE(matrix, col)
  110.     ((sol(0), sol(1), sol(2)), (r1, r2, r3))
  111.   }
  112.  
  113.   override def methodStep(x1: Double, x2: Double): Double = {
  114.     val ((a1, a2, a3), (r1, r2, r3)) = findCoeffs(x1, x2)
  115.     a1 * f(r1) + a2 * f(r2) + a3 * f(r3)
  116.   }
  117. }
  118.  
  119. // ...
  120.  
  121. // вспомогательные штучки
  122. object TaskFunctions {
  123.   def f(x: Double) = ...
  124.   val a = ...
  125.   val b = ...
  126.   val alpha = ...
  127.   val beta = ...
  128.  
  129.   val exactResult = ...
  130.  
  131.   // моменты порядков от 0 до 5 включительно, для случая, когда beta = 0, alpha != 0
  132.   // если у тебя beta != 0, alpha = 0, можно либо вывести как-нибудь их аналогично,
  133.   // либо посчитать интегралы руками,
  134.   // либо своровать у кого-нибудь (:
  135.   def newM0(x1: Double, x2: Double): Double =
  136.     (pow(x2 - a, 1 - alpha) - pow(x1 - a, 1 - alpha)) / (1 - alpha)
  137.   def newM1(x1: Double, x2: Double): Double =
  138.     (pow(x2 - a, 2 - alpha) - pow(x1 - a, 2 - alpha)) / (2 - alpha) + a * newM0(x1, x2)
  139.   def newM2(x1: Double, x2: Double): Double =
  140.     (pow(x2 - a, 3 - alpha) - pow(x1 - a, 3 - alpha)) / (3 - alpha) + 2 * a * newM1(x1, x2) - a * a * newM0(x1, x2)
  141.   def newM3(x1: Double, x2: Double): Double =
  142.     (pow(x2 - a, 4 - alpha) - pow(x1 - a, 4 - alpha)) / (4 - alpha) + 3 * a * newM2(x1, x2) - 3 * a * a * newM1(x1, x2) + pow(a,3) * newM0(x1, x2)
  143.   def newM4(x1: Double, x2: Double): Double =
  144.     (pow(x2 - a, 5 - alpha) - pow(x1 - a, 5 - alpha)) / (5 - alpha) + 4 * a * newM3(x1, x2) - 6 * a * a * newM2(x1, x2) + 4 * pow(a,3) * newM1(x1, x2) - pow(a, 4) * newM0(x1, x2)
  145.   def newM5(x1: Double, x2: Double): Double =
  146.     (pow(x2 - a, 6 - alpha) - pow(x1 - a, 6 - alpha)) / (6 - alpha) +
  147.     5 * a * newM4(x1, x2) - 10 * a * a * newM3(x1, x2) + 10 * a * a * a * newM2(x1, x2) -
  148.     5 * a * a * a * a * newM1(x1, x2) + a * a * a * a * a * newM0(x1, x2)
  149.  
  150.  
  151.   def newtonMoments(x1: Double, x2: Double): (Double, Double, Double) = (newM0(x1, x2), newM1(x1, x2), newM2(x1, x2))
  152. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement