Optimal order fulfillment - algorithm

I have the following problem. A user has a cart with N items in it. There is a quantity Q of each item. Further, there are P warehouses, and each of them has a certain stock level for each product (which may be 0). Distances between each warehouse and customer are also known. I need to find a set of warehouses that can accommodate the orders and satisfies the following constraints (ordered by decreasing priority):
It should contain a minimal number of warehouses
All warehouses should be as close to customer as it possible.
Any ideas are highly appreciated. Thanks!
UPD:
If one warehouse can't fulfill some line item completely, then it can be delivered by several different warehouses. E.g. we need 10 apples and we have 2 warehouses that have stock levels of 7 and 3. Then apples will be provided by these two warehouses (to provide 10 in total).
UPD 2
Number of available warehouses is nearly 15. So brute force won't help here.

This is solvable by integer programming.
Let items be indexed by i and warehouses be indexed by j. Let Qi be the quantity of item i in the cart and Sij be the quantity of item i at warehouse j and Dj be the distance from the customer to the warehouse j.
First find the minimum warehouse count k. Let binary variable xj be 1 if and only if warehouse j is involved in the order. k is the value of this program.
minimize sum over j of xj
subject to
for all i, (sum over j of min(Sij, Qi) * xj) >= Qi
for all j, xj in {0, 1}
Second find the closest warehouses. I'm going to assume that we want to minimize the sum of the distances.
minimize sum over j of Dj * xj
subject to
for all i, (sum over j of min(Sij, Qi) * xj) >= Qi
(sum over j of xj) <= k
for all j, xj in {0, 1}
There are many different libraries to solve integer programs, some free/open source. They typically accept programs in a format similar to but more restricted than the one I've presented here. You'll have to write some code yourself to expand the sums and universal quantifiers ("for all").

I would recommend to go with David Eisenstat's solution. If you'd like to understand more about the topic or need to implement an algorithm for solving integer programs yourself, I can recommend the following reference:
Chapter 9 from an MIT lecture on Applied Mathematical Programming gives a nice introduction into integer programming. On the third page, you find the warehouse location problem as an example of a problem solvable by integer programming. Note that the problem described there is slightly more general than the problem you described in your question: For your case, warehouses can be assumed to be always open (yi = 1), and the fixed operating cost fi of a warehouse is always fi = 0 in your case.
The rest of this chapter goes into the details of integer programming and also highlights various approaches to solve integer programs.

You may or may not like this, but I have warehousing and order fulfillment processing experience. My personal real life experience didn't require an algo but a series of warehouse and customer service back tools (hopefully this will be food for thought to you and others struggling in the warehousing operations development world):
If you have 10 items on the order.
You have 9 in stock
You have 5 in one location and 4 in the other.
You split the order. The 1 product that can't be fulfilled becomes a 'back order'. It can be cancelled because you don't know when you or if your supplier is going to deliver. Make sure you hang on to your credit card authorization references.
The 9 left over (fulfill-able products) in stock will be queried against your warehousing virtual inventory for the best combinations.
In our case we do three things:
Can the fulfillment staff at a warehouse X transfer in the item from another warehouse easily? Yes/No
If so which products can transfer.
This might require human interaction based on warehouse load and capabilities.
If you are strictly going on automation and virtual inventory that fluctuates day in and day out, then you give it your best guess against warehouse inventories.
Next, split the order to two, with references to the main order for paper trails.
You then print to your destinations and hope they can fulfill, if they can't, then hopefully they can partially fulfill the order and generate back order that can be cancelled at the customer's request.
So basically here is what you have to code for.
Order
First glance back order split and reference to main order.
Inventory warehouse feeler function.
Weighted split order based on virtual inventory with reference to main order based on warehouse capabilities to retrieve products from other warehouses.
Print pick page (warehouse function)
Back order or partial fulfillment manual functions (customer service tools)
Collect the money on only the stuff you fulfilled when marked as shipped.
Considerations:
Make sure the main order references the actions back order and splits.
Make sure the splits and partial fulfillment orders references any additional back order and splits.
Fullfill what you can
Mark a shipped.
Collect $$$ on the products that shipped.
Hope this helps and good luck!!!

Related

Optimize event seat assignments with Corona restrictions

Problem:
Given a set of group registrations, each for a varying number of people (1-7),
and a set of seating groups (immutable, at least 2m apart) varying from 1-4 seats,
I'd like to find the optimal assignment of people groups to seating groups:
People groups may be split among several seating groups (though preferably not)
Seating groups may not be shared by different people groups
(optional) the assignment should minimize the number of 'wasted' seats, i.e. maximize the number of seats in empty seating groups
(ideally it should run from within a Google Apps script, so memory and computational complexity should be as small as possible)
First attempt:
I'm interested in the decision problem (is it feasible?) as well as the optimization problem (see optional optimization function). I've modeled it as a SAT problem, but this does not find an optimal solution.
For this reason, I've tried to model it as an optimization problem. I'm thinking along the lines of a (remote) variation of multiple-knapsack, but I haven't been able to name it yet:
items: seating groups (size -> weight)
knapsacks: people groups (size -> container size)
constraint: combined item weight >= container size
optimization: minimize the number of items
As you can see, the constraint and optimization are inverted compared to the standard problem. So my question is: Am I on the right track here or would you go about it another way? If it's correct, does this optimization problem have a name?
You could approach this as an Integer Linear Programming Problem, defined as follows:
let P = the set of people groups, people group i consists of p_i people;
let T = the set of tables, table j has t_j places;
let x_ij be 1 if people from people group i are placed at table j, 0 otherwise
let M be a large penalty factor for empty seats
let N be a large penalty factor for splitting groups
// # of free spaces = # unavailable - # occupied
// every time a group uses more than one table,
// a penalty of N * (#tables - 1) is incurred
min M * [SUM_j(SUM_i[x_ij] * t_j) - SUM_i(p_i)] + N * SUM_i[(SUM_j(x_ij) - 1)]
// at most one group per table
s.t. SUM_i(x_ij) <= 1 for all j
// every group has enough seats
SUM_j(x_ij * t_j) = p_i for all i
0 <= x_ij <= 1
Although this minimises the number of empty seats, it does not minimise the number of tables used or maximise the number of groups admitted. If you'd like to do that, you could expand the objective function by adding a penalty for every group turned away.
ILPs are NP-hard, so without the right solvers, it might not be possible to make this run with Google Apps. I have no experience with that, so I'm afraid I can't help you. But there are some methods to reduce your search space.
One would be through something called column generation. Here, the problem is split into two parts. The complex master problem is your main research question, but instead of the entire solution space, it tries to find the optimum from different candidate assignments (or columns).
The goal is then to define a subproblem that recommends these new potential solutions that are then incorporated in the master problem. The power of a good subproblem is that it should be reducable to a simpler model, like Knapsack or Dijkstra.

Formal name for this optimization algorithm?

I have the following problem in one of my coding project which I will simplify here:
I am ordering groceries online and want very specific things in very specific quantities. I would like to order the following:
8 Apples
1 Yam
2 Soups
3 Steaks
20 Orange Juices
There are many stores equidistant from me which I will have food delivered from. Not all stores have what I need. I want to obtain what I need with the fewest number of orders made. For example, ordering from Store #2 below is a wasted order, since I can complete my items in less orders by ordering from different stores. What is the name of the optimization algorithm that solves this?
Store #1 Supply
50 Apples
Store #2 Supply
1 Orange Juice
2 Steaks
1 Soup
Store #3 Supply
25 Soup
50 Orange Juices
Store #4 Supply
25 Steaks
10 Yams
The lowest possible orders is 3 in this case. 8 Apples from Store #1. 2 Soup and 20 Orange Juice from Store #3. 1 Yam and 3 Steaks from Store #4.
To me, this most likely sounds like a restricted case of the Integer Linear programming problem (ILP), namely, its 0-or-1 variant, where the integer variables are restricted to the set {0, 1}. This is known to be NP-hard (and the corresponding decision problem is NP-complete).
The problem is formulated as follows (following the conventions in the op. cit.):
Given the matrix A, the constraint vector b, and the weight vector c, find the vector x ∈ {0, 1}N such that all the constraints A⋅x ≥ b are satisfied, and the cost c⋅x is minimal.
I flipped the constraint inequality, but this is equivalent to changing the sign of both A and b.
The inequalities indicate satisfaction of your order: that you can buy at the least the amount of every item in the visited store. Note that b has the same length as the number of rows in A and the number of columns in both c and x. The dot-product c⋅x is, naturally, a scalar.
Since you are minimizing the number of trips, each trip costs the same, so that c = 1, and c⋅x is the total number of trips. The store inventory matrix A has a row per item, and a column per store, and the b is your shopping list.
Naturally, the exact best solution is found by trying all possible 2N values for the x.
Since there is no single approach to NP-hard problems, consider the problem size, and how close to the optimum you want to arrive. A greedy approach would work well (when your next store to visit has the most total number of items not yet satisfied) when the "inventories" are large. If you have the idea in advance about the expected minimum number of trips, you can trim the search beam at some value, exceeding the number of trips by some multiplication coefficient. This is the best approach when your search is time constrained (I routinely do beam searches, closely related to the branch-and-cut approach mentioned in the article, in graphs that take a few GB of memory slightly faster than the limit of 30ms per exploration step with a beam as wide as 10,000). Simulated annealing also works, if the search landscape is not excessively rough.
Also search on cs.SE; it may be even a better place for questions of this type.

How do I calculate the most profit-dense combination in the most efficient way?

I have a combinations problem that's bothering me. I'd like someone to give me their thoughts and point out if I'm missing some obvious solution that I may have overlooked.
Let's say that there is a shop that buys all of its supplies from one supplier. The supplier has a list of items for sale. Each item has the following attributes:
size, cost, quantity, m, b
m and b are constants in the following equation:
sales = m * (price) + b
This line slopes downward. The equation tells me how many of that item I will be able to sell if I charge that particular price. Each item has its own m and b values.
Let's say that the shop has limited storage space, and limited funds. The shop wants to fill its warehouse with the most profit-dense items possible.
(By the way, profit density = profit/size. I'm defining that profit density be only with regard to the items size. I could work with the density with regard to size and cost, but to do that I'd have to know the cost of warehouse space. That's not a number I know currently, so I'm just going to use size.)
The profit density of items drops the more you buy (see below.)
If I flip the line equation, I can see what price I'd have to charge to sell some given amount of the item in some given period of time.
price = (sales-b)/m
So if I buy n items and wanted to sell all of them, I'd have to charge
price = (n-b)/m
The revenue from this would be
price*n = n*(n-b)/m
The profit would be
price*n-n*cost = n*(n-b)/m - n*cost
and the profit-density would be
(n*(n-b)/m - n*cost)/(n*size)
or, equivalently
((n-b)/m - cost)/size
So let's say I have a table containing every available item, and each item's profit-density.
The question is, how many of each item do I buy in order to maximise the amount of money that the shop makes?
One possibility is to generate every possible combination of items within the bounds of cost and space, and choose the combo with the highest profitability. In a list of 1000 items, this takes too long. (I tried this and it took 17 seconds for a list of 1000. Horrible.)
Another option I tried (on paper) was to take the top two most profitable items on the list. Let's call the most profitable item A, the 2nd-most profitable item B, and the 3rd-most profitable item C. I buy as many of item A as I can until it's less profitable than item B. Then I repeat this process using B and C, for every item in the list.
It might be the case however, that after buying item B, item A is again the most profitable item, more so than C. So this would involve hopping from the current most profitable item to the next until the resources are exhausted. I could do this, but it seems like an ugly way to do it.
I considered dynamic programming, but since the profit-densities of the items change depending on the amount you buy, I couldn't come up with a resolution for this.
I've considered multiple-linear regression, and by 'consider' I mean I've said to myself "is multi-linear regression an option?" and then done nothing with it.
My spidey-sense tells me that there's a far more obvious method staring me in the face, but I'm not seeing it. Please help me kick myself and facepalm at the same time.
If you treat this as a simple exercise in multivariate optimization, where the controllable variables are the quantities bought, then you are optimizing a quadratic function subject to a linear constraint.
If you use a Lagrange multiplier and differentiate then you get a linear equation for each quantity variable involving itself and the Lagrange multiplier as the only unknowns, and the constraint gives you a single linear equation involving all of the quantities. So write each quantity as a linear function of the Lagrange multiplier and substitute into the constraint equation to get a linear equation in the Lagrange multiplier. Solve this and then plug the Lagrange multiplier into the simpler equations to get the quantities.
This gives you a solution if you are allowed to buy fractional and negative quantities of things if required. Clearly you are not, but you might hope that nothing is very negative and you can round the non-integer quantities to get a reasonable answer. If this isn't good enough for you, you could use it as a basis for branch and bound. If you make an assumption on the value of one of the quantities and solve for the others in this way, you get an upper bound on the possible best answer - the profit predicted neglecting real world constraints on non-negativity and integer values will always be at least the profit earned if you have to comply with these constraints.
You can treat this as a dynamic programming exercise, to make the best use of a limited resource.
As a simple example, consider just satisfying the constraint on space and ignoring that on cost. Then you want to find the items that generate the most profit for the available space. Choose units so that expressing the space used as an integer is reasonable, and then, for i = 1 to number of items, work out, for each integer value of space up to the limit, the selection of the first i items that gives the most return for that amount of space. As usual, you can work out the answers for i+1 from the answers for i: for each value from 0 up to the limit on space just consider all possible quantities of the i+1th item up to that amount of space, and work out the combined return from using that quantity of the item and then using the remaining space according to the answers you have already worked out for the first i items. When i reaches the total number of items you will be working out the best possible return for the problem you actually want to solve.
If you have constraints for both space and cost, then the state of the dynamic program is not the single variable (space) but a pair of variables (space, cost) but you can still solve it, although with more work. Consider all possible values of (space, cost) from (0, 0) up to the actual constraints - you have a 2-dimensional table of returns to compute instead of a single set of values from 0 to max-space. But you can still work from i=1 to N, computing the highest possible return for the first i items for each limit of (space, cost) and using the answers for i to compute the answers for i+1.

If you know the future prices of a stock, what's the best time to buy and sell?

Interview Question by a financial software company for a Programmer position
Q1) Say you have an array for which the ith element is the price of a given stock on
day i.
If you were only permitted to buy one share of the stock and sell one share
of the stock, design an algorithm to find the best times to buy and sell.
My Solution :
My solution was to make an array of the differences in stock prices between day i and day i+1 for arraysize-1 days and then use Kadane Algorithm to return the sum of the largest continuous sub array.I would then buy at the start of the largest continuous array and sell at the end of the largest
continous array.
I am wondering if my solution is correct and are there any better solutions out there???
Upon answering i was asked a follow up question, which i answered exactly the same
Q2) Given that you know the future closing price of Company x for the next 10 days ,
Design a algorithm to to determine if you should BUY,SELL or HOLD for every
single day ( You are allowed to only make 1 decision every day ) with the aim of
of maximizing profit
Eg: Day 1 closing price :2.24
Day 2 closing price :2.11
...
Day 10 closing price : 3.00
My Solution: Same as above
I would like to know what if theres any better algorithm out there to maximise profit given
that i can make a decision every single day
Q1 If you were only permitted to buy one share of the stock and sell one share of the stock, design an algorithm to find the best times to buy and sell.
In a single pass through the array, determine the index i with the lowest price and the index j with the highest price. You buy at i and sell at j (selling before you buy, by borrowing stock, is in general allowed in finance, so it is okay if j < i). If all prices are the same you don't do anything.
Q2 Given that you know the future closing price of Company x for the next 10 days , Design a algorithm to to determine if you should BUY,SELL or HOLD for every single day ( You are allowed to only make 1 decision every day ) with the aim of of maximizing profit
There are only 10 days, and hence there are only 3^10 = 59049 different possibilities. Hence it is perfectly possible to use brute force. I.e., try every possibility and simply select the one which gives the greatest profit. (Even if a more efficient algorithm were found, this would remain a useful way to test the more efficient algorithm.)
Some of the solutions produced by the brute force approach may be invalid, e.g. it might not be possible to own (or owe) more than one share at once. Moreover, do you need to end up owning 0 stocks at the end of the 10 days, or are any positions automatically liquidated at the end of the 10 days? Also, I would want to clarify the assumption that I made in Q1, namely that it is possible to sell before buying to take advantage of falls in stock prices. Finally, there may be trading fees to be taken into consideration, including payments to be made if you borrow a stock in order to sell it before you buy it.
Once these assumptions are clarified it could well be possible to take design a more efficient algorithm. E.g., in the simplest case if you can only own one share and you have to buy before you sell, then you would have a "buy" at the first minimum in the series, a "sell" at the last maximum, and buys and sells at any minima and maxima inbetween.
The more I think about it, the more I think these interview questions are as much about seeing how and whether a candidate clarifies a problem as they are about the solution to the problem.
Here are some alternative answers:
Q1) Work from left to right in the array provided. Keep track of the lowest price seen so far. When you see an element of the array note down the difference between the price there and the lowest price so far, update the lowest price so far, and keep track of the highest difference seen. My answer is to make the amount of profit given at the highest difference by selling then, after having bought at the price of the lowest price seen at that time.
Q2) Treat this as a dynamic programming problem, where the state at any point in time is whether you own a share or not. Work from left to right again. At each point find the highest possible profit, given that own a share at the end of that point in time, and given that you do not own a share at the end of that point in time. You can work this out from the result of the calculations of the previous time step: In one case compare the options of buying a share and subtracting this from the profit given that you did not own at the end of the previous point or holding a share that you did own at the previous point. In the other case compare the options of selling a share to add to the profit given that you owned at the previous time, or staying pat with the profit given that you did not own at the previous time. As is standard with dynamic programming you keep the decisions made at each point in time and recover the correct list of decisions at the end by working backwards.
Your answer to question 1 was correct.
Your answer to question 2 was not correct. To solve this problem you work backwards from the end, choosing the best option at each step. For example, given the sequence { 1, 3, 5, 4, 6 }, since 4 < 6 your last move is to sell. Since 5 > 4, the previous move to that is buy. Since 3 < 5, the move on 5 is sell. Continuing in the same way, the move on 3 is to hold and the move on 1 is to buy.
Your solution for first problem is Correct. Kadane's Algorithm runtime complexity is O(n) is a optimal solution for maximum subarray problem. And benefit of using this algorithm is that it is easy to implement.
Your solution for second problem is wrong according to me. What you can do is to store the left and right index of maximum sum subarray you find. Once you find have maximum sum subarray and its left and right index. You can call this function again on the left part i.e 0 to left -1 and on right part i.e. right + 1 to Array.size - 1. So, this is a recursion process basically and you can further design the structure of this recursion with base case to solve this problem. And by following this process you can maximize profit.
Suppose the prices are the array P = [p_1, p_2, ..., p_n]
Construct a new array A = [p_1, p_2 - p_1, p_3 - p_2, ..., p_n - p_{n-1}]
i.e A[i] = p_{i+1} - p_i, taking p_0 = 0.
Now go find the maximum sum sub-array in this.
OR
Find a different algorithm, and solve the maximum sub-array problem!
The problems are equivalent.

Shopping cart minimization algorithm

I have a list of products, which consists of list of shops, which sold it.
{
'Book A': [ShopA, ShopB, ShopC],
'Book B': [ShopC, ShopD],
'Movie C': [ShopA, ShopB, ShopD, ShopE],
...
}
(Price differs between the shops)
Each shop is also has a shipping cost. It's a "per-order" shipping cost, it doesn't matter how many items are in my cart. And it differs between the shops too.
Ex: if I buy "Book A" from ShopA, "Book B" from ShopC and "Movie C" from ShopA, the resulting price is: Book A price in ShopA + Book B price in ShopC + Movie C price in ShopA + ShopC shipping cost + ShopA shipping cost
If the shipping cost was zero or it was on per-item basis and constant, than I would just sort the offer lists by price+shipping field and fetch the first result from each set.
I need to buy all the items once and find the minimal price and the resulting set.
I'm not very good with optimization algorithms and dynamic programming so I need a solution or just a nod into the right direction.
This problem is NP Hard.
We will show a reduction from the Hitting Set problem.
Hitting Set problem: Given sets S1,S2,...,Sn and a number k: chose set S of size k, such that for every Si there is an element s in S such that s is in Si. [alternative definition: the intersection between each Si and S is not empty].
Reduction:
Given an instance of hitting set, in the form of (S1,...,Sn,k) create an instance of this problem:
All books cost nothing. In order to buy from each store you pay 1.
The book i is sold by each store denoted in Si, minimal price for this instance is k.
proof:
Hitting Set -> This problem: Assume there is a minimal hitting set in (S1,...,Sn) of size k. Let this hitting set be S. By buying from each store in S, we can buy all our books at cost k, since the books cost nothing [in our construction], and we bought all books, and we paid for the ordering from stores exactly k, thus the total price was k.
This problem -> Hitting set: Assume there is a pricing of k for the problem at the question. Then, from the building of the problem, and since the books cost nothing, we need to buy in k different stores to get all books. Let these stores be S. From the construction of the problem, S is a hitting set for (S1,...,Sn)
Q.E.D.
Conclusion:
Thus, this problem is "not easier then" Hitting Set Problem, and there is no known polynomial solution for this problem, so - your best shot, if you want optimal solution, is probably an exponential one, such as backtracking [Check all possibilities, and return the minimal solution].
With so little items I have a solution. It is dynamic.
We will process every shop iteratively. At every step we store the current best price with which we can cover all subsets of items. In the beginning all of them are infinity in price except for the empty subset which is 0 of price. Note that all subsets are 2^Num_products in count but in your case these are only about 1000.
Now how do we process the next to follow shop: Consider you cover every possible subset of the products with this shop (i mean subset that the shop can actually provide) and all the rest of the products being covered by shops you already observed, thus improving the minimal costs of covering every subset. This step takes 2^Num_products*2^Num_products=4^Num_products, still about a million which is bareable. You do this for every shop and at the end the answer is the cost of covering all the elements. The whole complexity of the proposed solution is 4^Num_products * num_shops which is about 50 million which is good to go.
Note that this is still exponential and this is not surprising. Thank you to amit for his incredible proof of NP hard.
EDIT Adding further explanation of the algorithm in pseudocode:
init:
cost[subset] = infi
cost[{}] = 0
for shop in shops
new_prices = costs.dup()
for set : subsets
for covered_set : all_subsets(set)
price = covered_set == {} ? 0 : delivery[shop]
remaining = set
for element : covered_set
if shop do not sale element
break for, choose next covered_set
price += el_price[element]
remaining.remove(element)
price += costs[remaining]
new_prices[set] = min(new_prices[set], price)
costs = new_prices
return costs[all]
Note that here I use sets as index - this is because I actually use the bitmask representation of the subsets e.g 1101 is a subset containing the 1st, 2nd and the forth element. Thus an iteration of all sets is for (int i = 0; i < (1 << n); i++).
There is also one more thing: if you want to cycle all the subsets of a subset S you can actually do it faster than iterating all the subsets of the initial set and checking whether the subset is subset of S. If S is also represented with bitmask bit_mask this for loop does the job: for(int i = bit_mask; i > 0; i = (i - 1) & bitmask). Using this approach you decrease the complexity of the algorithm to 3^Num_products * num_shops. However, this is a bit harder to understand and you will probably need to write by hand one example to make sure the loop I wrote actually cycles all the subsets of S. About the complexity - just trust me.
EDIT2 Edited the break condition. also let me elaborate on the set remaining and its calculation: as dmzkrsk pointed out the pseudocode mentions removal from the set, but you can actually just assign remaining = set ^ covered_set (again bit operation) in case of using bitmasks to represent the subsets.
I have dealt with this exact problem once. I didn't come up with any other solution than just testing every possible combination of shops but there is an easy way to filter out many of the shops in every product.
1. Calculate the lowest price (shipping cost included) of every product, let's call it best_price.
2. In every product, retain only the shops where price of the shop (without shipping cost) <= best_price (with shipping cost)
3. Test every possible combination of shops for the cheapest.
A good heuristic can be the ant colony optimization. I use it to solve the travel salesman problem. You can find a working example from google tsp solver. It's a javascript library that uses also a brute force and a dynamic programming solution. The AOC is used when you have more cities to compute then the current limit of 20 cities. I believe you can use the library to solve your problem and it just need a little rewrite. With 20 cities the program has to check 20! posibilites. In your case it's a bit lighter but maybe only a magnitude.

Resources