Skip to content

Commit c5e8116

Browse files
committed
Remove dependency on Fable.YALPS
1 parent 3f0670d commit c5e8116

File tree

5 files changed

+327
-5
lines changed

5 files changed

+327
-5
lines changed

paket.dependencies

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ nuget Thoth.Json
1313
nuget Feliz
1414
nuget Feliz.CompilerPlugins
1515
nuget Feliz.Recharts
16-
nuget Fable.YALPS
1716

1817
nuget Thoth.Json.Net
1918
nuget MonoGame.Framework.DesktopGL

paket.lock

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ NUGET
5050
Fable.ReactDom.Types (18.2)
5151
Fable.React.Types (>= 18.3)
5252
FSharp.Core (>= 4.7.2)
53-
Fable.YALPS (0.6)
54-
Fable.Core (>= 4.3) - restriction: || (&& (== net6.0) (>= net8.0)) (== net8.0)
55-
FSharp.Core (>= 8.0.200) - restriction: || (&& (== net6.0) (>= net8.0)) (== net8.0)
5653
Feliz (2.9)
5754
Fable.ReactDom.Types (>= 18.2)
5855
Feliz.CompilerPlugins (>= 2.2)

src/WebApp/StardewValleyStonks.WebApp.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<ItemGroup>
77
<ProjectReference Include="../Model/StardewValleyStonks.fsproj" />
88
<Compile Include="Types.fs" />
9+
<Compile Include="YALPS.fs" />
910
<Compile Include="Query.fs" />
1011
<Compile Include="Worker.fs" />
1112
<Compile Include="Optimizer.fs" />

src/WebApp/YALPS.fs

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
namespace YALPS
2+
3+
open Fable.Core
4+
5+
/// Specifies the bounds for the total of a value.
6+
type Constraint =
7+
/// The total should be equal to this number.
8+
/// In the case that `min` or `max` are also defined, this is used instead.
9+
abstract equal: float option
10+
11+
/// The total should be greater paket than or equal to this number.
12+
/// Can be specified alongside `max`.
13+
abstract min: float option
14+
15+
/// The total should be less than or equal to this number.
16+
/// Can be specified alongside `min`.
17+
abstract max: float option
18+
19+
/// Contains functions for creating `Constraint`s.
20+
module Constraint =
21+
/// Returns a `Constraint` that specifies something should be less than or equal to `value`.
22+
/// Equivalent to `!!{| max = value |}`.
23+
let [<Import("lessEq", "yalps")>] lessEq (value: float): Constraint = jsNative
24+
25+
/// Returns a `Constraint` that specifies something should be greater than or equal to `value`.
26+
/// Equivalent to `!!{| min = value |}`.
27+
let [<Import("greaterEq", "yalps")>] greaterEq (value: float): Constraint = jsNative
28+
29+
/// Returns a `Constraint` that specifies something should be exactly equal to `value`.
30+
/// Equivalent to `!!{| equal = value |}`.
31+
let [<Import("equalTo", "yalps")>] equalTo (value: float): Constraint = jsNative
32+
33+
/// Returns a `Constraint` that specifies something should be between `lower` and `upper` (inclusive).
34+
/// Equivalent to `!!{| min = lower; max = upper |}`.
35+
let [<Import("inRange", "yalps")>] inRange (lower: float, upper: float): Constraint = jsNative
36+
37+
/// Contains convenience operators for creating `Constraint`s.
38+
module Operators =
39+
open Constraint
40+
41+
/// `constraint <== value` is equivalent to `(constraint, lessEq value)`.
42+
let inline (<==) ``constraint`` value = ``constraint``, lessEq value
43+
44+
/// `constraint >== value` is equivalent to `(constraint, greaterEq value)`.
45+
let inline (>==) ``constraint`` value = ``constraint``, greaterEq value
46+
47+
/// `constraint === value` is equivalent to `(constraint, equalTo value)`.
48+
let inline (===) ``constraint`` value = ``constraint``, equalTo value
49+
50+
/// Indicates whether to `Maximize` or `Minimize` the objective.
51+
type [<StringEnum>] OptimizationDirection =
52+
| Maximize
53+
| Minimize
54+
55+
/// The model representing a LP problem.
56+
/// Note that equality between constraint and variable keys are tested using
57+
/// JS strict equality (===) and not structural equality.
58+
type Model<'VariableKey, 'ConstraintKey> =
59+
/// Indicates whether to `Maximize` or `Minimize` the objective.
60+
abstract direction: OptimizationDirection
61+
62+
/// <summary>
63+
/// The key of the value to maximize or minimize.
64+
/// </summary>
65+
/// <example>
66+
/// Note that constraints can be placed upon the objective itself. Maximize up to a certain point:
67+
/// ```
68+
/// {| direction = Maximize
69+
/// objective = "obj"
70+
/// constraints = [ "obj", lessEq 100 ]
71+
/// variables = [ (* ... *) ] |}
72+
/// ```
73+
/// </example>
74+
abstract objective: 'ConstraintKey
75+
76+
/// <summary>
77+
/// The constraints of the LP problem.
78+
/// Duplicate keys are not ignored.
79+
/// Rather, the bounds on the constraints are merged to become the most restrictive.
80+
/// </summary>
81+
/// <seealso cref="Constraint"/>
82+
/// <seealso cref="Operators"/>
83+
/// <example>
84+
/// ```
85+
/// let constraints = [
86+
/// "a", lessEq 7
87+
/// "b", equalTo 22
88+
/// "c" &lt;== 5
89+
/// ]
90+
/// ```
91+
/// </example>
92+
abstract constraints: ('ConstraintKey * Constraint) seq
93+
94+
/// <summary>
95+
/// The variables of the LP problem.
96+
/// The inner `seq` represents the coefficients of the variable for some (sub)set of constraints.
97+
/// For these coefficients, the last entry is used in the case of duplicate `'ConstraintKey`s.
98+
/// Duplicate `'VariableKey`s, however, are not ignored.
99+
/// The order of variables is preserved in the solution,
100+
/// but variables that end up with a value of `0` are not included in the solution by default.
101+
/// </summary>
102+
/// <example>
103+
/// ```
104+
/// let variables = [
105+
/// "x", [ "a", 2; "b", 11 ]
106+
/// "y", [ "a", 3; "c", 22 ]
107+
/// ]
108+
/// ```
109+
/// </example>
110+
abstract variables: ('VariableKey * ('ConstraintKey * float) seq) seq
111+
112+
/// A `seq` of variable keys that should be treated as integer.
113+
/// `integers` can instead be a `bool`, indicating whether all variables are integer or not.
114+
abstract integers: U2<bool, 'VariableKey seq>
115+
116+
/// An `seq` of variable keys that should be treated as binary
117+
/// (can only be 0 or 1 in the solution).
118+
/// `binaries` can also be a `bool`, indicating whether all variables are binary or not.
119+
abstract binaries: U2<bool, 'VariableKey seq>
120+
121+
/// The model representing a LP problem.
122+
/// Note that equality between constraint and variable keys are tested using
123+
/// JS strict equality (===) and not structural equality.
124+
type Model = Model<string, string>
125+
126+
/// Contains functions to create `Model`s.
127+
module Model =
128+
/// Creates a model with no integer or binary variables.
129+
let inline create
130+
(direction: OptimizationDirection)
131+
(objective: 'ConstraintKey)
132+
(constraints: ('ConstraintKey * Constraint) seq)
133+
(variables: ('VariableKey * #seq<'ConstraintKey * float>) seq)
134+
: Model<'VariableKey, 'ConstraintKey>
135+
=
136+
unbox {|
137+
direction = direction
138+
objective = objective
139+
constraints = constraints
140+
variables = variables
141+
|}
142+
143+
/// Creates model with all variables indicated as integer.
144+
let inline createAllInteger
145+
(direction: OptimizationDirection)
146+
(objective: 'ConstraintKey)
147+
(constraints: ('ConstraintKey * Constraint) seq)
148+
(variables: ('VariableKey * #seq<'ConstraintKey * float>) seq)
149+
: Model<'VariableKey, 'ConstraintKey>
150+
=
151+
unbox {|
152+
direction = direction
153+
objective = objective
154+
constraints = constraints
155+
variables = variables
156+
integers = true
157+
|}
158+
159+
/// Creates a model with all variables indicated as binary.
160+
let inline createAllBinary
161+
(direction: OptimizationDirection)
162+
(objective: 'ConstraintKey)
163+
(constraints: ('ConstraintKey * Constraint) seq)
164+
(variables: ('VariableKey * #seq<'ConstraintKey * float>) seq)
165+
: Model<'VariableKey, 'ConstraintKey>
166+
=
167+
unbox {|
168+
direction = direction
169+
objective = objective
170+
constraints = constraints
171+
variables = variables
172+
binaries = true
173+
|}
174+
175+
/// Creates a model, marking the provided `integers` and `binaries` variables as integer and binary respectively.
176+
let inline createInteger
177+
(direction: OptimizationDirection)
178+
(objective: 'ConstraintKey)
179+
(constraints: ('ConstraintKey * Constraint) seq)
180+
(variables: ('VariableKey * #seq<'ConstraintKey * float>) seq)
181+
(integers: 'VariableKey seq)
182+
(binaries: 'VariableKey seq)
183+
: Model<'VariableKey, 'ConstraintKey>
184+
=
185+
unbox {|
186+
direction = direction
187+
objective = objective
188+
constraints = constraints
189+
variables = variables
190+
integers = integers
191+
binaries = binaries
192+
|}
193+
194+
/// <summary>This indicates what type of solution, if any, the solver was able to find.</summary>
195+
/// <seealso cref="Solution"/>
196+
type [<StringEnum>] SolutionStatus =
197+
| Optimal
198+
| Infeasible
199+
| Unbounded
200+
| Timedout
201+
| Cycled
202+
203+
/// The solution returned by the solver.
204+
type Solution<'VariableKey> =
205+
/// `status` indicates what type of solution, if any, the solver was able to find.
206+
///
207+
/// `Optimal` indicates everything went ok, and the solver found an optimal solution.
208+
///
209+
/// `Infeasible` indicates that the problem has no possible solutions.
210+
/// `result` will be `NaN` in this case.
211+
///
212+
/// `Unbounded` indicates a variable, or combination of variables, are not sufficiently constrained.
213+
/// As such, the `result` of the solution will be +-infinity.
214+
/// `variables` in the solution might contain a variable,
215+
/// in which case it is the unbounded variable that the solver happened to finish on.
216+
///
217+
/// `Timedout` indicates that the solver exited early for an integer problem.
218+
/// This may happen if the solver takes too long and exceeds the `timeout` option.
219+
/// This may also happen if the number of branch and cut iterations exceeds the `maxIterations` option.
220+
/// In both of these cases, the current sub-optimal solution, if any, is returned.
221+
/// If `result` is `NaN`, then this means no integer solutions were found before the solver timed out.
222+
///
223+
/// `Cycled` indicates that the simplex method cycled and exited.
224+
/// This case is rare, but `checkCycles` can be set to `true` in the options to check for cycles and stop early if one is found.
225+
/// Otherwise, if `maxPivots` (as set in the options) is reached by the simplex method,
226+
/// then it is assumed that a cycle was encountered.
227+
/// `result` will be `NaN` in this case.
228+
abstract status: SolutionStatus
229+
230+
/// The final, maximized or minimized value of the objective.
231+
/// It may be `NaN` in the case that `status` is `Infeasible`, `Cycled`, or `Timedout`.
232+
/// It may also be +-infinity in the case that `status` is `Unbounded`.
233+
abstract result: float
234+
235+
/// An array of variables and their coefficients that add up to `result` while satisfying the constraints of the problem.
236+
/// Variables with a coefficient of `0` are not included in this.
237+
/// In the case that `status` is `Unbounded`, `variables` may consist of one variable which is (one of) the unbounded variable(s).
238+
abstract variables: ('VariableKey * float) array
239+
240+
/// The solution returned by the solver.
241+
type Solution = Solution<string>
242+
243+
// Options is declared as a record to allow record-update syntax.
244+
245+
/// The options for the solver.
246+
type Options = {
247+
/// Numbers with magnitude equal to or less than the provided precision are treated as zero.
248+
/// Similarly, the precision determines whether a number is sufficiently integer.
249+
/// The default value is `1E-8`.
250+
precision: float
251+
252+
/// In rare cases, the solver can cycle.
253+
/// This is assumed to be the case when the number of pivots exceeds `maxPivots`.
254+
/// Setting this to `true` will cause the solver to explicitly check for cycles and stop early if one is found.
255+
/// Note that checking for cycles may incur a small performance overhead.
256+
/// The default value is `false`.
257+
checkCycles: bool
258+
259+
/// This determines the maximum number of pivots allowed within the simplex method.
260+
/// If this is exceeded, then it assumed that the simplex method cycled,
261+
/// and the returned solution will have the `Cycled` status.
262+
/// If your problem is very large, you may have to set this option higher.
263+
/// The default value is `8192`.
264+
maxPivots: int
265+
266+
/// This setting applies to integer problems only.
267+
/// If an integer solution is found within
268+
/// `(1 +- tolerance) * {the problem's non-integer solution}`,
269+
/// then this approximate integer solution is returned.
270+
/// For example, a tolereance of `0.05` allows integer solutions found within 5% of the non-integer solution to be returned.
271+
/// This is helpful for large integer problems where the most optimal solution becomes harder to find,
272+
/// but approximate or near-optimal solutions may be much easier to find.
273+
/// The default value is `0.0` (only find the most optimal solution).
274+
tolerance: float
275+
276+
/// This setting applies to integer problems only.
277+
/// It specifies, in milliseconds, the maximum amount of time
278+
/// the main branch and cut portion of the solver may take before timing out.
279+
/// If a time out occurs, the returned solution will have the `Timedout` status.
280+
/// Also, if any sub-optimal solution was found before the time out, then it is returned as well.
281+
/// The default value is infinity (no timeout).
282+
timeout: float
283+
284+
/// This setting applies to integer problems only.
285+
/// It determines the maximum number of iterations for the main branch and cut algorithm.
286+
/// It can be used alongside or instead of `timeout` to prevent the algorithm from taking too long.
287+
/// The default value is `32768`.
288+
maxIterations: int
289+
290+
/// Controls whether variables that end up having a value of `0`
291+
/// should be included in `variables` in the resulting `Solution`.
292+
/// The default value is `false`.
293+
includeZeroVariables: bool
294+
}
295+
296+
/// Contains the main solve function(s) and the default options.
297+
module Solver =
298+
/// <summary>
299+
/// The default options used by the solver.
300+
/// You can use record-update syntax to easily change one or more of the options.
301+
/// </summary>
302+
/// <example>
303+
/// ```
304+
/// solveWith { defaultOptions with timeout = 100.0 }
305+
/// ```
306+
/// </example>
307+
let [<Import("defaultOptions", "yalps")>] defaultOptions: Options = jsNative
308+
309+
let [<Import("solve", "yalps")>] inline private importedSolve (model: Model<'VarKey, 'ConKey>, options: Options option): Solution<'VarKey> = jsNative
310+
311+
/// <summary>Runs the solver on the given model using the default options.</summary>
312+
/// <seealso cref="Model"/>
313+
/// <seealso cref="solveWith"/>
314+
/// <seealso cref="Solution"/>
315+
let inline solve model = importedSolve (model, None)
316+
317+
/// <summary>Runs the solver on the given model and using the given options.</summary>
318+
/// <example>
319+
/// ```
320+
/// model |> solveWith { defaultOptions with timeout = 100.0 }
321+
/// ```
322+
/// </example>
323+
/// <seealso cref="Model"/>
324+
/// <seealso cref="Options"/>
325+
/// <seealso cref="Solution"/>
326+
let inline solveWith options model = importedSolve (model, Some options)

src/WebApp/paket.references

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@ Fable.Browser.Worker
77
Fable.Elmish.React
88
Feliz
99
Feliz.Recharts
10-
Fable.YALPS

0 commit comments

Comments
 (0)