# stochastic rule with multiple percentages workaround

1153
3
03-08-2017 01:42 PM
by
New Contributor II

HI, I was wondering if its possible to use more than 1 attribute as percentages in an stochastic rule, something like this:

attr mytrattribute1 = 0

attr mytrattribute2 = 0

attr mytrattribute3 = 0

Function01 -->

mytrattribute1% : Do something

mytrattribute2% : Do something

mytrattribute3% : Do something

else: Do something

I tried using P() like this:

Function01 -->

case p (mytrattribute1):  Do something

case p (mytrattribute2): Do something

case p (mytrattribute3): Do something

else:  Do something

but it does not accept more than one attr, i really wouldn't like to hardcode this percentages =/

thank you guys for your attention!

3 Replies
Esri Regular Contributor

I'm not sure the second piece of code with p() actually does the same thing as the first piece of code.  In the second piece of code, the case statements are run through sequentially, which the second case statement is only reached if the first case statement fails.  Consider the following example.

Let's say we want our result to be:

30%:  A.

20%:  B.

10%:  C.

else: D.

I don't think the following is a replacement for the above:

case p(0.3): A.

case p(0.2): B.

case p(0.1): C.

else:       D.

because the second statement will only be reached if the first statement is false.  The chance that the first statement is false is 0.7.  When considering the combination with the first statement, he second statement's code (B) will be evaluated with probability 0.7*0.2.  Then, the third statement's code (C) has probability 0.7*0.8*0.1 of being reached.  I think that's how it would theoretically work, but you can write tests to evaluate it and see if this does happen.

Workaround:

Here's a workaround for the above example.  You could pick a random number in [0,1] and based on its value, choose to evaluate the appropriate case statement.  This way, you can vary the attributes a, b, and c which control the percentages.

attr a = 0.3

attr b = 0.2

attr c = 0.1

Rule1 -->

Rule2(rand(0,1))

Rule2(x) -->

case x<a:                     A.

case x>=a && x<a+b:           B.

case x>=a+b && x<a+b+c: C.

else:                         D.

New Contributor III

Thanks for the workaround Cheryl. I've seen this question a couple of times, so it is clearly relevant to a few people.

I've tried applying this to a more complex situation and it really fell over unfortunately. I want to drive a mix of potential housetypes (currently 9 but could be much more in other scenarios) across multiple sites (start shapes) for an existing urban area. I tried applying the workaround and I think the sheer number of types caused the problem.

I realise that having a large number of start shapes means the probability approach of % and 'p' conditions could see a significant divergence from intended % mix - but it was the cascading logic of the check that I think made it fall over.

It would be really good if there were a workaround - or better still, a new feature added to the code base - that can cope with a bigger range of possible attribute inputs.

attr Mix_A = 0.05

@Percent

attr Mix_B = 0.10

@Percent

attr Mix_C = 0.15

@Percent

attr Mix_D = 0.15

@Percent

attr Mix_E = 0.15

@Percent

attr Mix_F = 0.15

@Percent

attr Mix_G = 0.10

@Percent

attr Mix_H = 0.15

@Percent

attr Mix_J = 0.0

BuildForm(Storeys)-->

case Typol == "House":

alignScopeToGeometry(yUp, any, longest)

HouseMixer1(Storeys, HouseGroupCount,1)-

else: BuildForm2(Storeys,1,4.5,Typol,1000)

HouseMixer1(Storeys, HGCount,Count)-->

HouseMixer2(Storeys, HGCount, rand(0,1))

HouseMixer2(Storeys,HGCount,Mix)-->

case Mix>=Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F+Mix_G+Mix_H

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F+Mix_G+Mix_H+Mix_J: BuildForm2(Storeys,HGCount,HouseWidth_J,"J",HouseJ_GFA)

case Mix>=Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F+Mix_G

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F+Mix_G+Mix_H: BuildForm2(Storeys,HGCount,HouseWidth_H,"H",HouseH_GFA)

case Mix>=Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F+Mix_G: BuildForm2(Storeys,HGCount,HouseWidth_G,"G",HouseG_GFA)

case Mix>=Mix_A+Mix_B+Mix_C+Mix_D+Mix_E

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D+Mix_E+Mix_F: BuildForm2(Storeys,HGCount,HouseWidth_F,"F",HouseF_GFA)

case Mix>=Mix_A+Mix_B+Mix_C+Mix_D

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D+Mix_E: BuildForm2(Storeys,HGCount,HouseWidth_E,"E",HouseE_GFA)

case Mix>=Mix_A+Mix_B+Mix_C

&& Mix<Mix_A+Mix_B+Mix_C+Mix_D: BuildForm2(Storeys,HGCount, HouseWidth_D,"D",HouseD_GFA)

case Mix>=Mix_A+Mix_B

&& Mix<Mix_A+Mix_B+Mix_C: BuildForm2(Storeys,HGCount, HouseWidth_C,"C", HouseC_GFA)

case Mix>=Mix_A

&& Mix<Mix_A+Mix_B: BuildForm2(Storeys,HGCount, HouseWidth_B,"B", HouseB_GFA)

case Mix<Mix_A: BuildForm2(Storeys,HGCount,HouseWidth_A,"A",HouseA_GFA)

else: BuildForm2(Storeys,HGCount,4.5,"X",1000)

Esri Regular Contributor

True.  It gets a bit messy when you have a lot of items in your mix.  In 2019.1, it is possible to use an array to hold the mix percentages and then get an index into this array, which represents an item in your mix.

``````const mix = [Mix_A, Mix_B, Mix_C, Mix_D, Mix_E, Mix_F, Mix_G, Mix_H, Mix_J]

const randNum = rand(0, getSum(mix))
const ind = getInd(randNum, 0, 0)

getSum(mix) = getSumRecursive(mix, 0, 0)
getSumRecursive(mix, currInd, currSum) =
case currInd==size(mix):
currSum
else:
getSumRecursive(mix, currInd+1, currSum+mix[currInd])

getInd(num, currInd, currSum) =
case currInd==size(mix):
-1
case num < currSum+mix[currInd]:
currInd
else:
getInd(num, currInd+1, currSum+mix[currInd])‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Rule -->
case ind==0: A.
case ind==1: B.
case ind==2: C.
// ...
else:        J.‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍``````