Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа 3. 6 вар. Трофимов-2019.pdf
Скачиваний:
190
Добавлен:
19.02.2020
Размер:
119.22 Кб
Скачать

DТест метода золотого сечения

1using System;

2using NUnit.Framework;

3

4namespace MathUtilities.Tests

5{

6

7

8

9

10

11

12

13

14

15

16

17

[TestFixture]

[TestOf(typeof(GoldenOptimizer))] public class GoldenOptimizerTest

{

[Test]

public void TestLeftParabola()

{

var o = new GoldenOptimizer(LeftParabola); var got = o.GetOptimal(); Assert.AreEqual(-1, got, 1E-04);

}

18

19

20

21

22

23

24

25

[Test]

public void TestParabola()

{

var o = new GoldenOptimizer(Parabola, start: 1); var got = o.GetOptimal();

Assert.AreEqual(0, got, 1E-04);

}

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

[Test]

public void TestAreaNotFound()

{

var o = new GoldenOptimizer(Line); Assert.Catch<ApplicationException>(() => o.GetOptimal());

}

private double LeftParabola(double x) => x * x + 2 * x + 1;

private double Parabola(double x) => x * x;

private double Line(double x) => 2 * x;

}

[TestFixture]

[TestOf(typeof(GoldenTriplet))] public class GoldenTripletTest

{

24

46[Test]

47[TestCase(0, 1, 0.61803)]

48[TestCase(0, 10, 6.1803)]

49[TestCase(0, -10, -6.1803)]

50public void TestRightCenter(double left, double right, double expected)

51{

52

var t = new GoldenTriplet{A = left, B = right};

53

var got = t.RightCenter;

54

Assert.AreEqual(expected, got, 1E-03);

55

}

56

57[Test]

58[TestCase(0, 1, 0.3819)]

59[TestCase(0, 10, 3.8196)]

60[TestCase(0, -10, -3.8196)]

61public void TestLeftCenter(double left, double right, double expected)

62{

63

var t = new GoldenTriplet{A = left, B = right};

64

var got = t.LeftCenter;

65

Assert.AreEqual(expected, got, 1E-03);

66

}

67

68[Test]

69[TestCase(0, 0.61803, 1)]

70[TestCase(0, 6.1803, 10)]

71[TestCase(0, -6.1803, -10)]

72public void TestRightFromRightCenter(double left, double rightCenter, ,! double expected)

73{

74

var t = new GoldenTriplet{A = left, RightCenter = rightCenter};

75

var got = t.B;

76

Assert.AreEqual(expected, got, 1E-03);

77

}

78

79[Test]

80[TestCase(0, 0.3819, 1)]

81[TestCase(0, 3.8196, 10)]

82[TestCase(0, -3.8196, -10)]

83public void TestRightFromLeftCenter(double left, double leftCenter, ,! double expected)

84{

85

var t =

new GoldenTriplet{A = left, LeftCenter = leftCenter};

86

var got

= t.B;

87

Assert.AreEqual(expected, got, 1E-03);

88}

89}

90}

25

EЛистинг кода метода Ньютона

1using static System.Math;

2using System;

3

4namespace MathUtilities

5{

6

7

8

9

///<summary>

///Класс для одномерной оптимизации методом Ньютона.

///</summary>

public class NewtonOptimizer

10{

11/// <summary>

12/// Функция для исследования.

13/// </summary>

14private readonly Func<double, double> _function;

15

16/// <summary>

17/// Класс для нахождения производной, градиента и Гессиана.

18/// </summary>

19private readonly Derivative _derivative;

20

21

22

23

24

25

///<summary>

///Начальный вектор поиска.

///</summary>

private readonly double _start;

26

27

28

29

30

///<summary>

///Точность поиска.

///</summary>

private readonly double _precision;

31

32

33

34

35

///<summary>

///Максимальное количество итераций.

///</summary>

private readonly int _operationsAmount;

36

37

38

39

40

///<summary>

///Счётчик операций.

///</summary>

private int counter;

41/// <summary>

42/// Стандартный конструктор

43/// </summary>

44/// <param name="function">функция для исследования</param>

45/// <param name="start">начальный вектор</param>

26

46/// <param name="precision">точность поиска</param>

47/// <param name="operationsAmount">максимальное количество ,! итераций</param>

48public NewtonOptimizer(

49

50

51

52

53

54

55

56

57

58

59

60

61

62

Func<double, double> function, double start = 0,

double precision = 1E-08, int operationsAmount = 15

) {

_function = function;

_derivative = new Derivative(function); _start = start;

_precision = precision; _operationsAmount = operationsAmount;

ResetCounter();

}

63/// <summary>

64/// Рассчитывает точку, в которой функция имеет минимум.

65/// </summary>

66public double GetOptimal()

67{

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

// считаем производную

var derivative = _derivative.GetDerivative(_start);

// считаем вторую производную

var secDerivative = _derivative.GetSecondDerivative(_start);

// считаем текущий вектор по формуле

var current = _start - derivative / secDerivative;

// пока разница между значениями не станет меньше заданного while (!Math.Equals(derivative, 0))

{

//если операций не больше максимального if (IsCountDown())

throw new ApplicationException("не нашлось решения");

//рассчитать производную в текущей точке

derivative = _derivative.GetDerivative(current);

// считаем вторую производную

secDerivative = _derivative.GetSecondDerivative(current);

// считаем текущий вектор по формуле

current = current - derivative / secDerivative;

}

89

// вернуть найденный вектор

90

return current;

91

}

27

92

93/// <summary>

94/// Не превысило ли количество операций максимальное.

95/// </summary>

96private bool IsCountDown() =>

97

counter++ > _operationsAmount;

98

 

99

100

101

102

103

104

///<summary>

///Обнуляет количество проделанных операций.

///</summary>

private void ResetCounter() => counter = 0;

105/// <summary>

106/// Проверяет, является ли новое решение слишком близким.

107/// </summary>

108/// <param name="previous">старое решение</param>

109/// <param name="current">текущее решение</param>

110/// <returns>истина, если решения находятся близко друг к ,! другу</returns>

111private bool IsTooSmall(double previous, double current) =>

112

Abs(_function(current) - _function(previous)) < _precision;

113

}

114

115/// <summary>

116/// Класс для численного дифференцирования.

117/// </summary>

118public class Derivative

119{

120/// <summary>

121/// Функция для дифференцирования.

122/// </summary>

123private readonly Func<double, double> _function;

124

125/// <summary>

126/// Стандартный конструктор для дифференцирования.

127/// </summary>

128/// <param name="function">функция для дифференцирования</param>

129public Derivative(Func<double, double> function) =>

130

131

_function = function;

132/// <summary>

133/// Рассчитывает обычную производную по одному аргументу.

134/// </summary>

135/// <param name="point">точка, в которой рассчитывается

,! производная</param>

136 /// <returns>значение производной в точке</returns>

28

137

138

139

140

141

142

143

144

public double GetDerivative(double point)

{

var eps = Math.MinimalTenPower(point); var left = _function(point + eps);

var right = _function(point - eps); return (left - right) / (2 * eps);

}

145/// <summary>

146/// Рассчитывает обычную вторую производную по одному аргументу.

147/// </summary>

148/// <param name="point">точка, в которой рассчитывается

,! производная</param>

149/// <returns>значение второй производной в точке</returns>

150public double GetSecondDerivative(double point)

151{

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

var eps = Math.MinimalTenPower(point); var left = _function(point + 2 * eps); var right = _function(point - 2 * eps);

return (left + right - 2 * _function(point)) / (4 * eps * eps);

}

}

///<summary>

///Отдельные специальные вычисления.

///</summary>

public static class Math

{

///<summary>

///Количество значащих цифр для сравнения.

///</summary>

public const int TYPICAL_POWER = 5;

169

170

171

172

173

174

175

176

177

178

179

180

181

182

///<summary>

///Примерно сравнивает числа.

///</summary>

///<param name="a">одно число</param>

///<param name="b">другое число</param>

///<returns>истина, если числа равны хотя бы

///до -5 знака после значащей цифры</returns>

public static bool Equals(double a, double b)

{

var minimalTenPower = Max(MinimalTenPower(a), MinimalTenPower(b)); if (Abs(a - b) < minimalTenPower)

return true;

return false;

29

183

}

184

185/// <summary>

186/// Передаёт минимальное количество значащих цифр от 0 до 15.

187/// </summary>

188/// <remark>

189/// Не работает для чисел \in (1; 10).

190/// </remark>

191/// <param name="n">число</param>

192/// <param name="restrict15">использовать ограничение на 15 цифр; ,! по-умолчанию - истина</param>

193/// <returns>минимальное количество значащих цифр</returns>

194public static int MinimalPower(double n, bool restrict15 = true)

195{

196

197

if (n == 0) return TYPICAL_POWER;

198

// модулируем

199

var absolute = Abs(n);

200

// находим оригинальную степень

201

var power = Log10(absolute);

202

// убираем знаки после запятой

203

var rounded = Round(power);

204

// новая степень десятки - количество значащих цифр;

205

// удаляем минус из количества цифр

206

var answer = (int) Abs(rounded - TYPICAL_POWER);

207

// избавляемся от чисел, меньше 1E-15 или больше 1E+15

208

answer = restrict15 && answer > 15 ? 15 : answer;

209

 

210

return answer;

211

}

212

 

213/// <summary>

214/// Передаёт минимальную степень десятки, соответствующую минимальному ,! количеству значащих цифр.

215/// </summary>

216/// <remark>

217/// Не работает для чисел \in (1; 10).

218/// </remark>

219/// <param name="n">число</param>

220/// <returns>минимальная степень десятки, соответствующая минимальному ,! количеству значащих цифр</returns>

221public static double MinimalTenPower(double n) =>

222

Pow(10, -1 * MinimalPower(n));

223}

224}

30