Error when assigning a difference to a vector

I have posted this question on stackoverflow as well.

I am using the following code to apply a function to my data. The function definition is also provided below. However, I am getting a type error. Could you please help me figure out what am I doing wrong here:

Note: you can download the data here

using DataFrames
using RData
import CodecBzip2
df = load("sdata.rda", convert = true)
sdata = df["sdata"]

apply_wiedemann(sdata,
                30,
                0.02,
                0.08,
                0.25,
                unique(sdata[:, "LV_length_m"])[2],
                unique(sdata[:, "LV_width_m"])[2],
                5,
                5,
                0.0001,
                2,
                2)
TypeError: non-boolean (Missing) used in boolean context

Stacktrace:
 [1] apply_wiedemann(::DataFrame, ::Int64, ::Float64, ::Float64, ::Float64, ::Float64, ::Float64, ::Int64, ::Int64, ::Float64, ::Int64, ::Int64) at .\In[30]:115
 [2] top-level scope at In[31]:1
 [3] include_string(::Function, ::Module, ::String, ::String) at .\loading.jl:1091

Function definition

function apply_wiedemann(df, V_DESIRED, FAKTORVmult, BMAXmult, BNULLmult, 
        L, W, AXadd, BXadd, angular_vel_threshold, EXadd,  OPDVadd)  
  
## Parameters --------------------------------------------------------------------
V_MAX = 44

L = L

angular_vel_threshold = angular_vel_threshold
CX = sqrt(W / angular_vel_threshold)

BMIN = -8
AX = L + AXadd 


## Time--------------------------------------------------------------------------
delta_T = (df[2,"frames"] - df[1,"frames"])/60
last_time = last(df[:,"time_complete"])
Time = collect(0:delta_T:last_time)

ts = size(Time)[1]

## Empty vectors-----------------------------------------------
BMAX = Vector{Union{Float64,Missing}}(missing, ts)
vn_complete = Vector{Union{Float64,Missing}}(missing, ts)
vn_complete[1] = df[1,"ED_speed_mps"]

vn1_complete = df[:,"LV_speed_mps"]
dv = Vector{Union{Float64,Missing}}(missing, ts)
dv[1] = df[1,"LV_DV_mps"]


xn_complete = Vector{Union{Float64,Missing}}(missing, ts)
xn_complete[1] = df[1,"ED_position_m"]


xn1_complete = df[:,"LV_position_m"]


bn_complete = Vector{Union{Float64,Missing}}(missing, ts)

sn_complete = Vector{Union{Float64,Missing}}(missing, ts)
sn_complete[1] = df[1,"LV_spacing_m"]



BX = Vector{Union{Float64,Missing}}(missing, ts) ### an empty vector 
ABX = Vector{Union{Float64,Missing}}(missing, ts) ### an empty vector 

SDV = Vector{Union{Float64,Missing}}(missing, ts)### an empty vector 
B_App = Vector{Union{Float64,Missing}}(missing, ts) ### an empty vector 

bl = df[:, "LV_acc_mps2"]

B_Emg = Vector{Union{Float64,Missing}}(missing, ts)

SDX = Vector{Union{Float64,Missing}}(missing, ts)

CLDV = Vector{Union{Float64,Missing}}(missing, ts)

OPDV = Vector{Union{Float64,Missing}}(missing, ts)

cf_state_sim = Vector{Union{String,Missing}}(missing, ts)



## Unintentional Acceleration and Deceleration when the car is at V_DESIRED
# BNULL = BNULLmult * (RND4 + NRND) 
BNULL = BNULLmult 


FaktorV = V_MAX / (V_DESIRED + FAKTORVmult * (V_MAX - V_DESIRED))


# EX = EXadd + EXmult * (NRND - RND2)
EX = EXadd




for t in collect(1:1:(ts-1)) 

    #println("$t")

    ## Speed-dependent part of Minimum following distance
    BX[t] = BXadd .* sqrt(min(vn_complete[t], vn1_complete[t])) 

    ## Minimum following distance
    ABX[t] = AX + BX[t] 


    ## Speed-difference at which driver perceives that the lead vehicle is slow
    SDV[t] = ((sn_complete[t] - AX)/CX)^2 ###0.34 |


    ## Maximum following distance
    SDX[t] = AX + (EX * BX[t])


    ## Speed-difference when driver perceives that lead vehicle is slower
    CLDV[t] = SDV[t] * EX^2


    ## Speed-difference when driver perceives that lead vehicle is faster
    # OPDV = CLDV * (((-1) * OPDVadd) - (OPDVmult * NRND))
    OPDV[t] = CLDV[t] * ((-1) * OPDVadd)



    if !ismissing(sn_complete[t]) & (sn_complete[t] <= ABX[t]) 

          B_Emg[t] = 0.5 * ((dv[t])^2 / (AX - sn_complete[t])) + bl[t] + 
            (BMIN * ((ABX[t] - sn_complete[t]) / (ABX[t] - AX)))

          bn_complete[t] = ifelse(B_Emg[t] < BMIN | B_Emg[t] > 0, BMIN, B_Emg[t])

          cf_state_sim[t] = "emergency_braking"

    elseif !ismissing(sn_complete[t]) & (sn_complete[t] < SDX[t]) 

        if !ismissing(dv[t]) & (dv[t] > CLDV[t]) 

            bn_complete[t] = BNULL

            cf_state_sim[t] = "following"

        elseif !ismissing(dv[t]) & (dv[t] < OPDV[t]) 

            bn_complete[t] = BNULL

            cf_state_sim[t] = "following"

        else 

            BMAX[t] = BMAXmult * (V_MAX - (vn_complete[t] * FaktorV)) 

            bn_complete[t] = BMAX[t]

            cf_state_sim[t] = "free_driving"

        end

    else 
        if !ismissing(dv[t]) & (dv[t] > SDV[t])
            B_App[t] = 0.5 * ((dv[t])^2 / (ABX[t] - sn_complete[t])) + bl[t]

            bn_complete[t] = ifelse(B_App[t] < BMIN, BMIN, B_App[t])

            cf_state_sim[t] = "approaching"
        else
            BMAX[t] = BMAXmult * (V_MAX - (vn_complete[t] * FaktorV)) 

            bn_complete[t] = BMAX[t]

            cf_state_sim[t] = "free_driving"
        end
    end

    vn_complete[t+1] = vn_complete[t] + (bn_complete[t] * delta_T)

    vn_complete[t+1] = ifelse(vn_complete[t+1] < 0, 0, vn_complete[t+1])

    xn_complete[t+1] = xn_complete[t] - (vn_complete[t] * delta_T) + (0.5 * bn_complete[t] * (delta_T)^2)
        
   ##### Error occurs with sn_complete line 
   
    sn_complete[t+1] = xn_complete[t+1] - xn1_complete[t+1]
 #=
    dv[t+1] = vn_complete[t+1] - vn1_complete[t+1]
    =#
    #println(xn_complete[t+1] - xn1_complete[t+1])
end 

### How to do this sum? I could not find the 'sum' function in julia
#sqrt(sum((head(vn_complete, -1) - data$ED_speed_mps)^2, na.rm=TRUE)/length(Time))
    
end

It’s probably this line.

I would guess that SDV[t] is returning missing. You should probably add a ismissing check for that value as well. Also, use && instead of &. && is for control flow, & does OR on bits.

2 Likes

Thanks for your reply. I replaced all & with &&, and wrapped !ismissing around all variables like SDV[t]. It still throws the same error.

Also, if I do not assign xn_complete[t+1] - xn1_complete[t+1] to sn_complete[t+1], it does not throw any error. That is strange.

I haven’t run your code, but I would suggest updating your post to reflect how you’ve changed the code. The error looks suspicious in that the sn_complete line doesn’t seem to have boolean operations, whereas the error says “non-boolean (Missing) used in boolean context”. It could be the real error lies somewhere else, or that with your updates something else is different/incorrect. For example, maybe you didn’t manage to wrap !ismissing in all the right places, or there’s a mis-placed closing parenthesis.

Also as an unrelated notes, I notice some code that is not idiomatic Julia. For example, you may be unnecessarily copying the data with stuff like df[:, "LV_acc_mps2"]. Perhaps you can directly access with df."LV_acc_mps2" or df[!, "LV_acc_mps2"]? Also, this seems to copy a column: last(df[:,"time_complete"]) and might be replaced with df[end, "time_complete"]? This is a trivial thing, but to me it’s nicer to use size(Time, 1) instead of size(Time)[1].

Similarly, collect allocates memory, often unnecessarily, so maybe you can just use Time = 0:delta_T:last_time and for t in 1:ts-1? Another suggestion: Instead of your rectifying ifelses, maybe combine each with the preceding line, e.g. vn_complete[t+1] = max(0, vn_complete[t] + (bn...? Reads a bit clearer to me, although your mileage may vary.

Of course, better to find the bug first, and worry about silly optimizations later.

2 Likes

Thank you. I have now explicitly dealt with the missing values at the beginning of the for-loop. This solved the error.

About your comments on optimization: Thanks! Where can I learn more about what is better in terms of speed/memory? I could not find this info. in the beginner tutorials.

Actually that’s a really good point, I’m not quite sure where those simple optimizations are documented. I was sure they would be in performance tips, but mostly they are not. The tips do recommend array views (over slices), but doesn’t really describe when copying occurs. In fact, another section says that copying isn’t always bad. That’s true, but assumes people already know not to copy.

The current performance tips are actually a bit advanced, There may be need for a simpler set of basic performance tips. Describe when copying occurs and how to avoid, and maybe a general proscription against collect, which is very rarely warranted.

None of this should matter unless performance is critical. If so, you can ask for help on Discourse, and I wouldn’t be surprised if people suggest very substantial improvements. Your code already does several things well, like pre-allocating arrays and working in a loop. (Some try to vectorize without properly broadcasting.) And if you want a huge improvement, just entitle your post “Julia is slower than Python when assigning a difference to a vector.” (That’s a joke!)

2 Likes