I am re-developing a legacy system that matches a basket of user selected retail products into one or more valid promotions. These promotions are the industry standard BOGOF (buy one get one free), buy two get third free, buy product X and Y and get 10% off, etc... but all require that you can filter the list of potential items into those that satisfy these promotions.
I would like the solution to take an entire basket of retail items and analyse them in one operation, as opposed to the incumbent method of matching a single product as and when it is ordered. (The current solution leads to undesirable limitations)
Each promotion has a series of qualifying products that must be present in order to trigger the promotion. These are arranged in n number of sets (or positions), for example:
Example "Buy two get third free" Promotion =
| Item 1 | | Item 1 | | Item 2 |
| or | | or | | or |
| Item 2 | AND | Item 4 | AND | Item 6 |
| or | | or | | or |
| Item 3 | | Item 9 | | Item 4 |
Set 1 Set 2 Set 3
Each promotion must have exactly one product from each group present, unless the item appears in the same set multiple times. The promotion can have an unlimited (but usually < 10) 'sets' of products.
As a simple example a shopping basket of Item 1, Item 4 and Item 6
would trigger the promotion,
similarly the basket of Item 1, Item 1 and Item 2
would also trigger it.
However the basket of Item 1, Item 2 and Item 3
would not as each set is not satisfied.
Aside from the obivious question of the best way to detect when a promotion has been triggered, I will also need to recover the set (position) that the item had been matched into to handle the detail of the pricing etc. It would also be desirable if more expensive (in currency terms) items are favoured over less expensive (equally matched) items when assigning them to the promotion.
Hopefully the next part will aid a solution, not sound so unclear that it will create unnecessary noise, feel free to disregard !
My best solution so far is to create a new set for each retail item in the "shopping basket" holding the promotion set (position) that this item will satisfy. ie.
Item 1 satisifies sets: {1,2}
Item 4 satisifies sets: {2,3}
Item 6 satisifies sets: {3}
Then my theory is that you "check" that this list of sets contains a unique item in each position and that each promotion position is filled. So far my working examples all use brute force, loops or recursion to produce all combinations of the sets (above) in an attempt to check if there is a unique combination. This scales very very badly and with anything other than a very trivial example doesn't work at all in the real world. (This function will be called in realtime as items are added to a basket, so needs to be quick)
Lots of research suggest that Bipartite matching would produce some desired outcome, but I can only find research articles and fairly complex mathematical texts on the subject. Some pseudo code or basic logic would be great.
My two questions are basically:
1) Does anybody see a better/quicker/simpler way of analysing the customer basket to produce matching promotions.
2) Assuming I have identified the most efficient way of matching items into the relevant positions, what is the least expensive way of determining the list of retail items to record against the promotion.
Any assistance would be gratefully received as I can no longer see light at the end of the tunnel! (The final solution will be in .NET and we use SQL server 2008 R2.)