Skip to content
Nested Dynamic loop...
 
Notifications
Clear all

Nested Dynamic loops

2 Posts
2 Users
0 Likes
750 Views
Avatar
Posts: 1
Customer
Topic starter
(@mfu4yepi9wzzwtzoiharrlfp77l1)
New Member
Joined: 2 years ago

Hello.

 

I am trying to set up the following flow using a Dynamic loop within another, but I am coming up against warning message 41302 (and anomalous results). The * is meant to represent an additional level of depth on top of the bullet.

 

Portfolio start (Dynamic over Time (x1 = Initial contracts, a decision variable, x = Portfolio_end[Time-1]) )

  • Used capacity
  • Total available capacity 
  • Capacity available for each buyer (Dynamic over the Buyers index (x1 = Total available capacity, x = self[Buyers-1] - Sales Aggregate[Buyers-1]) )
  • * Sales = if Capacity available for each buyer > 0 and some other conditions then output an Array using the same index as Portfolio start
  • * Sales Aggregate = convert Sales into a simpler index, because at this point I only need to keep track of the capacity, not the additional information that Sales generates
  • Portfolio changes = Sales. We've exited the Buyers loop, but need to insert the Sales info into the Portfolio. This is what triggers the warning.

Portfolio end = Portfolio start + Portfolio changes

 

Aside from the Time index, Portfolio start, end and Sales are indexed by Buyers (just a 1..10 list of rows) and Field (which holds various features of their contracts, including Capacity). Used and Total available Capacity are only indexed by Time. Capacity available for each buyer is also indexed by Buyers and cascades the available capacity down the list. Sales Aggregate also inherits the Buyers index.

 

How can I work myself out of this jam? The example model Dynamic on multiple indexes is very helpful, but it has no equivalent for Sales being reinserted into the starting position.

 

Thanks!

1 Reply
Avatar
Posts: 25
Moderator
(@drice)
Member
Joined: 3 years ago

The error 41302 means that you're operating over the dynamic index inside the dynamic loop, which is not allowed. It is worth understanding the conceptual reason for why this isn't allowed first.

The common case (which sounds like your case) involves Summing over the index. Consider a simple dynamic over Time.

Variable A ::= Dynamic( startA, Sum(B,Time)+B[Time-1] )
Variable B ::= F(A)

This issue is that when it needs to compute, say, A[Time=4], it needs the value of B over every time index, which then needs the value of A[Time=4]. Thus, it would need to know the value of A[Time=4] in order to compute A[Time=4].  This issue happens generally whenever you use any array function, Fun( x, I ), with the dynamic index for the index parameter.

In the case of Sum, often what one actually needs is not Sum(B,Time), but rather just the sum of B across previous time points (i.e., a cumulation). But since Cumulate(x,I) is an array function (i.e., it operates over the entire array), you can't simply use it. But you can just add a new variable the cumulates A:

Variable cumB ::= Dynamic( 0, self[Time-1] + B[Time-1] )
Variable A ::= Dynamic( startA, cumB + B[Time-1] )

As I understand your problem, you have a Dynamic[Buyer](...) loop that is logically nested inside Dynamic[Time](...). You are thinking that the inner Buyer loop should be able to continue to completion for each Time point, so that a Sum( *, Buyer ) wouldn't create loop, at least in theory. However, it does -- when there are multiple Dynamic loops over different indexes, Analytica sees that as a single Dynamic loop. In the general case, there isn't always a clear-cut nesting, and the algorithm allows cell-level dependencies to be in any order within the 2-D grid. Because it is considered to be the same dynamic loop, it means that the limit of operating over Buyer applies as well.

It sounds to me that the above "trick" should work fine for your use case. In other words, your Sales_aggregate variable will be something like

Variable Sales_aggregate ::= Dynamic[Buyer]( sales, self[Buyer-1] + sales )

Since you are actually modeling available capacity, and then distributing that across buyer, I would bet you could do this more elegantly without having any dynamic loop over Buyer -- just one loop over Time -- and instead use the Dispatch function to handle the capacity allocation. I don't know your specific logic, but if it were me I would definitely try using Dispatch first before going to a more complex multiple-index Dynamic.

 

 

 

 

Reply
Share: