Recursive derivation on ordered-graph: first free delivery

Hi there,

I am trying to get to the first available Delivery with free quantity. The code below does not work because the dependencies of the ‘Delivery’ = assignments are not correct. How can this be done?

'Deliveries': collection ['ID'] 'Consumption Order': ordered-graph .'Previous Delivery' ( ?'No' || ?'Yes'>'Previous Delivery' ) {
	'ID': text
	'Previous Delivery': stategroup (
		'No' { }
		'Yes' {
			'Previous Delivery': text -> ^ sibling in ( 'Consumption Order' )
		}
	)
	'Free Quantity': number '10^-2 quantity unit' = // assume this it the free quantity
	'Has Free Quantity': stategroup = switch . 'Free Quantity' compare ( 0 ) (
		| > => 'Yes' ( )
		| <= => 'No' ( )
	) (
		'No' { }
		'Yes' { }
	)
	'First Free Delivery': stategroup = ( recurse 'Consumption Order' ) switch . 'Previous Delivery' (
		| 'No' => switch . 'Has Free Quantity' (
			| 'No' => 'Not Available' ( )
			| 'Yes' as $ => 'Available' where 'Delivery' = $ ( )
		)
		| 'Yes' as $ => switch $ > 'Previous Delivery' . 'First Free Delivery' (
			| 'Not Available' => switch . 'Has Free Quantity' (
				| 'No' => 'Not Available' ( )
				| 'Yes' as $ => 'Available' where 'Delivery' = $ ( )
			)
			| 'Available' as $ => 'Available' where 'Delivery' = $ .& 'Delivery' ( )
		)
	) (
		'Not Available' { }
		'Available' where 'Delivery' -> sibling . 'Has Free Quantity'?'Yes' {
		}
	)
}

According to your code, the Delivery is possibly a self reference. The reference type signature has to express that with || self. But, if you do that, you run into another error.

The language does not allow a self reference step (or unbounded sibling navigation step) in a recursive computation. Only sibling reference steps for traversing the specified graph (Consumption Order) are allowed. You can solve it like this:

'Deliveries': collection ['ID'] 'Consumption Order': ordered-graph .'Previous Delivery' ( ?'No' || ?'Yes'>'Previous Delivery' ) {
	'ID': text
	'Previous Delivery': stategroup (
		'No' { }
		'Yes' {
			'Previous Delivery': text -> ^ sibling in ( 'Consumption Order' )
			'Previous Free Delivery': stategroup = ( recurse ^ 'Consumption Order' ) switch >'Previous Delivery'.'Has Free Quantity' (
				| 'No' => switch >'Previous Delivery'.'Previous Delivery' (
					|'No' => 'Not Available' ( )
					|'Yes' as $ => switch $ .'Previous Free Delivery' (
						|'Available' as $ => 'Available' where 'Delivery' = $ .&'Delivery' ( )
						|'Not Available' => 'Not Available' ( )
					)
				)
				| 'Yes' as $ => 'Available' where 'Delivery' = $ ( )
			) (
				'Not Available' { }
				'Available' where 'Delivery' -> ( recurse ^ 'Consumption Order' ) ^ sibling in ('Consumption Order') . 'Has Free Quantity'?'Yes' { }
			)
		}
	)
	'Free Quantity': number '10^-2 quantity unit' // assume this it the free quantity
	'Has Free Quantity': stategroup = switch . 'Free Quantity' compare ( 0 ) (
		| > => 'Yes' ( )
		| <= => 'No' ( )
	) (
		'No' { }
		'Yes' { }
	)
	// If you need 'Nearest Free Delivery' on this level
	// (note that this computation is not recursive):
	'Nearest Free Delivery': stategroup = switch .'Has Free Quantity' (
		|'No' => switch .'Previous Delivery' (
			|'No' => 'Not Available' ( )
			|'Yes' as $ => switch $ .'Previous Free Delivery' (
				|'Not Available' => 'Not Available' ( )
				|'Available' as $ => 'Available' where 'Delivery' = $ .&'Delivery' ( )
			)
		)
		|'Yes' as $ => 'Available' where 'Delivery' = $ ( )
	) (
		'Not Available' { }
		'Available' where 'Delivery' -> sibling || self .'Has Free Quantity'?'Yes' { }
	)
}

Ok, the problem is that I would like to get the first free delivery:

A: 0 units, FFD: NO
B: 2 units, FFD: B
C: 4 units, FFD: B
D: 3 units, FFD: B

Last delivery: D, FFD: B

But I guess the same logic applies: make the recursive derivation so that the first free delivery itself does not point to itself.

Yes, that is correct. But then, worst case every Deliveries item requires updating when the Free Quantity of the first free delivery changes, which is rather inefficient. In addition, it does not make much sense to show an identical first free delivery on each Deliveries item.

Instead you could derive the First Free Delivery once, for all Deliveries:

'Has Delivery': stategroup = switch .'Deliveries'* (
	| nodes as $ => 'Yes' where 'First' = sink-of $ * in 'Consumption Order' ( )
	| none => 'No' ( )
) (
	'Yes' where 'First' -> .'Deliveries'[] {
		'Has Free Delivery': stategroup = switch .&'First'.'Has Free Quantity' (
			|'No' => switch .&'First'.'Next Delivery' ( // NOTE: you'll need to derive the next delivery or change the order of your graph
				|'No' => 'No' ( )
				|'Yes' as $ => switch $ .'Next Free Delivery' (
					|'Not Available' => 'No' ( )
					|'Available' as $ => 'Yes' where 'First Free Delivery' = $ .&'Delivery' ( )
				)
			)
			|'Yes' as $ => 'Yes' where 'First Free Delivery' = $ ( )
		) (
			'No' { }
			'Yes' where 'First Free Delivery' -> ^ .'Deliveries'[] .'Has Free Quantity'?'Yes' { }
		)
	}
	'No' { }
)

Ok, that seems a bit better than what I had, indeed. Thanks!