question

Peter W8 avatar image
0 Likes"
Peter W8 asked Felix Möhlmann commented

How to label items according to percentage and restrictions?

I need to create labels according to the following percentage:

Label AMT_G: 50%

Label AMT_RET: 21%

Label AMT_EXT_ULC: 7%

Label AMT_PIGG: 2%

Label AMT_PS: 2%

Label AMT_HYB: 1%

Label AMT_DUAL: 8%

Label PIE: 2%

Label PIE_RET: 7%


For this I use a trigger "Set Label by Percentage" at the source.

However, certain labels are not allowed to be created one after another. This applies to all labels except AMT_G and AMT_DUAL which are allowed to be created one after another. The creation restriction for the other labels should be as following:

AMT_RET: Max 1/4

AMT_EXT_ULC: Max 1/7

AMT_PIGG: Max 1/18

AMT_PS: Max 1/4

AMT_HYB: Max 1/4

PIE: Max 1/8

PIE_RET: Max 1/8

So for instance 7% of all created labels should be "PIE_RET" but "PIE_RET" is not to be created more often than every eight label. How do I achieve this?

I've uploaded my model ("LabelingWithPercentandFreq") to the flexsim file share site.


FlexSim 22.1.1
labelsby percentagerestrictioncreation
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Felix Möhlmann avatar image
0 Likes"
Felix Möhlmann answered Felix Möhlmann commented

My approach would be to build upon the "Set Label By Percentage" option. With labels the object can keep track of whether a label value is allowed to be assigned or not (as a combination of the min. intervals and the number of items since that label was last assigned). If the value can not be assigned right now, it is written to an array of pending values and a new random value is generated until the label can be assigned. This is done to not alter the quantity of how often a value is assigned overall, but only delay assigning it. Each time the trigger fires, the code first checks if any of the pending values can now be assigned. If not, or there aren't any, it goes back to generating random values.

In the example model that is linked below I use a bundle label on the source to keep track of when the values can be assigned. The "AllowedIn" column is set to the "MinInterval" value when the value is used and decremented each time a new item is generated. If the number in that column is 0, the value is allowed to be assigned.

1661339087426.png

The "Value" column is indexed (Rightclick on the column header to see the option), for fast lookup of the correct row in the code.

As mentioned above, the default "Set Label By Percentage" option forms the basis of the code with the rest added around it.

int stream = getstream(current);
// Decrement bundle "AllowedIn" column
treenode bundleLabel = current.labels["MinIntervals"];
int numRows = getbundlenrentries(bundleLabel);
for(int i = 0; i < numRows; i++)
{
    setbundlevalue(bundleLabel, i, "AllowedIn", Math.max(0, getbundlevalue(bundleLabel, i, "AllowedIn")-1));
}

// Get next number
// Check value queue first
for(int j = 1; j <= current.ValueQueue.length; j++)
{
    Variant value = current.ValueQueue[j];
    // Check if number is allowed
    int bundleRow = getbundleindexentries(bundleLabel, "Value", value)[1];
    if(getbundlevalue(bundleLabel, bundleRow, "AllowedIn") == 0)
    {
        // If so, set "AllowedIn" column, assign label, remove from array and terminate
        setbundlevalue(bundleLabel, bundleRow, "AllowedIn", getbundlevalue(bundleLabel, bundleRow, "MinInterval"));
        item.labels.assert("Type").value = value;
        current.ValueQueue.shift();
        return 0;
    }
}
while(true)
{
    double randomnum = uniform(0.0, 100.0, stream);
    string labelname = "Type";
    Object involved = item;
    Variant value;
    double total = 0.0;
    int foundmatch = 0;

    total += 50;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_G";
        foundmatch = 1;
    }
    total += 21;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_RET";
        foundmatch = 1;
    }
    total += 7;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_EXT_ULC";
        foundmatch = 1;
    }
    total += 2;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_PIGG";
        foundmatch = 1;
    }
    total += 2;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_PS";
        foundmatch = 1;
    }
    total += 1;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_HYB";
        foundmatch = 1;
    }
    total += 8;
    if (!foundmatch && randomnum <= total) {
        value = "AMT_DUAL";
        foundmatch = 1;
    }
    total += 2;
    if (!foundmatch && randomnum <= total) {
        value = "PIE";
        foundmatch = 1;
    }
    total += 7;
    if (!foundmatch && randomnum <= total) {
        value = "PIE_RET";
        foundmatch = 1;
    }

    // Check if number is allowed
    int bundleRow = getbundleindexentries(bundleLabel, "Value", value)[1];
    if(getbundlevalue(bundleLabel, bundleRow, "AllowedIn") == 0)
    {
        // If so, set "AllowedIn" column, assign label and terminate
        setbundlevalue(bundleLabel, bundleRow, "AllowedIn", getbundlevalue(bundleLabel, bundleRow, "MinInterval"));
        involved.labels.assert(labelname).value = value;
        return 0;
    }
    else
    {
        // If not push to ValueQueue
        current.ValueQueue.push(value);
    }
}

Download model (google drive)


1661339087426.png (7.1 KiB)
· 3
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Peter W8 avatar image Peter W8 commented ·

Thank you for your help! It seems to work :-)

One question though, how did you create the calculated tables? I really liked them. Never seen them before ( I'm a novice user still trying to learn the basics).

0 Likes 0 ·
Felix Möhlmann avatar image Felix Möhlmann Peter W8 commented ·

Calculated Tables are a pretty expansive topic, so for a start I will link you to the manual page abou them as well as the page about SQL queries in general.

In the model I use an "Aggregation" metric to count the type values and partition the result by the type as well.

If you have any specific questions, feel free to post a follow-up comment.

0 Likes 0 ·
Peter W8 avatar image Peter W8 commented ·
Never mind, I figured it out. Thanks for your help! Would never have solved it on my own.

/Peter

0 Likes 0 ·
Peter W8 avatar image
0 Likes"
Peter W8 answered Felix Möhlmann commented

Hi again,

I noticed an issue with one variant, "AMT_RET". That variant does not follow the creation restricton you helped me with. I believe it has to do with that you used a lower case "t" in the name. It should be a capital "T". But when I change it to a capital "T", it reverts back to a lower case "t" everytime I press stop or reset. How do I change it and could this be the reason for "AMT_RET" not taking the restriction into acount?

1663075060076.png


1663075060076.png (7.6 KiB)
· 1
5 |100000

Up to 12 attachments (including images) can be used with a maximum of 23.8 MiB each and 47.7 MiB total.

Felix Möhlmann avatar image Felix Möhlmann commented ·

Sorry for that mistake. Because the table is a label on the source and set automatically reset, you have to click on the "Save reset values" button after changing the entry in the table.

1663083968686.png

0 Likes 0 ·
1663083968686.png (10.2 KiB)