@@ -21,7 +21,7 @@ public static partial class MultiFunctionMath {
2121 /// <returns>The solution, including the final value of the functions and their derivatives.</returns>
2222 /// <remarks>
2323 /// <para>For information on integrating coupled, conservative ODEs, see
24- /// <see cref="IntegrateConservativeOde(Func{double, IList {double}, IList {double}}, double, IList {double}, IList {double}, double, MultiOdeSettings)"/>.</para>
24+ /// <see cref="IntegrateConservativeOde(Func{double, IReadOnlyList {double}, IReadOnlyList {double}}, double, IReadOnlyList {double}, IReadOnlyList {double}, double, MultiOdeSettings)"/>.</para>
2525 /// <para>This overload uses default settings for precision and evaluation budget. It targets a relative precision of
2626 /// about 10<sup>-12</sup> and an absolute precision of about 10<sup>-24</sup> with an evaluation budget of about 8000.
2727 /// </para>
@@ -32,7 +32,7 @@ public static partial class MultiFunctionMath {
3232 /// dimension.</exception>
3333 /// <exception cref="NonconvergenceException">The ODE could not be integrated to the required precision before exhausting
3434 /// the maximum allowed number of <paramref name="rhs"/>evaluations.</exception>
35- public static MultiOdeResult IntegrateConservativeOde ( Func < double , IList < double > , IList < double > > rhs , double x0 , IList < double > y0 , IList < double > yPrime0 , double x1 ) {
35+ public static MultiOdeResult IntegrateConservativeOde ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x0 , IReadOnlyList < double > y0 , IReadOnlyList < double > yPrime0 , double x1 ) {
3636 return ( IntegrateConservativeOde ( rhs , x0 , y0 , yPrime0 , x1 , new MultiOdeSettings ( ) ) ) ;
3737 }
3838
@@ -55,7 +55,7 @@ public static MultiOdeResult IntegrateConservativeOde (Func<double, IList<double
5555 /// <remarks>
5656 /// <para>For information on conservative ODEs, see <see cref="FunctionMath.IntegrateConservativeOde(Func{double, double, double}, double, double, double, double, OdeSettings)"/>.</para>
5757 /// </remarks>
58- public static MultiOdeResult IntegrateConservativeOde ( Func < double , IList < double > , IList < double > > rhs , double x0 , IList < double > y0 , IList < double > yPrime0 , double x1 , MultiOdeSettings settings ) {
58+ public static MultiOdeResult IntegrateConservativeOde ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x0 , IReadOnlyList < double > y0 , IReadOnlyList < double > yPrime0 , double x1 , MultiOdeSettings settings ) {
5959
6060 if ( rhs == null ) throw new ArgumentNullException ( nameof ( rhs ) ) ;
6161 if ( y0 == null ) throw new ArgumentNullException ( nameof ( y0 ) ) ;
@@ -86,12 +86,12 @@ public static MultiOdeResult IntegrateConservativeOde (Func<double, IList<double
8686 /// the maximum allowed number of <paramref name="rhs"/> evaluations.</exception>
8787 /// <remarks>
8888 /// <para>For information about integrating coupled ODEs, see
89- /// <see cref="IntegrateOde(Func{double, IList {double}, IList {double}}, double, IList {double}, double, MultiOdeSettings)"/>.</para>
89+ /// <see cref="IntegrateOde(Func{double, IReadOnlyList {double}, IReadOnlyList {double}}, double, IReadOnlyList {double}, double, MultiOdeSettings)"/>.</para>
9090 /// <para>This overload uses default settings for precision and evaluation budget. It targets a relative precision of
9191 /// about 10<sup>-12</sup> and an absolute precision of about 10<sup>-24</sup> with an evaluation budget of about 8000.
9292 /// </para>
9393 /// </remarks>
94- public static MultiOdeResult IntegrateOde ( Func < double , IList < double > , IList < double > > rhs , double x0 , IList < double > y0 , double x1 ) {
94+ public static MultiOdeResult IntegrateOde ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x0 , IReadOnlyList < double > y0 , double x1 ) {
9595 return ( IntegrateOde ( rhs , x0 , y0 , x1 , new MultiOdeSettings ( ) ) ) ;
9696 }
9797
@@ -115,7 +115,7 @@ public static MultiOdeResult IntegrateOde (Func<double, IList<double>, IList<dou
115115 /// of each component. Each component's derivative may depend itself and any other components, as well as on the independent variable.
116116 /// The independent variable x still takes only a single real value.</para>
117117 /// </remarks>
118- public static MultiOdeResult IntegrateOde ( Func < double , IList < double > , IList < double > > rhs , double x0 , IList < double > y0 , double x1 , MultiOdeSettings settings ) {
118+ public static MultiOdeResult IntegrateOde ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x0 , IReadOnlyList < double > y0 , double x1 , MultiOdeSettings settings ) {
119119
120120 if ( rhs == null ) throw new ArgumentNullException ( nameof ( rhs ) ) ;
121121 if ( y0 == null ) throw new ArgumentNullException ( nameof ( y0 ) ) ;
@@ -134,22 +134,26 @@ public static MultiOdeResult IntegrateOde (Func<double, IList<double>, IList<dou
134134
135135 internal abstract class MultiOdeEngine : OdeEngine {
136136
137- public MultiOdeEngine ( Func < double , IList < double > , IList < double > > rhs , double x , MultiOdeSettings settings ) : base ( x ) {
137+ public MultiOdeEngine ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x , MultiOdeSettings settings ) : base ( x ) {
138138 Debug . Assert ( rhs != null ) ;
139139 Debug . Assert ( settings != null ) ;
140140 this . rhs = rhs ;
141141 this . settings = settings ;
142142 }
143143
144- private readonly Func < double , IList < double > , IList < double > > rhs ;
144+ private readonly Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs ;
145145
146146 protected readonly MultiOdeSettings settings ;
147147
148- public IList < double > Evaluate ( double x , IList < double > y ) {
148+ public IReadOnlyList < double > Evaluate ( double x , IReadOnlyList < double > y ) {
149149 if ( count >= settings . EvaluationBudget ) throw new NonconvergenceException ( ) ;
150150 count ++ ;
151- ReadOnlyCollection < double > yWrapper = new ReadOnlyCollection < double > ( y ) ;
152- IList < double > z = rhs ( x , yWrapper ) ;
151+ // ReadOnlyCollection doesn't have a constructor that accepts IReadOnlyList.
152+ // But being an IReadOnlyList doesn't protect us from be cast back to a mutable
153+ // type, so for the moment this is actually not safe from poorly behaved
154+ // rhs's.
155+ //ReadOnlyCollection<double> yWrapper = new ReadOnlyCollection<double>(y);
156+ IReadOnlyList < double > z = rhs ( x , y ) ;
153157 if ( z == null ) throw new InvalidOperationException ( ) ;
154158 return ( z ) ;
155159 }
@@ -173,7 +177,7 @@ protected override void AcceptStep () {
173177
174178 internal class MultiBulrischStoerEngine : MultiOdeEngine , IBulrischStoerEngine {
175179
176- public MultiBulrischStoerEngine ( Func < double , IList < double > , IList < double > > rhs , double x , IList < double > y , MultiOdeSettings settings ) : base ( rhs , x , settings ) {
180+ public MultiBulrischStoerEngine ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x , IReadOnlyList < double > y , MultiOdeSettings settings ) : base ( rhs , x , settings ) {
177181
178182 Debug . Assert ( rhs != null ) ;
179183 Debug . Assert ( y != null ) ;
@@ -218,7 +222,7 @@ private double[] TrialStep (int n) {
218222 double [ ] nY1 = new double [ Y . Length ] ;
219223 for ( int i = 0 ; i < nY1 . Length ; i ++ ) { nY0 [ i ] = Y [ i ] ; nY1 [ i ] = Y [ i ] + h * YPrime [ i ] ; }
220224
221- IList < double > F ;
225+ IReadOnlyList < double > F ;
222226 for ( int k = 1 ; k < n ; k ++ ) {
223227 F = Evaluate ( X + k * h , nY1 ) ;
224228 for ( int i = 0 ; i < nY1 . Length ; i ++ ) { double t = nY1 [ i ] ; nY1 [ i ] = nY0 [ i ] + 2.0 * h * F [ i ] ; nY0 [ i ] = t ; }
@@ -279,7 +283,7 @@ public override MultiOdeResult GetResult () {
279283
280284 internal class MultiStoermerEngine : MultiOdeEngine , IBulrischStoerEngine {
281285
282- public MultiStoermerEngine ( Func < double , IList < double > , IList < double > > rhs , double x , IList < double > y , IList < double > yPrime , MultiOdeSettings settings ) : base ( rhs , x , settings ) {
286+ public MultiStoermerEngine ( Func < double , IReadOnlyList < double > , IReadOnlyList < double > > rhs , double x , IReadOnlyList < double > y , IReadOnlyList < double > yPrime , MultiOdeSettings settings ) : base ( rhs , x , settings ) {
283287
284288 Debug . Assert ( rhs != null ) ;
285289 Debug . Assert ( y != null ) ;
@@ -401,7 +405,7 @@ private void TrialStep (int n, out double[] Y1, out double[] YP1) {
401405
402406 int d = Y . Length ;
403407
404- IList < double > F ;
408+ IReadOnlyList < double > F ;
405409 Y1 = new double [ d ] ;
406410 double [ ] D1 = new double [ d ] ;
407411
0 commit comments