- •Введение
- •1 Средства для решения задач нелинейных алгебраических уравнений в распределенной вычислительной среде
- •1.1 Понятие распределенных вычислений как способа решения трудоёмких вычислительных задач с использованием нескольких компьютеров
- •1.2 Распределенные вычисления на основе стека
- •1.3 Понятие клиент-серверных систем
- •1.4 Методы и их модификации для решения систем нелинейных уравнений
- •2 Алгоритмы и методы для решения нелинейных алгебраиеских уравнений на основе метода натуральных градиентов
- •2.1 Техническое задание для написания программы для решения систем нелинейных алгебраических уравнений методом натуральных градиентов
- •2.2 Aлгоритм метода натуральных градиентов
- •2.3 Алгоритмы линейного и распределенного решения
- •2.4 Алгоритм синтаксического анализатора, разработанного на основе обратной польской записи
- •2.5 Математическая модель распределенного вычисления Якобиана отображения
- •2.6 Описание основных функций клиент-серверного приложения
- •3 Программный комплекс для решени нелинейных алгебраических уравнений методом натуральных градиентов
- •3.1 Руководство пользователя
- •3.2 Результат исследование зависимости времени нахождения решения от размерности системы и способа решения
- •Заключение
- •Список использованных источников
- •Приложение а
- •Код сервеной части
- •Приложение б
- •Код клиенткой части
- •Приложение в
- •Данные из тестовых файлов
- •Приложение г
Приложение а
(обязательное)
Код сервеной части
using System;
using System.Xml;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
namespace server
{
public partial class MainForm : Form
{
// Количество неизвестных
private static int n;
// Список уравнений
private String[] Urav;
public MainForm()
{
InitializeComponent();
}
// Решение выражения выражения
// при помощи обратной польской записи
double solve (String s)
{
s=s.Trim();
double rez=0.0;
if (double.TryParse(s,out rez))
{
return rez;
}
if (String.IsNullOrEmpty(s))
{
return 0.0;
}
PostfixNotationExpression post=new PostfixNotationExpression();
return (double)post.result(s);
}
// Заменяем тригонометрические функции на вычисленные выражения
private void ChangeFun (ref String s, int numFun)
{
String[] funs=new String[] {"sin","cos","ctg","tg"}; // сначала ctg, потом tg обязательно!!!!!!!!!
String fun=funs[numFun];
// Избавляемся от sin cos tg ctg
int pos=-1;
while (s.IndexOf(fun)>=0)
{
pos=s.IndexOf(fun);
int i0=pos+1;
while(s[i0]!='(') i0++;
int j=i0+1;
int level=0;
while (s[j]!=')' || level>0) {
if (s[j]=='(') { level++; j++; } else
if (s[j]==')') level--; else j++;
}
int k=i0+1;
while (s[k]==' ') k++;
// от k до j-1
string part;
part=s.Substring(k,j-1-k+1).Trim();
// Убираем лишние скобки
if (part[0]=='(' && part[part.Length-1]==')')
{
part=part.Substring(1,part.Length-2);
}
// Решаем в скобках тригонометрической функции
double v0=solve(part);
// Вычисляем значение тригонометричекой функции
double v=0.0;
switch (numFun)
{
case 0: v=Math.Sin(v0); break;
case 1: v=Math.Cos(v0); break;
case 2: v=Math.Tan(v0); break;
case 3:
{
double t=Math.Tan(v0);
if (Math.Abs(t)<0.00000001) v=1000000000; else
v=1.0/t;
};
break;
};
// Вырезаем тригонометрическую функцию от pos до j
string replace=s.Substring(pos,j-pos+1);
double dd=Math.Round(v,6);
if (dd>100000000) dd=100000000;
// Заменяем функцию на вычисленное значение
s=s.Replace(replace,dd.ToString());
}
}
// Вычисляем производуню по j-ой переменной в i-ой функции
// Значение Якобиана [i,j]
double fYakobi (int i, int j, double[,] x)
{
// Простейшая формула численного дифференцирования
double h=0.0001;
double f2=func(Urav[i],x);
x[j,0]+=h;
double f1=func(Urav[i],x);
return (f1-f2)/h;
}
// Значение функции, записанной в строке
double func (String s,double[,] x)
{
// Добавляем знак (*) между, пример: x001x005 --> x001*x005
for (int j=0; j<=9; j++)
{
while (s.IndexOf(j.ToString()+"x")>=0)
{
s=s.Replace(j.ToString()+"x",j.ToString()+"*x");
}
}
// Заменяем
s=s.Replace(")c",")*c");
s=s.Replace(")s",")*s");
s=s.Replace(")t",")*t");
s=s.Replace(")(",")*(");
// Заменяем числами, пример x001*x005 --> 1.2*4.3
for (int j=0; j<x.Length; j++)
{
String num=(j+1).ToString();
while (num.Length<3) num="0"+num;
String ss=String.Format("{0:f8}",x[j,0]);
if (x[j,0]<0)
{
s=s.Replace("x"+num,"(0,000000001"+ss+")"); // отрицательное число ставим в скобках
}
else
{
s=s.Replace("x"+num,ss);
}
}
// Замена всех тригонометрических функций
for (int j=0; j<4; j++)
{
ChangeFun (ref s, j);
}
s=s.Trim();
s=s.Replace(" "," ");
String[] mas=s.Split(' ');
double val=0.0;
foreach (String member in mas)
{
val+=solve(member.Trim());
}
return val;
}
void MainFormLoad(object sender, EventArgs e)
{
}
// Перемножение матриц
void umn (int n, int m, int k, double[,] A, double[,] B, out double[,] Rez)
{
Rez=new double[n,k];
for (int i=0; i<n; i++)
{
for (int j=0; j<k; j++)
{
Rez[i,j]=0.0;
}
};
// По всем строкам матрицы A
for (int i=0; i<n; i++)
{
for (int j=0; j<k; j++) // По всем стоблцам матрицы B
{
for (int d=0; d<m; d++) // По всем элементам строки А и столбца В
{
Rez[i,j]+=A[i,d]*B[d,j];
};
};
};
}
// Транспонирование матрицы.
private static void transp (double[,] A,out double[,] Rez)
{
Rez=new double[n,n];
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
Rez[i,j]=A[j,i];
}
};
}
// Скаляр
private static double scal(int n, double[,] s1, double[,] s2)
{
double sc=0.0;
for (int i=0; i<n; i++)
{
sc+=s1[i,0]*s2[i,0];
}
return sc;
}
void Button1Click(object sender, EventArgs e)
{
if (n<=0)
{
MessageBox.Show("Откройте файл теста");
return;
}
double[,] x0=new double[n,1];
double[,] f0=new double[n,1];
double[,] w0=new double[n,n];
double[,] x1=new double[n,1];
double[,] f1=new double[n,1];
double[,] w1=new double[n,n];
double mu;
// Задаём приближения
for (int i=0; i<n; i++) x0[i,0]=0;
for(int i=0; i<n; i++)
{
f0[i,0]=func(Urav[i],x0);
}
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
w0[i,j]=fYakobi(i,j,x0);
}
}
mu=1.0;
double[,] wt0;
double[,] wf0;
transp(w0,out wt0);
umn(n,n,1,wt0,f0,out wf0);
listBox1.Items.Clear();
listBox2.Items.Clear();
// Проверка сходимости
bool test=false;
int numiter=0; // номер итерации расходимости
// Точность решения (по невязке)
double eps=float.Parse(EditE.Text);
// флаг нахождения решения
bool solveOK=false;
// Засекаем время
System.Diagnostics.Stopwatch sw = new Stopwatch();
sw.Start();
int iter=0; // КОличество итераций
int max=1000;
// Пока невязка большая или
// количество итераций не превышено допустимого
while(iter<max && !solveOK)
{
// Расчет и вывод промежуточного решения
String sx="";
for (int i=0; i<n; i++)
{
x1[i,0]=x0[i,0]-mu*wf0[i,0];
sx+=Math.Round(x1[i,0],3)+" ";
};
listBox2.Items.Add(iter+": "+sx);
// Расчет якобиана
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
w1[i,j]=fYakobi(i,j,x1);
}
}
// решение найдено
solveOK=true;
// Расчет и вывод невязки
String s="";
for(int i=0; i<n; i++)
{
f1[i,0]=func(Urav[i],x1);
solveOK=solveOK && (Math.Abs(f1[i,0]-f0[i,0])<eps);
if (Math.Abs(f1[i,0])>=Math.Abs(f0[i,0])+eps*10 && iter>5)
{
if (!test) numiter=iter;
test=true;
}
s+=Math.Round(f1[i,0],3)+ " ";
}
listBox1.Items.Add(iter+": "+s);
// Расчет mu
double[,] wt;
double[,] wf;
double[,] wwf;
transp(w1,out wt);
umn(n,n,1,wt,f1,out wf);
umn(n,n,1,w1,wf,out wwf);
mu=scal(n,f1,wwf)/scal(n,wwf,wwf);
for (int i=0; i<n; i++)
{
f0[i,0]=f1[i,0];
x0[i,0]=x1[i,0];
wf0[i,0]=wf[i,0];
for (int j=0; j<n; j++)
{
w0[i,j]=w1[i,j];
}
}
// Счетчик итераций
iter++;
}
sw.Stop();
label5.Text="Время работы: "+sw.ElapsedMilliseconds.ToString()+ "мс";
// Выделяем последние расчетные данные в списке
listBox1.SelectedIndex=listBox1.Items.Count-1;
listBox2.SelectedIndex=listBox2.Items.Count-1;
if (test)
{
label3.Text=" С итерации № "+numiter+" обнаружена расходимость.";
}
else
{
label3.Text="Приближенное решение найдено";
}
}
void ОткрытьТестToolStripMenuItemClick(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog()==DialogResult.OK)
{
// Загружаем
StreamReader sr=new StreamReader(openFileDialog1.FileName);
String txt=sr.ReadToEnd().Trim();
sr.Close();
//Замянем
txt=txt.Replace("\r\n","\n");
Urav=txt.Split('\n');
n=Urav.Length;
listBox3.Items.Clear();
foreach(String s in Urav)
listBox3.Items.Add(s);
}
}
void ФайлToolStripMenuItemClick(object sender, EventArgs e)
{
}
void Button2Click(object sender, EventArgs e)
{
if (n<=0)
{
MessageBox.Show("Откройте файл теста");
return;
}
XmlTextReader reader = new XmlTextReader ("ip_address.xml");
String[] ip=new String[2];
int num=0;
int[] port=new int[2];
int nom=0;
while (reader.Read())
{
if (reader.NodeType==XmlNodeType.Element && reader.Name.Equals("ip"))
{
reader.Read();
ip[num]=reader.Value;
num++;
}
if (reader.NodeType==XmlNodeType.Element && reader.Name.Equals("port"))
{
reader.Read();
port[nom]=int.Parse(reader.Value);
nom++;
}
}
IPHostEntry ipHost1 = Dns.GetHostEntry(ip[0]);
IPHostEntry ipHost2 = Dns.GetHostEntry(ip[1]);
IPAddress ipAddr1=ipHost1.AddressList[0];
IPAddress ipAddr2=ipHost2.AddressList[0];
// Посылаем размерность
byte[] ans=new byte[1];
byte[] sendByte=new byte[2];
sendByte[0]=0;
sendByte[1]=(byte)n;
SendMessageFromSocket(ipAddr1,port[0], sendByte, ref ans);
sendByte[0]=1;
SendMessageFromSocket(ipAddr2,port[1], sendByte, ref ans);
// Посылаем уравнения
for (int i=0; i<n; i++)
{
sendByte=Encoding.Unicode.GetBytes(Urav[i]);
SendMessageFromSocket(ipAddr1,port[0], sendByte, ref ans);
SendMessageFromSocket(ipAddr2,port[1], sendByte, ref ans);
}
double[,] x0=new double[n,1];
double[,] f0=new double[n,1];
double[,] w0=new double[n,n];
double[,] x1=new double[n,1];
double[,] f1=new double[n,1];
double[,] w1=new double[n,n];
double mu;
// Задаём приближения
for (int i=0; i<n; i++) x0[i,0]=0;
for(int i=0; i<n; i++)
{
f0[i,0]=func(Urav[i],x0);
}
for (int i=0; i<n; i++)
{
for (int j=0; j<n; j++)
{
w0[i,j]=fYakobi(i,j,x0);
}
}
mu=1.0;
double[,] wt0;
double[,] wf0;
transp(w0,out wt0);
umn(n,n,1,wt0,f0,out wf0);
listBox1.Items.Clear();
listBox2.Items.Clear();
// Проверка сходимости
bool test=false;
int numiter=0; // номер итерации расходимости
// Точность решения (по невязке)
double eps=float.Parse(EditE.Text);
// флаг нахождения решения
bool solveOK=false;
// Засекаем время
System.Diagnostics.Stopwatch sw = new Stopwatch();
sw.Start();
int iter=0; // КОличество итераций
int max=1000;
// Пока невязка большая или
// количество итераций не превышено допустимого
while(iter<max && !solveOK)
{
// Расчет и вывод промежуточного решения
String sx="";
for (int i=0; i<n; i++)
{
x1[i,0]=x0[i,0]-mu*wf0[i,0];
sx+=Math.Round(x1[i,0],3)+" ";
};
listBox2.Items.Add(iter+": "+sx);
// Расчет якобиана - Параллельно
// Посылаем x1 на оба компьютера
double[] mas=new double[n];
for (int v=0; v<n; v++) mas[v]=x1[v,0];
sendByte=new byte[mas.Length*8];
Buffer.BlockCopy(mas, 0, sendByte, 0, sendByte.Length);
SendMessageFromSocket(ipAddr1,port[0], sendByte, ref ans);
SendMessageFromSocket(ipAddr2,port[1], sendByte, ref ans);
// Получаем Якобиан по частям
int middle=n/2;
for (int i=0; i<middle; i++)
{
byte[] question=new byte[2];
question[0]=1;
question[1]=(byte)i;
byte[] getByte=new byte[sendByte.Length];
SendMessageFromSocket(ipAddr1,port[0], question, ref getByte);
for(int v = 0 ; v < n ; v++)
{
w1[i,v] = BitConverter.ToDouble(getByte, v * 8);
}
}
for (int i=middle; i<n; i++)
{
byte[] question=new byte[2];
question[0]=1;
question[1]=(byte)i;
byte[] getByte=new byte[sendByte.Length];
SendMessageFromSocket(ipAddr2,port[1], question, ref getByte);
for(int v = 0 ; v < n ; v++)
{
w1[i,v] = BitConverter.ToDouble(getByte, v * 8);
}
}
listBox3.Items.Add("Полученный Якобиан по частям:");
// Вывод Якобиана
for (int i=0; i<n; i++)
{
String s3="";
for (int j=0; j<n; j++)
{
s3+=Math.Round(w1[i,j],5)+" ";
}
listBox3.Items.Add(s3);
}
// решение найдено
solveOK=true;
// Расчет и вывод невязки
String s="";
for(int i=0; i<n; i++)
{
f1[i,0]=func(Urav[i],x1);
solveOK=solveOK && (Math.Abs(f1[i,0]-f0[i,0])<eps);
if (Math.Abs(f1[i,0])>=Math.Abs(f0[i,0])+eps*10 && iter>5)
{
if (!test) numiter=iter;
test=true;
}
s+=Math.Round(f1[i,0],3)+ " ";
}
listBox1.Items.Add(iter+": "+s);
// Расчет mu
double[,] wt;
double[,] wf;
double[,] wwf;
transp(w1,out wt);
umn(n,n,1,wt,f1,out wf);
umn(n,n,1,w1,wf,out wwf);
mu=scal(n,f1,wwf)/scal(n,wwf,wwf);
for (int i=0; i<n; i++)
{
f0[i,0]=f1[i,0];
x0[i,0]=x1[i,0];
wf0[i,0]=wf[i,0];
for (int j=0; j<n; j++)
{
w0[i,j]=w1[i,j];
}
}
// Счетчик итераций
iter++;
// Посылаем контрольный байт
byte[] ans3=new byte[1];
byte[] sendByte3=new byte[2];
if (iter<max && !solveOK)
sendByte3[0]=0; // 0 - продолжаем
else
sendByte3[0]=3; // 3 - конец
sendByte3[1]=0;
SendMessageFromSocket(ipAddr1,port[0], sendByte3, ref ans3);
SendMessageFromSocket(ipAddr2,port[1], sendByte3, ref ans3);
}
// посленяя запись
listBox3.SelectedIndex=listBox3.Items.Count-1;
sw.Stop();
label6.Text="Время работы: "+sw.ElapsedMilliseconds.ToString()+ "мс";
// Выделяем последние расчетные данные в списке
listBox1.SelectedIndex=listBox1.Items.Count-1;
listBox2.SelectedIndex=listBox2.Items.Count-1;
if (test)
{
label3.Text=" С итерации № "+numiter+" обнаружена расходимость.";
}
else
{
label3.Text="Приближенное решение найдено";
}
}
static void SendMessageFromSocket(IPAddress ipAddr, int port, byte[] sendBytes, ref byte[] getBytes)
{
// Соединяемся с удаленным устройством
// Устанавливаем удаленную точку для сокета
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, port);
Socket sender = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Соединяем сокет с удаленной точкой
sender.Connect(ipEndPoint);
// Отправляем данные через сокет
int bytesSent = sender.Send(sendBytes);
// Получаем ответ
int bytesRec = sender.Receive(getBytes);
// Освобождаем сокет
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
}
}