stochastic rule with multiple percentages workaround

03-08-2017 01:42 PM
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!

0 Kudos
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.


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(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


attr Mix_B = 0.10


attr Mix_C = 0.15


attr Mix_D = 0.15


attr Mix_E = 0.15


attr Mix_F = 0.15


attr Mix_G = 0.10


attr Mix_H = 0.15


attr Mix_J = 0.0


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))


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)

0 Kudos
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):
      getSumRecursive(mix, currInd+1, currSum+mix[currInd])

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

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