Skip to content

Commit 75dfbdf

Browse files
committed
Consistency and QOL Fixes
--Generalized extension name into the abstract type ExtendGPU to allow for alternative GPU-based methods. --Added manual garbage collection to reduce time spent on GPU GC. --Corrected variable name generation when variables with indices are used (e.g. x[1:5] instead of x). --Corrected recognition of variables with indices in some edge cases. --Corrected mid_expr, which sometimes returned results inconsistent with McCormick.jl. --Added a ::Nothing relaxation rule. --Corrected some typos in multiplication relaxation rules. --Added "cut" operator to multiplication and division operations. --Added min/max rules (may need further development/verification). --Changed "factor" to no longer modify input expressions. --Added some support for "constants", which are inputs that should be treated symbolically but should not be expanded into McCormick tuples. --Added "sort_vars" function, which groups McCormick tuples together, and places constants at the front, before alphabetically sorting McCormick tuple groups. --Reordered user-facing inputs and outputs to [cv, cc, lo, hi] instead of [lo, hi, cv, cc].
1 parent f99f050 commit 75dfbdf

File tree

12 files changed

+344
-134
lines changed

12 files changed

+344
-134
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.vscode/
2+
Manifest.toml

Project.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
name = "SourceCodeMcCormick"
22
uuid = "a7283dc5-4ecf-47fb-a95b-1412723fc960"
33
authors = ["Robert Gottlieb <Robert.x.gottlieb@uconn.edu>"]
4-
version = "0.2.0"
4+
version = "0.3.0"
55

66
[deps]
7+
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
8+
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
79
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
10+
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
811
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
912
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
1013
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
14+
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
1115

1216
[compat]
1317
DocStringExtensions = "0.8 - 0.9"
14-
ModelingToolkit = "8"
1518
IfElse = "0.1.0 - 0.1.1"
19+
ModelingToolkit = "8"
1620
SymbolicUtils = "1"
1721
julia = "1.7"
1822

examples/ParBB/extension.jl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,22 @@
55
# See also: subroutines.jl, in this folder
66

77
using DocStringExtensions, EAGO
8+
9+
abstract type ExtendGPU <: EAGO.ExtensionType end
10+
811
"""
912
$(TYPEDEF)
1013
11-
The ExtendGPU integrator is meant to be paired with the SourceCodeMcCormick
12-
package. A required component of ExtendGPU is the function `convex_func`,
14+
The PointwiseGPU integrator is meant to be paired with the SourceCodeMcCormick
15+
package. A required component of PointwiseGPU is the function `convex_func`,
1316
which should take arguments corresponding to the McCormick tuple [cc, cv, hi, lo]
1417
for each branch variable in the problem and return a vector of convex
1518
relaxation evaluations of the objective function, of length equal to the
1619
length of the inputs.
1720
1821
$(TYPEDFIELDS)
1922
"""
20-
Base.@kwdef mutable struct ExtendGPU <: EAGO.ExtensionType
23+
Base.@kwdef mutable struct PointwiseGPU <: ExtendGPU
2124
"A user-defined function taking argument `p` and returning a vector
2225
of convex evaluations of the objective function"
2326
convex_func
@@ -49,9 +52,9 @@ Base.@kwdef mutable struct ExtendGPU <: EAGO.ExtensionType
4952
multistart_points::Int = 1
5053
end
5154

52-
function ExtendGPU(convex_func, var_count::Int; alpha::Float64 = 0.01, node_limit::Int = 50000,
55+
function PointwiseGPU(convex_func, var_count::Int; alpha::Float64 = 0.01, node_limit::Int = 50000,
5356
prepopulate::Bool = true, multistart_points::Int = 1)
54-
return ExtendGPU(convex_func, var_count, node_limit, alpha,
57+
return PointwiseGPU(convex_func, var_count, node_limit, alpha,
5558
Vector{Float64}(undef, node_limit), Vector{Float64}(undef, node_limit), Vector{NodeBB}(undef, node_limit), 0,
5659
Matrix{Float64}(undef, node_limit, var_count),
5760
Matrix{Float64}(undef, node_limit, var_count), prepopulate, multistart_points)

examples/ParBB/subroutines.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ function solve_gpu!(m::EAGO.GlobalOptimizer)
5050
# Run branch and bound; terminate when the stack is empty or when some
5151
# tolerance or limit is hit
5252
while !EAGO.termination_check(m)
53+
54+
# Garbage collect every 1000 iterations
55+
if mod(m._iteration_count, 1000)==0
56+
GC.enable(true)
57+
GC.gc(false)
58+
GC.enable(false)
59+
end
60+
5361
# Fathoming step
5462
EAGO.fathom!(m)
5563

@@ -197,7 +205,7 @@ add_to_substack!(m::EAGO.GlobalOptimizer{R,S,Q}) where {R,S,Q<:EAGO.ExtensionTyp
197205

198206
# Solve the lower and upper problem for all nodes simultaneously, using the convex_func
199207
# function from the ExtendGPU extension
200-
function lower_and_upper_problem!(t::ExtendGPU, m::EAGO.GlobalOptimizer)
208+
function lower_and_upper_problem!(t::PointwiseGPU, m::EAGO.GlobalOptimizer)
201209
# Step 1) Bring the bounds into the GPU
202210
lvbs_d = CuArray(t.all_lvbs)
203211
uvbs_d = CuArray(t.all_uvbs) # [points x num_vars]
@@ -208,8 +216,8 @@ function lower_and_upper_problem!(t::ExtendGPU, m::EAGO.GlobalOptimizer)
208216
eval_points = Vector{CuArray{Float64}}(undef, 3*w)
209217
for i = 1:w
210218
eval_points[3i-2] = CuArray{Float64}(undef, l*np)
211-
eval_points[3i-1] = repeat(uvbs_d[:,i], inner=np)
212-
eval_points[3i] = repeat(lvbs_d[:,i], inner=np)
219+
eval_points[3i-1] = repeat(lvbs_d[:,i], inner=np)
220+
eval_points[3i] = repeat(uvbs_d[:,i], inner=np)
213221
end
214222
evals_d = CuArray{Float64}(undef, l*np)
215223
results_d = CuArray{Float64}(undef, l)

examples/explicit_kinetic_problem.jl

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#############################################################################
88

99
# Import the necessary packages
10-
using EAGO, JuMP, CSV, DataFrames, Symbolics, SourceCodeMcCormick, CUDA, BenchmarkTools
10+
using EAGO, JuMP, CSV, DataFrames, Symbolics, SourceCodeMcCormick, CUDA
1111

1212
# Import the ParBB algorithm
1313
include(joinpath(@__DIR__, "ParBB", "extension.jl"))
@@ -255,15 +255,3 @@ JuMP.register(m, :fobj, 3, fobj, autodiff=true)
255255
@NLobjective(m, Min, fobj(p...))
256256

257257
optimize!(m)
258-
259-
# Save the results
260-
open("C:/Users/rxg20001/Documents/Research Files/2023-03-25 Kinetic Problem SCMC GPU.txt","a") do io
261-
println(io, "SCMC; GPU; Alpha=2e-5; 50k nodes per batch")
262-
println(io, "Semi-parallelized lvb/uvb loading")
263-
println(io, "Node count, Global Lower Bound, Global Upper Bound, Time (s)")
264-
log = m.moi_backend.optimizer.model._global_optimizer._log
265-
loglen = length(log.global_lower_bound)
266-
for i = 1:loglen
267-
println(io, string(log.node_count[i]), ",", string(log.global_lower_bound[i]), ",", string(log.global_upper_bound[i]), ",", string(log.run_time[i]))
268-
end
269-
end

src/SourceCodeMcCormick.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11

22
module SourceCodeMcCormick
33

4-
using ModelingToolkit
4+
# using ModelingToolkit
5+
import ModelingToolkit: Equation, ODESystem, @named, toparam, iv_from_nested_derivative, value, collect_vars!
6+
using Symbolics
57
using SymbolicUtils.Code
68
using IfElse
79
using DocStringExtensions
10+
using Graphs
11+
using CUDA
12+
import Dates
13+
14+
import SymbolicUtils: BasicSymbolic, exprtype, SYM, TERM, ADD, MUL, POW, DIV
815

916
import SymbolicUtils: BasicSymbolic, exprtype, SYM, TERM, ADD, MUL, POW, DIV
1017

src/interval/interval.jl

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function var_names(::IntervalTransform, a::BasicSymbolic)
1212
aU = genvar(Symbol(string(get_name(a))*"_hi"))
1313
return aL.val, aU.val
1414
elseif exprtype(a)==TERM
15-
if varterm(a)
15+
if varterm(a) && typeof(a.f)<:BasicSymbolic
1616
arg_list = Symbol[]
1717
for i in a.arguments
1818
push!(arg_list, get_name(i))
@@ -56,25 +56,29 @@ end
5656
"""
5757
get_name
5858
59-
Take a `BasicSymbolic` object such as `x[1,1]` and return a symbol like `:x_1_1`.
59+
Take a `BasicSymbolic` object such as `x[1,1]` and return a symbol like `:xv1v1`.
6060
"""
6161
function get_name(a::BasicSymbolic)
6262
if exprtype(a)==SYM
6363
return a.name
6464
elseif exprtype(a)==TERM
6565
if varterm(a)
66-
return a.f.name
67-
elseif (a.f==getindex)
68-
args = a.arguments
69-
new_var = string(args[1])
70-
for i in 2:lastindex(args)
71-
new_var = new_var * "_" * string(args[i])
66+
if a.f==getindex
67+
args = a.arguments
68+
new_var = string(args[1])
69+
for i in 2:lastindex(args)
70+
new_var = new_var * "v" * string(args[i])
71+
end
72+
return Symbol(new_var)
73+
else
74+
return a.f.name
7275
end
73-
return Symbol(new_var)
7476
else
7577
error("Problem generating variable name. This may happen if the variable is non-standard. Please post an issue if you get this error.")
7678
end
7779
end
7880
end
81+
get_name(a::Num) = get_name(a.val)
82+
get_name(a::Real) = a
7983

8084
include(joinpath(@__DIR__, "rules.jl"))

src/relaxation/relaxation.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function var_names(::McCormickTransform, a::BasicSymbolic)
99
acc = genvar(Symbol(string(get_name(a))*"_cc"))
1010
return acv.val, acc.val
1111
elseif exprtype(a)==TERM
12-
if varterm(a)
12+
if varterm(a) && typeof(a.f)<:BasicSymbolic
1313
arg_list = Symbol[]
1414
for i in a.arguments
1515
push!(arg_list, get_name(i))
@@ -84,7 +84,7 @@ end
8484
line_expr(x, xL, xU, zL, zU) = IfElse.ifelse(zU > zL, (zL*(xU - x) + zU*(x - xL))/(xU - xL), zU)
8585

8686
# A symbolic way of computing the mid of three numbers (returns IfElse block)
87-
mid_expr(a, b, c) = IfElse.ifelse(a < b, IfElse.ifelse(b < c, b, IfElse.ifelse(c < a, a, c)),
88-
IfElse.ifelse(c < b, b, IfElse.ifelse(a < c, a, c)))
87+
mid_expr(x, y, z) = IfElse.ifelse(x >= y, IfElse.ifelse(y >= z, y, IfElse.ifelse(y == x, y, IfElse.ifelse(z >= x, x, z))),
88+
IfElse.ifelse(z >= y, y, IfElse.ifelse(x >= z, x, z)))
8989

9090
include(joinpath(@__DIR__, "rules.jl"))

0 commit comments

Comments
 (0)