Page 1 of 1

a gnarly IF THEN ELSE problem

Posted: Fri Jul 21, 2023 11:29 pm
by sjgenco
I'm trying to translate some fairly complex InsightMaker code into a Vensim model and have been beating my head against the wall all day with this equation, trying to get rid of 'Expecting an operator' errors. Here's the code:

Code: Select all

IF THEN ELSE( pE < w ,
    # if true that pE < w
    IF THEN ELSE( Time-sy <= 0 ,
        # if true that Time-sy <= 0
        q = 1 ,
        # if false that Time-sy <= 0
        IF THEN ELSE( Time-sy >= py ,   
            # if true that Time-sy >= py
            q = (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ,
            # if false that Time-sy >= py
            q = ((((Time-sy)/py)) * (1-p) + (1-(Time-sy)/py)) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ),
        # if false that Time-sy <= 0
        q = 1 ),
    # if false that pE < w
    q = 1 )
The first IF statement triggers an embedded IF statement if it evaluates to TRUE. If FALSE, it assigns 'q = 1'.

Inside that second IF statement there is third one, which evaluates to 'q = 1' if TRUE, but enters a third IF statement if FALSE.

That third IF statement assigns a long calculation to q if TRUE and an even longer one if FALSE.

Whatever I do with this code, it just comes up 'Expecting an operator'.

(future enhancement tip: it would be nice to know where it's expecting an operator)

(2nd future enhancement tip: it would be great if the Vensim editor had a parentheses matching function, like most every other editor in the world. I checked all my parentheses by copying the code into Atom. All the wrapping of the individual elements appears to be what it should be (according to the code I'm translating).

Thanks!

Re: a gnarly IF THEN ELSE problem

Posted: Sat Jul 22, 2023 2:17 am
by Administrator
That equation will not work at all in Vensim. Things like the # are reserved characters so need to be in quotes. Even if it were close to Vensim syntax, that's an awful equation to replicate.

I would definitely simplify it. And try and not nest IF THEN ELSE statements. For example, have something like

q =
IF THEN ELSE( Time-sy <= 0 , 1 , 0)
+ IF THEN ELSE( Time-sy >= py , (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) , 0 )
+ IF THEN ELSE (etc)

This is awful as well, but easier to read and debug than a nested set of statements.
(future enhancement tip: it would be nice to know where it's expecting an operator)

(2nd future enhancement tip: it would be great if the Vensim editor had a parentheses matching function, like most every other editor in the world. I checked all my parentheses by copying the code into Atom. All the wrapping of the individual elements appears to be what it should be (according to the code I'm translating).
Both these are in the pipeline.

Re: a gnarly IF THEN ELSE problem

Posted: Sat Jul 22, 2023 4:21 pm
by sjgenco
My apologies! I grabbed the wrong commenting character from my memory banks. The comments were just to help me make sure I was at the right level for each IF statement. The revised code, with the comments properly marked (below), still fails with the 'Expecting an operator' error. I certainly understand your 'awful' comment, nested IFs are ugly, but are they not allowed in Vensim? Have I hit some kind of internal nesting limit? Hope not. I will try to simplify the code, but even if it's ugly, it seems to me this code should work. Any additional thoughts?

Code: Select all

IF THEN ELSE( pE < w ,
    {if true that pE < w}
    IF THEN ELSE( Time-sy <= 0 ,
        {if true that Time-sy <= 0}
        q = 1 ,
        {if false that Time-sy <= 0}
        IF THEN ELSE( Time-sy >= py ,   
            {if true that Time-sy >= py}
            q = (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ,
            {if false that Time-sy >= py}
            q = ((((Time-sy)/py)) * (1-p) + (1-(Time-sy)/py)) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ),
        {if false that Time-sy <= 0}
        q = 1 ),
    {if false that pE < w}
    q = 1 )

Re: a gnarly IF THEN ELSE problem

Posted: Sat Jul 22, 2023 5:38 pm
by sjgenco
I tried to take your advice and simplify the equations, setting q=0 as a flag to enter what had been nested IFs. The code now looks like this (with comments properly marked):

Code: Select all

IF THEN ELSE( pE > w , q=1, q=0 )   {if Ecosphere size [pE] is above [w], set q=1}

IF THEN ELSE( q=0 :AND: Time <= sy , q=1 , q=0 )   {if q=0 and year is before policy start year [sy], set q=1}

IF THEN ELSE( q=0 :AND: Time > sy + py ,   {if year is after policy launch period}

    q = (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ,   

    {year must be within the policy launch period}
    q = ((((Time-sy)/py)) * (1-p) + (1-(Time-sy)/py)) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) )
Unfortunately, this simplified code, which I can find nothing wrong with, also triggers an 'Expecting an operator' error.
To test whether the error was embedded in those long "q =" equations, I replaced each of them with (say) q=5, but the error still occurs.
I seem to be back where I started.

Re: a gnarly IF THEN ELSE problem

Posted: Sat Jul 22, 2023 6:22 pm
by sjgenco
A bit more background on this puzzler. The full equation this code comes from is actually assigning the variable [g] and here it is deciding whether to modify the original value of [g] with one of these values of [q] (of course if q=1, that will leave [g] unchanged). Here's the whole equation:

Code: Select all

(Io + LN(2)/t) * (1 - EXP(u * pE))

IF THEN ELSE( pE > w , q=1, q=0 )   {if Ecosphere size [pE] is above [w], set q=1}

IF THEN ELSE( q=0 :AND: Time <= sy , q=1 , q=0 )   {if q=0 and year is before policy start year [sy], set q=1}

IF THEN ELSE( q=0 :AND: Time > sy + py ,   {if year is after policy launch period}

    q = (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ,   

    {year must be within the policy launch period}
    q = ((((Time-sy)/py)) * (1-p) + (1-(Time-sy)/py)) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) )

g * q
I tried deleting various pieces of this to find where the error is occurring.
So first I deleted the third IF statement, still got the error.
Then I deleted the second and third IF statements, still got the error.
Then I deleted all three IF statements, still got the error.
Then I deleted the input from [q] to [g] in the View and deleted all three IF statements and the final g*q statement, and that got an 'Equation OK'.
Which is where I started this thing. Now I'm thinking maybe in beating on this for so many hours, I've managed to corrupt the variable somehow. This just doesn't seem like behavior that makes any sense.

Re: a gnarly IF THEN ELSE problem

Posted: Sun Jul 23, 2023 7:31 pm
by tomfid
I think your simplification is incorrect, because it doesn't nest. It should look li

IF THEN ELSE( a=b, c
, IF THEN ELSE( d=e, f, g)
)

Re: a gnarly IF THEN ELSE problem

Posted: Sun Jul 23, 2023 8:48 pm
by sjgenco
I'm trying to avoid the nesting by using the value q=0 as a kind of flag.
The variable I'm assigning here is [g].
If the first IF statement evaluates to TRUE, we assign q=1 so we can skip the next two IF statements (which require q=0).
But if pE > w is FALSE, then we need to do more work, so we set q=0.

The second IF statement only gets called if q=0.
It tests whether we're in a year (Time) before the year [sy] in which a policy period [p] is launched.
If TRUE, q is set to 1, because we're done and want to ignore the third IF statement. So [q] will have no effect on [g] (g = g*1).
If FALSE, then we're either in a year after the start year [sy], or we're in a year between the start year and the policy duration [py], so we have more work to do.

Only if [q] is still 0 (second IF statement evaluated to FALSE), does this third IF statement get called.
We check to see if we're after the policy period (Time>sy+py).
If TRUE, we set q to one value.
If FALSE we must be within the policy period, so we set q to a different value.

Then we're done with the IFs and we we get our output value for [g] by multiplying g * q.
No nesting required?

Re: a gnarly IF THEN ELSE problem

Posted: Mon Jul 24, 2023 12:28 am
by tomfid
The Vensim language doesn't support that kind of procedural code. I'm not sure it improves readability over nesting.

Re: a gnarly IF THEN ELSE problem

Posted: Mon Jul 24, 2023 12:45 am
by sjgenco
okey dokey, live and learn.

Re: a gnarly IF THEN ELSE problem

Posted: Mon Jul 24, 2023 1:08 am
by tomfid
Your translation has two clauses for # if false that Time-sy <= 0 - you can get rid of the second q = 1 ),

Then it can be implemented as

Code: Select all

q = 
IF THEN ELSE( pE < w ,
    {# if true that pE < w}
    IF THEN ELSE( Time-sy <= 0 ,
        {# if true that Time-sy <= 0}
        {q =} 1 ,
        {# if false that Time-sy <= 0}
        IF THEN ELSE( Time-sy >= py ,   
            {# if true that Time-sy >= py}
            {q =} (1 - p) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) ,
            {# if false that Time-sy >= py}
            {q =} ((((Time-sy)/py)) * (1-p) + (1-(Time-sy)/py)) * (1-EXP(-10*(w-pE))) + EXP(-10*(w-pE)) 
        )
    ),
    {# if false that pE < w}
    {q =} 1
)
It still seems like a horrible equation though. I would go back to the stated purpose of the original and rebuild from scratch.