a gnarly IF THEN ELSE problem

Use this forum to post Vensim related questions.
Post Reply
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

a gnarly IF THEN ELSE problem

Post 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!
Administrator
Super Administrator
Posts: 4590
Joined: Wed Mar 05, 2003 3:10 am

Re: a gnarly IF THEN ELSE problem

Post 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.
Advice to posters seeking help (it really helps us to help you)
http://www.ventanasystems.co.uk/forum/v ... f=2&t=4391

Units are important!
http://www.bbc.co.uk/news/magazine-27509559
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

Re: a gnarly IF THEN ELSE problem

Post 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 )
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

Re: a gnarly IF THEN ELSE problem

Post 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.
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

Re: a gnarly IF THEN ELSE problem

Post 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.
tomfid
Administrator
Posts: 3811
Joined: Wed May 24, 2006 4:54 am

Re: a gnarly IF THEN ELSE problem

Post 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)
)
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

Re: a gnarly IF THEN ELSE problem

Post 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?
tomfid
Administrator
Posts: 3811
Joined: Wed May 24, 2006 4:54 am

Re: a gnarly IF THEN ELSE problem

Post by tomfid »

The Vensim language doesn't support that kind of procedural code. I'm not sure it improves readability over nesting.
sjgenco
Member
Posts: 25
Joined: Mon Sep 26, 2022 10:52 pm
Vensim version: PLE

Re: a gnarly IF THEN ELSE problem

Post by sjgenco »

okey dokey, live and learn.
tomfid
Administrator
Posts: 3811
Joined: Wed May 24, 2006 4:54 am

Re: a gnarly IF THEN ELSE problem

Post 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.
Post Reply