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

BТест метода дихотомии

1using NUnit.Framework;

2using System;

3

4namespace MathUtilities.Tests

5{

6

7

8

9

10

11

12

13

14

15

16

17

[TestFixture]

[TestOf(typeof(DichotomyOptimizer))] public class DichotomyOptimizerTest

{

[Test]

public void TestLeftParabola()

{

var o = new DichotomyOptimizer(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 DichotomyOptimizer(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 DichotomyOptimizer(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(Triplet))] public class TripletTest

16

46{

47[Test]

48[TestCase(1, 3, 2)]

49[TestCase(1, -1, 0)]

50[TestCase(-5, -3, -4)]

51public void TestCenter(double left, double right, double expected)

52{

53

var t =

new Triplet{A = left, B = right};

54

var got

= t.Center;

55

Assert.AreEqual(expected, got);

56}

57}

58}

17

CЛистинг кода метода золотого сечения

1using static System.Math;

2using System;

3

4namespace MathUtilities

5{

6/// <summary>

7/// Находит оптимум функции одной переменной при помощи метода золотого

,! сечения.

8/// </summary>

9public class GoldenOptimizer

10{

11/// <summary>

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

13/// </summary>

14private readonly Func<double, double> _function;

15

16

17

18

19

20

///<summary>

///Начало поиска.

///</summary>

private readonly double _start;

21

22

23

24

25

///<summary>

///Шаг поиска.

///</summary>

private readonly double _step;

26/// <summary>

27/// Точность поиска. Влияет на размер области поиска.

28/// </summary>

29private readonly double _precision;

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

///<summary>

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

///</summary>

private readonly uint _operationAmount;

///<summary>

///Смотрим ли максимум или минимум.

///</summary>

private readonly bool _lookingForMax;

///<summary>

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

///</summary>

private uint counter;

18

45

46/// <summary>

47/// Стандартный конструктор анализатора.

48/// </summary>

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

50/// <param name="start">точка начала поиска</param>

51/// <param name="step">шаг поиска</param>

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

53/// <param name="operationsAmount">максимальное количество

,! операций</param>

54/// <param name="lookingForMax">смотрим ли максимум или минимум</param>

55public GoldenOptimizer(

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

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

double step = 1E-02, double precision = 1E-04,

uint operationsAmount = 150, bool lookingForMax = false

) {

_function = function; _start = start;

//разворачивает шаг в нужную сторону

//учитывает max / min

_step = function(start + step) > function(start - step) ? lookingForMax ? step : -step

: lookingForMax ? -step : step;

_precision = precision; _operationAmount = operationsAmount; _lookingForMax = lookingForMax;

ResetCounter();

}

78/// <summary>

79/// Рассчитывает оптимальное значение функции.

80/// </summary>

81/// <returns>оптимальное значение функции</returns>

82public double GetOptimal()

83{

84

85

86

87

88

89

// узнаём область поиска var triplet = GetArea();

//если область поиска маленькая,

//не продолжать искать

while (!IsTooSmall(triplet))

{

19

90

// если количество операций превысило максимальное, выкинуть

 

,! ошибку

91

if (IsCountDown())

92

throw new ApplicationException("не удалось найти оптимального

 

,! решения");

93

 

94

95

96

// выбираем лучшую между левой и правой triplet = FindGood(triplet);

}

97

 

98

// всё равно передаём центральную точку

99

return triplet.A + (triplet.B - triplet.A) / 2;

100

}

101

 

102/// <summary>

103/// Рассчитывает область поиска или кидает исключение по превышении ,! количества операций.

104/// </summary>

105/// <returns>область поиска оптимума</returns>

106public GoldenTriplet GetArea()

107{

108

// записываем шаг

поиска

109

var step = _step;

 

110

// создаём тройку

с нуля

111

var triplet = new GoldenTriplet {A = _start, RightCenter = _start +

 

,! step};

 

112

// пока не найдём удачную тройку, ищем

113

while (!IsLucky(triplet))

114

{

 

115

// если количество операций превысило максимальное, кинуть

 

,! ошибку

 

116

117

if (IsCountDown())

throw new ApplicationException("не удалось найти область

,! поиска");

118

119

120

121

122

// двигаем провотиположную A сторону на количество шагов triplet.LeftCenter = triplet.B;

}

123

124

125

126

127

128

129

130

ResetCounter(); return triplet;

}

///<summary>

///Удачна ли тройка для этой функции.

///</summary>

///<remark>

20

131/// Учитывает настройку, какой параметр ищем: max / min.

132/// </remark>

133/// <param name="triplet">тройка</param>

134/// <returns>истина, если тройка удачная</returns>

135private bool IsLucky(GoldenTriplet triplet) =>

136

137

138

139

140

141

_lookingForMax

? _function(triplet.RightCenter) >= _function(triplet.A) && _function(triplet.RightCenter) >= _function(triplet.B)

: _function(triplet.RightCenter) <= _function(triplet.A) && _function(triplet.RightCenter) <= _function(triplet.B);

142/// <summary>

143/// Узнаёт, не мала ли тройка.

144/// </summary>

145/// <param name="triplet">тройка</param>

146/// <returns>истина, если тройка меньше точности поиска</returns>

147private bool IsTooSmall(GoldenTriplet triplet) =>

148

Abs(triplet.B - triplet.A) <= _precision;

149

150

151/// <summary>

152/// Выбирает из двух частей тройки лучшую.

153/// </summary>

154/// <remark>

155/// Учитывает настройку, какой параметр ищем: max / min.

156/// </remark>

157/// <param name="old">тройка для рассмотрения</param>

158/// <returns>новая тройка, оказавшаяся лучше</returns>

159private GoldenTriplet FindGood(GoldenTriplet old)

160{

161

if (_lookingForMax)

162

return _function(old.LeftCenter) > _function(old.RightCenter) ?

 

,! new GoldenTriplet {A = old.LeftCenter, B = old.B} : new

 

,! GoldenTriplet {A = old.A, B = old.RightCenter};

163

else

164

return _function(old.LeftCenter) < _function(old.RightCenter) ?

 

,! new GoldenTriplet {A = old.A, B = old.RightCenter} : new

 

,! GoldenTriplet {A = old.LeftCenter, B = old.B};

165

}

166

 

167/// <summary>

168/// Увеличивает счётчик на 1 и передаёт, не превысило ли количество ,! операций максимальное.

169/// </summary>

170/// <returns>истина, если количество операций превысило

,! максимальное</returns>

171 private bool IsCountDown() =>

21

172

counter++ > _operationAmount;

173

 

174

/// <summary>

175

/// Сбрасывает счётчик.

176

/// </summary>

177

private void ResetCounter() =>

178

counter = 0;

179

}

180

181/// <summary>

182/// Тройка с золотым сечением.

183/// </summary>

184public class GoldenTriplet

185{

186/// <summary>

187/// Золотое число. 1 - (\sqrt(5) - 1) / 2

188/// </summary>

189public const double SmallGolden = 0.3819660113;

190

191/// <summary>

192/// Золотое число. (\sqrt(5) - 1) / 2

193/// </summary>

194public const double Golden = 0.6180339887;

195

196/// <summary>

197/// Золотое число. (\sqrt(5) + 1) / 2

198/// </summary>

199public const double BigGolden = 1.6180339887;

200

201

202

203

204

205

///<summary>

///Левая часть тройки.

///</summary>

public double A { get; set; }

206

207

208

209

210

///<summary>

///Правая часть тройки.

///</summary>

public double B { get; set; }

211/// <summary>

212/// Центральная часть тройки ближе к правому краю.

213///

214/// Сеттер на самом деле устанавливает правую часть.

215/// </summary>

216/// <remark>

217/// Золотое сечение.

218/// </remark>

22

219public double RightCenter { get => A + (B - A) * Golden; set => B = value ,! * BigGolden - A * Golden; }

220

221/// <summary>

222/// Центральная часть тройки ближе к левому краю.

223/// </summary>

224/// <remark>

225/// Золотое сечение.

226/// </remark>

227public double LeftCenter { get => B - (B - A) * Golden; set => B = value

,! + BigGolden * (value - A); }

228

 

229

public override string ToString() =>

230

$"{A} - {LeftCenter} - {RightCenter} - {B}";

231}

232}

23