tpaviot / ProcessScheduler

A Python package for automatic and optimized resource scheduling
https://processscheduler.github.io/
GNU General Public License v3.0
59 stars 18 forks source link

Cost functions #34

Closed tpaviot closed 3 years ago

tpaviot commented 3 years ago

For a Task, the current definition of the cost_per_period is very poor and does not cover all situations of industrial cases. Indeed, cost functions may depend on time (for example, a cost quadratic function of time). It should be possible to define such functions and run the scheduler/optimizer on top of it.

The z3 solver is able to deal with Real numbers and nonlinear expressions. But none of the exp/sin/cos etc. functions, only polynomials. The best way to go is to define a cost function using only integer numbers. I suggest interpolating any function of one real variable using linear segments defined only with integer numbers. I contributed related code to https://github.com/tpaviot/LinearIntegerInterpolation. It is a very first draft.

ping @dreinon

dreinon commented 3 years ago

What about taylor series?

tpaviot commented 3 years ago

Taylor series gives you a polynomial approximation around a single point. Here, I rather need an interpolation over a wide range.

dreinon commented 3 years ago

True

dreinon commented 3 years ago

Do you know spline or kringing iterpolation? Those may give a better function approximation. Although, we may not want a better whole function approximation but rather an easier-to-compute approximation which gives the right results for costs of integers, and that's the point of the linear interpolation, am I right?

tpaviot commented 3 years ago

Right, I don't care about the interpolation quality. Although I should, however, compute the error of the interpolation (I guess least square error is a good indicator). I want my interpolation function:

tpaviot commented 3 years ago

I don't know the kringing interpolation

tpaviot commented 3 years ago

Maybe we can start with implementing a cost function as a linear function on the interval [0, horizon], and see later for interpolating more complex functions, for example:

ress1=Worker('Worker1', cost=CostFunction(cost_ress_1 = lambda t : 2*t + 10))
ress2=Worker('Worker2', cost=CostPerPeriod(5))

The CostFunction and CostPerPeriod would inherit from a _Cost base class.

What do you think?

tpaviot commented 3 years ago

Note:

ress2=Worker('Worker2', cost=CostFunction(cost_ress_2 = lambda t : 5))

This would be equivalent, but less readable

tpaviot commented 3 years ago

The advantage with constant or linear cost functions is that the total cost over a given period can be computed from a very simple area computation (rectangle if constant function, trapeze if linear)

dreinon commented 3 years ago
cost_ress_1 

I don't understand why naming the lambda function, doesn't it work like this: ress1=Worker('Worker1', cost=CostFunction(lambda t : 2*t + 10)) ??

dreinon commented 3 years ago

Also, what about accepting cost as Union[int, CostFunction]? Then, if cost is int, instancing CostPerPeriod(5) inside the function.

This would give a more readable approach, right?

tpaviot commented 3 years ago

Don't what is more readable. If the user is forced to use a Cost instance whenever he wants to assign cost to a resource, it might be better. Indeed I believe that an explicit class name is better than implicit typing. IMO

ress2=Worker('Worker2', cost=ConstantCostPerPeriod(5))

is more readable, at some point, than

ress2=Worker('Worker2', cost=5)

because, in the latter, we don't really know what this 5 refers to.

tpaviot commented 3 years ago

yes, you're right, no need to name the lambda function

dreinon commented 3 years ago

Right. I agree now with that approach.

tpaviot commented 3 years ago

Ok, I decided to start simple. I implemented ConstantCostPerPeriod and what I called PolynomialCostFunction. There are a some related tests

tpaviot commented 3 years ago

The first draft is in the master branch. Issue closed, further issues will need another entry.