using System; using System.Windows.Forms; namespace lab06 { public partial class MainForm : Form { #region Methods public MainForm( ) { InitializeComponent( ); } void bSolve_Click( object sender, EventArgs e ) { try { MathFunctionDelegate of = delegate( double[ ] args ) { return -args[ 0 ] * args[ 0 ] * args[ 0 ]; }; MathFunctionDelegate[ ] c = { delegate( double[ ] args ) { return args[ 0 ] - 1; } }; PenaltyFunctionMethod pfm = new PenaltyFunctionMethod( of, c, 1, 1e-4 ); pfm.Solve( PenaltyFunctionMethod.PenaltyFunctionType.Function3, new double[ ] { 5 } ); tbSolvingLog.Text = pfm.GetSolve; } catch ( Exception exception ) { MessageBox.Show( String.Format( "Message:\r\n{0}\r\n\r\nStackTrace:\r\n{1}", exception.Message, exception.StackTrace ), "Error" ); } } #endregion } } using System; using System.Collections.Generic; using System.Text; namespace lab06 { public class PenaltyFunctionMethod { private MathFunctionDelegate ObjectiveFunction; private MathFunctionDelegate[ ] Constraints; private MathFunctionDelegate PenaltyFunction; private int NumberOfVariables; private double Epsilon; private double C; private List Solutions; private List Parameters; public PenaltyFunctionMethod( MathFunctionDelegate ObjectiveFunction, MathFunctionDelegate[ ] Constraints, int NumberOfVariables, double Epsilon ) { this.ObjectiveFunction = ObjectiveFunction; this.Constraints = Constraints; this.NumberOfVariables = NumberOfVariables; this.Epsilon = Epsilon; C = 10; } private double PenaltyFunction1( double[ ] args ) { double sum = 0; for ( int i = 0; i < Constraints.Length; i++ ) { sum += Math.Pow( Math.Max( 0, Constraints[ i ]( args ) ), 2 ); } return C * sum; } private double PenaltyFunction3( double[ ] args ) { double sum = 0; for ( int i = 0; i < Constraints.Length; i++ ) { sum += Math.Exp(C*Constraints[i](args)); } return sum; } private double PenaltyFunction4( double[ ] args ) { double sum = 0; for ( int i = 0; i < Constraints.Length; i++ ) { if ( Constraints[ i ]( args ) < 0 ) { sum += 1 / Constraints[ i ]( args ); } else { return 1e20; } } return -sum / C; } private double Function( double[ ] args ) { return ObjectiveFunction( args ) + PenaltyFunction( args ); } public void Solve( PenaltyFunctionType penaltyFunctionType, double[] x0 ) { switch ( penaltyFunctionType ) { case PenaltyFunctionType.Function1: PenaltyFunction = PenaltyFunction1; break; case PenaltyFunctionType.Function3: PenaltyFunction = PenaltyFunction3; break; case PenaltyFunctionType.Function4: PenaltyFunction = PenaltyFunction4; break; default: break; } Solutions = new List( ); Parameters = new List( ); double[ ] firstSolution = x0; Solutions.Add( firstSolution ); Parameters.Add( C ); double penaltyFunctionResult; do { C *= 2; double[ ] solution = FunctionMinimization.HookeJeevesMethod( Function, Solutions[ Solutions.Count - 1 ], Epsilon, 1, 1.5 ); Solutions.Add( solution ); Parameters.Add( C ); penaltyFunctionResult = PenaltyFunction( solution ); } while ( penaltyFunctionResult > Epsilon ); } public string GetSolve { get { StringBuilder SB = new StringBuilder( ); SB.AppendFormat( "ε = {0}\r\n\r\n", Epsilon ); for ( int i = 0; i < Solutions.Count; i++ ) { SB.Append( "X = [" ); for ( int j = 0; j < Solutions[i].Length; j++ ) { if ( j < Solutions[ i ].Length - 1 ) { SB.AppendFormat( "{0}, ", Math.Round(Solutions[ i ][ j ],3) ); } else { SB.AppendFormat( "{0}", Math.Round( Solutions[ i ][ j ], 3 ) ); } } //SB.AppendLine("] C = " + Parameters[i].ToString() ); SB.AppendLine( "]" ); } return SB.ToString( ); } } public enum PenaltyFunctionType { Function1, Function3, Function4 } } public static class FunctionMinimization { static List Solves; static double Epsilon; static double Step; static double AcceleratingMultiplier; static Vector[ ] Directions; static int IterationsLimit; static FunctionMinimization( ) { Solves = new List( ); IterationsLimit = 5000; } public static double[ ] HookeJeevesMethod( MathFunctionDelegate Function, double[ ] firstX, double epsilon, double stepValue, double acceleratingMultiplier ) { #region Initialize Solves.Add( new Vector( firstX ) ); Epsilon = epsilon; Step = stepValue; AcceleratingMultiplier = acceleratingMultiplier; Directions = new Vector[ firstX.Length ]; for ( int i = 0; i < Directions.Length; i++ ) { double[ ] v = new double[ Directions.Length ]; v[ i ] = 1; Directions[ i ] = new Vector( v ); } #endregion #region Solve int n = Solves[ 0 ].GetLength; Vector Y = ( Vector ) Solves[ 0 ].Clone( ); int counter = 0; while ( counter < IterationsLimit ) { for ( int i = 0; i < n; i++ ) { if ( Function( ( Y + Step * Directions[ i ] ).PGetDoubleArray ) < Function( Y.PGetDoubleArray ) ) { Y = Y + Step * Directions[ i ]; } else { if ( Function( ( Y - Step * Directions[ i ] ).PGetDoubleArray ) < Function( Y.PGetDoubleArray ) ) { Y = Y - Step * Directions[ i ]; } } } if ( Function( Y.PGetDoubleArray ) < Function( Solves[ Solves.Count - 1 ].PGetDoubleArray ) ) { Solves.Add( ( Vector ) Y.Clone( ) ); Y = Solves[ Solves.Count - 1 ] + AcceleratingMultiplier * ( Solves[ Solves.Count - 1 ] - Solves[ Solves.Count - 2 ] ); } else { if ( Step <= Epsilon ) { break; } else { Step /= 2; Y = ( Vector ) Solves[ Solves.Count - 1 ].Clone( ); } } ++counter; } if ( counter == IterationsLimit ) { System.Windows.Forms.MessageBox.Show( "Поиск потребовал " + IterationsLimit.ToString( ) + " итераций, требуемая точность возможно не была достигнута.", "Attention!" ); } #endregion return Solves[ Solves.Count - 1 ].PGetDoubleArray; } } public delegate double MathFunctionDelegate( double[ ] args ); class Vector : ICloneable { #region Fields private double[ ] FItems; #endregion #region Properties public double this[ int pos ] { get { if ( pos >= this.GetLength || pos < 0 ) { throw new IndexOutOfRangeException( "Out of Range!" ); } else { return FItems[ pos ]; } } } public int GetLength { get { return FItems.Length; } } public double[ ] PGetDoubleArray { get { return FItems; } } #endregion #region Constructors public Vector( params double[ ] AItems ) { FItems = AItems; } #endregion #region Methods public object Clone( ) { return new Vector( ( double[ ] ) this.FItems.Clone( ) ); } #endregion #region Define operators public static Vector operator +( Vector V1, Vector V2 ) { double[ ] newValues = new double[ V1.GetLength ]; if ( V1.GetLength != V2.GetLength ) { throw new ArgumentException( "Vectors have different length!" ); } else { for ( int i = 0; i < newValues.Length; i++ ) { newValues[ i ] = V1[ i ] + V2[ i ]; } return new Vector( newValues ); } } public static Vector operator -( Vector V1, Vector V2 ) { double[ ] newValues = new double[ V1.GetLength ]; if ( V1.GetLength != V2.GetLength ) { throw new ArgumentException( "Vectors have different length!" ); } else { for ( int i = 0; i < newValues.Length; i++ ) { newValues[ i ] = V1[ i ] - V2[ i ]; } return new Vector( newValues ); } } public static Vector operator -( Vector V1 ) { double[ ] newValues = new double[ V1.GetLength ]; for ( int i = 0; i < newValues.Length; i++ ) { newValues[ i ] = -V1[ i ]; } return new Vector( newValues ); } public static double operator *( Vector V1, Vector V2 ) { double result = 0; if ( V1.GetLength != V2.GetLength ) { throw new ArgumentException( "Vectors have different length!" ); } else { for ( int i = 0; i < V1.GetLength; i++ ) { result += V1[ i ] * V2[ i ]; } return result; } } public static Vector operator *( double K, Vector V ) { double[ ] newValues = new double[ V.GetLength ]; for ( int i = 0; i < newValues.Length; i++ ) { newValues[ i ] = K * V[ i ]; } return new Vector( newValues ); } #endregion } }