Solved

Shifting Elements Between Sets

  • 12 July 2022
  • 8 replies
  • 104 views

Badge +3

Hello everyone, 

in my Simulation i have a Set Full of Orders which have to be released. I want to shift the Elements from the Set “Order Pool” to the Set “Orders in Production” and once finished to the Set “FinishedOrders”. 

 

I would like to know how to put Elements from one Set into another Set when a certain condition is fullfilled. 

 

Can anyone help me with that problem.

 

Kind regards

Alex

icon

Best answer by Chris Kuip 12 July 2022, 22:29

View original

8 replies

Userlevel 5
Badge +7

Hi Alex,

 

Let me give some examples of set operations in AIMMS:

 

! Initialize the set order pool by assigning all orders initially to it.

s_orderPool := s_allOrders ;

 

! Construct a set of orders based on some condition.

s_orderInProduction := { i_order | bp_orderInProduction( i_order ) } ;

 

! Moving a particular order from one set to another:

ep_thisOrder := First( s_orderPool ); ! As an example, let's move the first order in the pool to the orders in production.

s_orderPool -= ep_thisOrder ; ! Remove the order from the pool.

s_orderInProduction += ep_thisOrder ; ! And add it to the orders in production.

 

Does that help?

 

With kind regards,

 

Chris

Badge +3

Hi @Chris Kuip ,

 

i havent tried it out yet. But i think that was exactly what i was looking 

for. 

 

Thank you very much.

Badge +3

Hey @Chris Kuip,

 

i have one more question regarding that topic.

The Elements in the order set have certain parameters related to them (e.g. due date, process time etc.) How can i assure that when an order moves from one set to another the same parameters are still “attached” to them? 

 

An Answer is much appreciated.

 

With kind regards,

Alex 

Userlevel 5
Badge +7

Hi Alex,

 

Assuming all order subsets are subsets of the set s_allOrders, and the index i_order is an index of the set s_allOrders, then declare the parameter p_dueDate as p_dueDate(i_order).

With such a declaration, moving an order from one subset of s_allOrders to another subset of s_allOrdes does not affect p_dueDate of that order.

 

Does this help?

 

With kind regards,

 

Chris

Badge +3

Hi Alex,

 

Let me give some examples of set operations in AIMMS:

 

! Initialize the set order pool by assigning all orders initially to it. s_orderPool := s_allOrders ;

 

! Construct a set of orders based on some condition. s_orderInProduction := { i_order | bp_orderInProduction( i_order ) } ;

 

! Moving a particular order from one set to another: ep_thisOrder := First( s_orderPool ); ! As an example, let's move the first order in the pool to the orders in production. s_orderPool -= ep_thisOrder ; ! Remove the order from the pool. s_orderInProduction += ep_thisOrder ; ! And add it to the orders in production.

 

Does that help?

 

With kind regards,

 

Chris

Hey @Chris Kuip 

 

My Code is as follows: 

for  (j in OrderPool_AllOrders) do
if(PlannedReleaseDateOfOrder(j) <= TimeLimit) then

endif;
endfor;

 

In the if-Statemtent i want to move all Orders that fullfill the condition from the set OrderPool_AllOrders to the set OrderPool_InTimeLimit. I am not so sure how to do this with the operations mentioned above. 

 

I thought i can maybe do it like this: 

for  (j in OrderPool_AllOrders) do
OrderPool_InTimeLimit := {j | PlannedReleaseDateOfOrder(j) <= TimeLimit} 
endfor;

 

But then i get the error message: There is no operation defined for operator "<=" with arguments of data type element and data type numeric; the arguments themselves are "j $ PlannedReleaseDateOfOrder(j)" and "TimeLimit".

 

Sorry for asking so much questions, but i have never worked with Aimms and the model i have to implement is rather complex for me so i have a lot of points where i cant get it to work :(

 

Thank you in advance and kind regards

Alex

Userlevel 5
Badge +7

Hi Alex,

 

To create the set OrderPool_InTimeLimit you formulated that almost correctly.

 

There are two ways to improve:

 

First, the for statement is obselete, just bind the "j” in the set constructor as follows:

OrderPool_InTimeLimit := {j in OrderPool_AllOrders | some_condition} 

 

Second (assuming PlannedReleaseDateOfOrder(j) is an element parameter), you can indeed not compare an element in an AIMMS set, with a numeric parameter. therefor you want to replace some_condition with something like 

StringToMoment( format, unit, planningStartDate, PlannedReleaseDateOfOrder(j) ) <= TimeLimit

See also: https://documentation.aimms.com/functionreference/elementary-computational-operations/time-functions/stringtomoment.html

 

Let me know if you have questions about the above, or further questions.

 

With kind regards,

 

Chris

 

PS: there is one exception to not being able to compare the an element in an AIMMS set with a numeric parameter; that is when the AIMMS Set is a subset of the set AllIntegers.

Badge +3

Hi @Chris Kuip ,

 

Thank you for your help and time so far. It already helped me a lot, but i still have some problems to get the model to do the exact thing i want.

 

This is the first part, that works ok, in my opinion. (i is the index for the Workingstations and j the index for the Orders):

 

CurrentWorkloadOnStation(i) := StartingWorkloadOfStation(i);
OrderPool_InTimeLimit := {j in OrderPool_AllOrders| PlannedReleaseDateOfOrder(j) <= TimeLimit};
for (j  in OrderPool_InTimeLimit) do
WorkloadIfOrderGetsReleased(i,j) := CurrentWorkloadOnStation(i) + (WorkloadOfOrderOnWorkstation(j,i) / NumberOfWorkstationInRouting(j,i));
endfor;

 

→ In this part i am just setting up the set with Orders that are inside a given time limit and prepare a chart with the Workload Contribution that each order gives to each station.

 

Then the second part is the actual release procedure and here things dont really work out as intended: 

 

for (i in WorkingStations) do
    for (j in OrderPool_InTimeLimit) do
        ThisOrder := First (OrderPool_InTimeLimit);
        if(CurrentWorkloadOnStation (i) + WorkloadIfOrderGetsReleased(i,j) <= WorkloadNormOfWorkstations) then
        CurrentWorkloadOnStation(i) := CurrentWorkloadOnStation(i) + WorkloadIfOrderGetsReleased(i,j);

        OrderPool_InTimeLimit -= ThisOrder;
        OrdersInProduction += ThisOrder;
        else
        OrderPool_NextPeriod += ThisOrder;


        endif;
    endfor;
endfor;

 

→ What should happen is:The first order in the OrderPool_InTimeLimit gets selected and when the workloadcontribution for this order doesnt hurt the WorkloadNorm of any station it gets released and therefore switched to the set OrdersInProduction. If workloadnorms are violated it just gets moved into the next Period, where it will be checked again. 

BUT: The Problem here is i cant seem to view each order seperatly, like i intend to with the Ep “ThisOrder” , cause i cant use the if-statement only for the workload of “ThisOrder”. I also have tried the same code but without all the lines including “ThisOrder” and shifting it between sets but then again the mechanism just releases every possble part until the Workloadnorm for each workstation is met. (For example if Station 1 has still workload left for Order5 it will ad the Workload part from Order 5 for station 1 but not for Station 3 if the workload is already full, so Orders are released partly while they should only be released as a whole). 

 

I know this is very much text, but I hope I could explain my problem in an understandable way and if not feel free to ask where I can explain it better. I am thankyful for every advice I can get.

 

With kind regards, 

Alex

 

Badge +3

Hi @Chris Kuip ,

 

Thank you for your help and time so far. It already helped me a lot, but i still have some problems to get the model to do the exact thing i want.

 

This is the first part, that works ok, in my opinion. (i is the index for the Workingstations and j the index for the Orders):

 

CurrentWorkloadOnStation(i) := StartingWorkloadOfStation(i);
OrderPool_InTimeLimit := {j in OrderPool_AllOrders| PlannedReleaseDateOfOrder(j) <= TimeLimit};
for (j  in OrderPool_InTimeLimit) do
WorkloadIfOrderGetsReleased(i,j) := CurrentWorkloadOnStation(i) + (WorkloadOfOrderOnWorkstation(j,i) / NumberOfWorkstationInRouting(j,i));
endfor;

 

→ In this part i am just setting up the set with Orders that are inside a given time limit and prepare a chart with the Workload Contribution that each order gives to each station.

 

Then the second part is the actual release procedure and here things dont really work out as intended: 

 

for (i in WorkingStations) do
    for (j in OrderPool_InTimeLimit) do
        ThisOrder := First (OrderPool_InTimeLimit);
        if(CurrentWorkloadOnStation (i) + WorkloadIfOrderGetsReleased(i,j) <= WorkloadNormOfWorkstations) then
        CurrentWorkloadOnStation(i) := CurrentWorkloadOnStation(i) + WorkloadIfOrderGetsReleased(i,j);

        OrderPool_InTimeLimit -= ThisOrder;
        OrdersInProduction += ThisOrder;
        else
        OrderPool_NextPeriod += ThisOrder;


        endif;
    endfor;
endfor;

 

→ What should happen is:The first order in the OrderPool_InTimeLimit gets selected and when the workloadcontribution for this order doesnt hurt the WorkloadNorm of any station it gets released and therefore switched to the set OrdersInProduction. If workloadnorms are violated it just gets moved into the next Period, where it will be checked again. 

BUT: The Problem here is i cant seem to view each order seperatly, like i intend to with the Ep “ThisOrder” , cause i cant use the if-statement only for the workload of “ThisOrder”. I also have tried the same code but without all the lines including “ThisOrder” and shifting it between sets but then again the mechanism just releases every possble part until the Workloadnorm for each workstation is met. (For example if Station 1 has still workload left for Order5 it will ad the Workload part from Order 5 for station 1 but not for Station 3 if the workload is already full, so Orders are released partly while they should only be released as a whole). 

 

I know this is very much text, but I hope I could explain my problem in an understandable way and if not feel free to ask where I can explain it better. I am thankyful for every advice I can get.

 

With kind regards, 

Alex

 

 Another try I did looked like this:

 

ThisOrder := first (OrderPool_InTimeLimit);
CurrentOrder += ThisOrder;

for (j in CurrentOrder) do
    for (i in WorkingStations) do        
        if(CurrentWorkloadOnStation (i) + WorkloadIfOrderGetsReleased(j,i) <= WorkloadNormOfWorkstations(i)) then
        CurrentWorkloadOnStation(i) := CurrentWorkloadOnStation(i) + WorkloadIfOrderGetsReleased(j,i);
        CurrentOrder -= ThisOrder;
        OrdersInProduction += ThisOrder;

        endif;
    endfor;    
endfor;


This allows me to release only  the first order, but i cant figure out how to repeat this process until the Set OrderPool_InTimeLimit is empty.

Reply


Didn't find what you were looking for? Try searching on our documentation pages:

AIMMS Developer & PRO | AIMMS How-To | AIMMS SC Navigator