Optaplanner is being used to plan the routes of a fleet of vehicles and I am optimizing the route times.
I have a scenario where I have one visit with time windows in the morning and the second visit with time window in the afternoon. However the vehicle leaves when the time window opens, makes the first delivery and heads to the second visit. Since the second visit has a time window in the afternoon, the vehicle has to wait for the time window of this visit to open, which introduces downtime. This downtime (idle time) can be reduced by leaving the depot later. So I would like to ask if:
Is there any rule to q backtrack to the depot or to the previous visit, wait longer to continue, and thereby reduce the downtime or waiting time on the second visit?
I have tried different variants:
1- I implemented a constraint to penalize if early to a visit and penalize with customer -> customer.getReadyTime() - customer.getArrivalTime().
This may optimize but it does not roll back the arrivalTime.
2- Modify my listener (ArrivalTimeUpdatingVariableListener, updateArrivalTime method).When calculating the arrival time, if there is idle time, I go to the previous visit and subtract the idle time. However, in some cases it does not recursively update all previous visits correctly, and in other cases it gives me a "VariableListener corruption". I have had no success for this variant either.
Is there any rule to wait or roll back and update all visits again?
I attach my constraint and listener for better context.
ArrivalTimeUpdatingVariableListener.class:
protected void updateArrivalTime(ScoreDirector scoreDirector, TimeWindowedVisit sourceCustomer) {
Standstill previousStandstill = sourceCustomer.getPreviousStandstill();
Long departureTime = previousStandstill == null ? null
: (previousStandstill instanceof TimeWindowedVisit)
? ((TimeWindowedVisit) previousStandstill).getArrivalTime() + ((TimeWindowedVisit) previousStandstill).getServiceDuration()
: ((PlanningVehicle) previousStandstill).getDepot() != null
? ((TimeWindowedDepot) ((PlanningVehicle) previousStandstill).getDepot()).getReadyTime()
: 0;
TimeWindowedVisit shadowCustomer = sourceCustomer;
Long arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
while (shadowCustomer != null && !Objects.equals(shadowCustomer.getArrivalTime(), arrivalTime)) {
scoreDirector.beforeVariableChanged(shadowCustomer, "arrivalTime");
shadowCustomer.setArrivalTime(arrivalTime);
scoreDirector.afterVariableChanged(shadowCustomer, "arrivalTime");
departureTime = shadowCustomer.getDepartureTime();
shadowCustomer = shadowCustomer.getNextVisit();
arrivalTime = calculateArrivalTime(shadowCustomer, departureTime);
}
}
private Long calculateArrivalTime(TimeWindowedVisit customer, Long previousDepartureTime) {
long arrivalTime = 0;
if (customer == null || customer.getPreviousStandstill() == null) {
return null;
}
if (customer.getPreviousStandstill() instanceof PlanningVehicle) {
arrivalTime = Math.max(customer.getReadyTime(),
previousDepartureTime + customer.distanceFromPreviousStandstill());
} else {
arrivalTime = previousDepartureTime + customer.distanceFromPreviousStandstill();
// to reach backwards and (attempt to) shift the previous arrival time.
Standstill previousStandstill = customer.getPreviousStandstill();
long idle = customer.getReadyTime() - arrivalTime;
if (previousStandstill != null && idle > 0) {
arrivalTime += idle;
if (previousStandstill instanceof TimeWindowedVisit) {
long previousArrival = ((TimeWindowedVisit) previousStandstill).getArrivalTime() + idle;
if (previousArrival > ((TimeWindowedVisit) previousStandstill).getDueTime()){
System.out.println("Arrival es mayor que el duetime");
previousArrival = ((TimeWindowedVisit) previousStandstill).getDueTime() - ((TimeWindowedVisit) previousStandstill).getServiceDuration();
}
((TimeWindowedVisit) previousStandstill).setArrivalTime(previousArrival);
}
}
}
// breaks
return arrivalTime;
}
ConstraintProvider.class:
private Constraint arrivalEarly(ConstraintFactory constraintFactory) {
return constraintFactory.from(TimeWindowedVisit.class)
.filter((customer) -> !customer.getVehicle().isGhost() && customer.getArrivalTime() < customer.getReadyTime())
.penalizeConfigurableLong(
VehicleRoutingConstraintConfiguration.MINIMIZE_IDLE_TIME,
customer -> customer.getReadyTime() - customer.getArrivalTime());
}
var period = Period.ofWeeks(2)
println("period of two weeks: $period")
gives
period of two weeks: P14D
Unfortunately for my purpose I need P2W as output, so directly the weeks instead of weeks converted to days. Is there any elegant way to do this, besides building my Period string manually?
Your observation is true. java.time.Period does not really conserve the week value but automatically converts it to days - already in the factory method during construction. Reason is that a Period only has days and months/years as inner state.
Possible workarounds or alternatives in the order of increasing complexity and count of features:
You write your own class implementing the interface java.time.temporal.TemporalAmount with weeks as inner state.
You use the small library threeten-extra which offers the class Weeks. But be aware of the odd style of printing negative durations like P-2W instead of -P2W. Example:
Weeks w1 = Weeks.of(2);
Weeks w2 = Weeks.parse("P2W");
System.out.println(w1.toString()); // P2W
System.out.println(w2.toString()); // P2W
Or you use my library Time4J which offers the class net.time4j.Duration. This class does not implement the interface TemporalAmount but offers a conversion method named toTemporalAmount(). Various normalization features and formatting (ISO, via patterns and via net.time4j.PrettyTime) and parsing (ISO and via patterns) capabilities are offered, too. Example:
Duration<CalendarUnit> d1 = Duration.of(2, CalendarUnit.WEEKS);
Duration<IsoDateUnit> d2 = Duration.parseWeekBasedPeriod("P2W"); // also for week-based-years
System.out.println(d1.toString()); // P2W
System.out.println(PrettyTime.of(Locale.US).print(d2); // 2 weeks
As extra, the same library also offers the class net.time4j.range.Weeks as simplified week-only duation.
The Period toString method only handles Day, Month and Year.
as you can see below is toString() method from class java.time.Period.
So Unfortunately I think you need to create it yourself.
/**
* Outputs this period as a {#code String}, such as {#code P6Y3M1D}.
* <p>
* The output will be in the ISO-8601 period format.
* A zero period will be represented as zero days, 'P0D'.
*
* #return a string representation of this period, not null
*/
#Override
public String toString() {
if (this == ZERO) {
return "P0D";
} else {
StringBuilder buf = new StringBuilder();
buf.append('P');
if (years != 0) {
buf.append(years).append('Y');
}
if (months != 0) {
buf.append(months).append('M');
}
if (days != 0) {
buf.append(days).append('D');
}
return buf.toString();
}
}
I'm stack for along time in this problem and i will really appreciate if any one could help me in that.
I asked many times in many forums, i've searched alot but no answer that really helped me.
i'm developping an application where i have to calculate the velocity of a joint of skeleton body using vs c# 2012 and kinect sdk 1.7
i have first to be sure of the logic of things before asking this question so,
if I understood correctly, the delta_time i'm looking for to calculate velocity, is not the duration of one frame (1/30s) but it must be calculated from two instants:
1- the instant when detecting and saving the "joint point" in the first frame
2- the instant when detecting and saving the same "joint point" in the next frame
if it's not true, thank you for clarifying things.
starting from this hypothesis, i wrote a code to :
detectiong a person
tracking the spine joint ==> if it's is tracked then saving its coordinates into a list (I reduced the work for the moment on the Y axis to simplify)
pick up the time when saving the coordinates
increment the framecounter (initially equal to zero)
if the frame counter is > 1 calculate velocity ( x2 - x1)/(T2 - T1) and save it
here is a piece of the code:
System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
double msNow;
double msPast;
double diff;
TimeSpan currentTime;
TimeSpan lastTime = new TimeSpan(0);
List<double> Sylist = new List<double>();
private int framecounter = 0;
private void KinectSensorOnAllFramesReady(object sender, AllFramesReadyEventArgs allFramesReadyEventArgs)
{
Skeleton first = GetFirstSkeleton(allFramesReadyEventArgs);
if (first == null) // if there is no skeleton
{
txtP.Text = "No person detected"; // (Idle mode)
return;
}
else
{
txtP.Text = "A person is detected";
skeletonDetected = true;
/// look if the person is totally detected
find_coordinates(first);
/*******************************
* time computing *
/*******************************/
currentTime = stopWatch.Elapsed;
msNow = currentTime.Seconds * 1000 + currentTime.Milliseconds;
if (lastTime.Ticks != 0)
{
msPast = lastTime.Seconds * 1000 + lastTime.Milliseconds;
diff = msNow - msPast;
}
lastTime = currentTime;
}
//framecounter++;
}
void find_coordinates(Skeleton first)
{
//*modification 07052014 *****/
Joint Spine = first.Joints[JointType.Spine];
if (Spine.TrackingState == JointTrackingState.Tracked)
{
double Sy = Spine.Position.Y;
/*******************************
* time starting *
/*******************************/
stopWatch.Start();
Sylist.Add(Sy);
framecounter++;
}
else
return;
if (framecounter > 1)
{
double delta_Distance = Sylist[Sylist.Count] - Sylist[Sylist.Count - 1];
}
}
to be honnest, i dont really know how ti use timespan and stopwatch in this context ( i mean when there are frames to process many times/s)
i will be thankfull for any help !
First:
The SkeletonFrame has a property called Timespamp that you can use. It's better to use that one than to create your own timesystem because the timestamp is directly generated by the Kinect.
Second:
Keep track of the previous Timestamp and location.
Then it's just a matter of calculation.
(CurrentLocation - PreviousLocation) = Distance difference
(CurrentTimestamp - PreviousTimestamp) = Time taken to travel the distance.
For example you would get 0.1 meter per 33 miliseconds.
So you can get the meters per seconds like this = (1 second / time taken to travel) * distance difference. In the example this is = (1000/33)*0.1 = 3.03 meter per second.
Im needing to use local variables but when i use them for a timer (decreases time until conditions are met) it doesnt work
for (int i = 0; i < Weapons.Count; i++)
{
if (Weapons[i].ItemType == 6)
{
if (standard.IsKeyDown(Keys.G))
{
Cannons.Add(new CannonFire(this));
}
}
else if (Weapons[i].ItemType == 7)
{
float Recharge = Weapons[i].Laser.Rate;
Recharge -= (float)gametime.ElapsedGameTime.Seconds;
if (standard.IsKeyDown(Keys.G) && Recharge < 0)
{
laser.Add(new LaserFire(this, new Vector3(Weapons[i].Laser.range, 1, 1) ));
Recharge = Weapons[i].Laser.Rate;
}
}
}
other relevant code is where im getting the rate from
public class LaserItem
{
float Damage;
float Range;
float Last;
float RechargeRate;
public float damage
{
get { return Damage; }
set { Damage = value; }
}
public float Rate
{
get { return RechargeRate; }
set { RechargeRate = value; }
}
public float Life
{
get { return Last; }
set { Last = value; }
}
it works without the timer but i cant have it like that because i dont want 300 lasers to be built every time someone hits the key. as far as i can tell the timer is set to the laser rate every frame so it never reaches 0 (this section it in the update function)
for this piece of code its fine but when i need it in a loop i have to use local variables;
From what I can understand, what you are doing in the code is that you're creating a new local variable with the value set to the recharge rate of the laser every single update, firing it when the time from the last update is longer than the recharge rate - this would occur only on a very slow update.
Taking into account the automatic Update (the main loop one) calling of XNA, what would help you is setting some class variable for the Weapon, e.g. RemainingRecharge and when you fire, set it to the recharge rate and substract the elapsed time every update until it reaches zero or less. The only difference from your code is that the recharge is moved to the class instance and thus preserved between updates.
Recharge isn't a reference or a pointer; it's a copy (as float and double are immutable types). So, assigning a value to Recharge at the end of the if() block does absolutely nothing. (I'd bet that it even gets removed by the compiler).
Try this:
else if (Weapons[i].ItemType == 7)
{
float recharge = Weapons[i].Laser.Rate;
recharge -= (float)gametime.ElapsedGameTime.Seconds;
if (standard.IsKeyDown(Keys.G) && recharge < 0)
{
laser.Add(new LaserFire(this, new Vector3(Weapons[i].Laser.range, 1,1)));
/// changed the the next line:
Weapons[i].Laster.Rate = recharge;
}
}
i figured it out, XNA has a TimeSpan thing you can use its easier to work with and you can tell it if it reaches a number reset and do what you want
I use INCR and EXPIRE to implement rate limiting, e.g., 5 requests per minute:
if EXISTS counter
count = INCR counter
else
EXPIRE counter 60
count = INCR counter
if count > 5
print "Exceeded the limit"
However, 5 requests can be sent at the last second minute one and 5 more requests at the first second of minute two, i.e., 10 requests in two seconds.
How can this problem be avoided?
Update: I came up with this list implementation. Is this a good way to do it?
times = LLEN counter
if times < 5
LPUSH counter now()
else
time = LINDEX counter -1
if now() - time < 60
print "Exceeded the limit"
else
LPUSH counter now()
LTRIM counter 5
You could switch from "5 requests in the last minute" to "5 requests in minute x". By this it would be possible to do:
counter = current_time # for example 15:03
count = INCR counter
EXPIRE counter 60 # just to make sure redis doesn't store it forever
if count > 5
print "Exceeded the limit"
If you want to keep using "5 requests in the last minute", then you could do
counter = Time.now.to_i # this is Ruby and it returns the number of milliseconds since 1/1/1970
key = "counter:" + counter
INCR key
EXPIRE key 60
number_of_requests = KEYS "counter"*"
if number_of_requests > 5
print "Exceeded the limit"
If you have production constraints (especially performance), it is not advised to use the KEYS keyword. We could use sets instead:
counter = Time.now.to_i # this is Ruby and it returns the number of milliseconds since 1/1/1970
set = "my_set"
SADD set counter 1
members = SMEMBERS set
# remove all set members which are older than 1 minute
members {|member| SREM member if member[key] < (Time.now.to_i - 60000) }
if (SMEMBERS set).size > 5
print "Exceeded the limit"
This is all pseudo Ruby code, but should give you the idea.
The canonical way to do rate limiting is via the Leaky bucket algorithm. The downside of using a counter, is that a user can perform a bunch of request right after the counter is reset, i.e. 5 actions in the first second of the next minute for your case. The Leaky bucket algorithm solves this problem. Briefly, you can used ordered sets to store your "leaky bucket", using action time stamps as keys to fill it.
Check out this article for the exact implementation:
Better Rate Limiting With Redis Sorted Sets
UPDATE:
There is also another algorithm, which has some advantages compared to leaky bucket. It's called Generic Cell Rate Algorithm . Here's how it works at the higher level, as described in Rate Limiting, Cells, and GCRA:
GCRA works by tracking remaining limit through a time called the “theoretical arrival time” (TAT), which is seeded on the first request by adding a duration representing its cost to the current time. The cost is calculated as a multiplier of our “emission interval” (T), which is derived from the rate at which we want the bucket to refill. When any subsequent request comes in, we take the existing TAT, subtract a fixed buffer representing the limit’s total burst capacity from it (τ + T), and compare the result to the current time. This result represents the next time to allow a request. If it’s in the past, we allow the incoming request, and if it’s in the future, we don’t. After a successful request, a new TAT is calculated by adding T.
There is a redis module that implements this algorithm available on GitHub: https://github.com/brandur/redis-cell
This is an old question that was already answered, but here's an implementation I did taking some inspiration from here. I'm using ioredis for Node.js
Here is the rolling-window time limiter in all its asynchronous yet race-condition-free (I hope) glory:
var Ioredis = require('ioredis');
var redis = new Ioredis();
// Rolling window rate limiter
//
// key is a unique identifier for the process or function call being limited
// exp is the expiry in milliseconds
// maxnum is the number of function calls allowed before expiry
var redis_limiter_rolling = function(key, maxnum, exp, next) {
redis.multi([
['incr', 'limiter:num:' + key],
['time']
]).exec(function(err, results) {
if (err) {
next(err);
} else {
// unique incremented list number for this key
var listnum = results[0][1];
// current time
var tcur = (parseInt(results[1][1][0], 10) * 1000) + Math.floor(parseInt(results[1][1][1], 10) / 1000);
// absolute time of expiry
var texpiry = tcur - exp;
// get number of transacation in the last expiry time
var listkey = 'limiter:list:' + key;
redis.multi([
['zadd', listkey, tcur.toString(), listnum],
['zremrangebyscore', listkey, '-inf', texpiry.toString()],
['zcard', listkey]
]).exec(function(err, results) {
if (err) {
next(err);
} else {
// num is the number of calls in the last expiry time window
var num = parseInt(results[2][1], 10);
if (num <= maxnum) {
// does not reach limit
next(null, false, num, exp);
} else {
// limit surpassed
next(null, true, num, exp);
}
}
});
}
});
};
and here is a kind of lockout-style rate limiter:
// Lockout window rate limiter
//
// key is a unique identifier for the process or function call being limited
// exp is the expiry in milliseconds
// maxnum is the number of function calls allowed within expiry time
var util_limiter_lockout = function(key, maxnum, exp, next) {
// lockout rate limiter
var idkey = 'limiter:lock:' + key;
redis.incr(idkey, function(err, result) {
if (err) {
next(err);
} else {
if (result <= maxnum) {
// still within number of allowable calls
// - reset expiry and allow next function call
redis.expire(idkey, exp, function(err) {
if (err) {
next(err);
} else {
next(null, false, result);
}
});
} else {
// too many calls, user must wait for expiry of idkey
next(null, true, result);
}
}
});
};
Here's a gist of the functions. Let me know if you see any issues.
Note: The following code is a sample implementation in Java.
private final String COUNT = "count";
#Autowired
private StringRedisTemplate stringRedisTemplate;
private HashOperations hashOperations;
#PostConstruct
private void init() {
hashOperations = stringRedisTemplate.opsForHash();
}
#Override
public boolean isRequestAllowed(String key, long limit, long timeout, TimeUnit timeUnit) {
Boolean hasKey = stringRedisTemplate.hasKey(key);
if (hasKey) {
Long value = hashOperations.increment(key, COUNT, -1l);
return value > 0;
} else {
hashOperations.put(key, COUNT, String.valueOf(limit));
stringRedisTemplate.expire(key, timeout, timeUnit);
}
return true;
}
Here's my leaky bucket implementation of rate limiting, using Redis Lists.
Note: The following code is a sample implementation in php, you can implement it in your own language.
$list = $redis->lRange($key, 0, -1); // get whole list
$noOfRequests = count($list);
if ($noOfRequests > 5) {
$expired = 0;
foreach ($list as $timestamp) {
if ((time() - $timestamp) > 60) { // Time difference more than 1 min == expired
$expired++;
}
}
if ($expired > 0) {
$redis->lTrim($key, $expired, -1); // Remove expired requests
if (($noOfRequests - $expired) > 5) { // If still no of requests greater than 5, means fresh limit exceeded.
die("Request limit exceeded");
}
} else { // No expired == all fresh.
die("Request limit exceeded");
}
}
$redis->rPush($key, time()); // Add this request as a genuine one to the list, and proceed.
Your update is a very nice algorithm, although I a made couple of changes:
times = LLEN counter
if times < 5
LPUSH counter now()
else
time = LINDEX counter -1
if now() - time <= 60
print "Exceeded the limit"
else
LPUSH counter now()
RPOP counter
Similar to other Java answer but will less round trip to Redis:
#Autowired
private StringRedisTemplate stringRedisTemplate;
private HashOperations hashOperations;
#PostConstruct
private void init() {
hashOperations = stringRedisTemplate.opsForHash();
}
#Override
public boolean isRequestAllowed(String key, long limit, long timeout, TimeUnit timeUnit) {
Long value = hashOperations.increment(key, COUNT, 1l);
if (value == 1) {
stringRedisTemplate.expire(key, timeout, timeUnit);
}
return value > limit;
}
Here is an alternative approach. If the goal is to limit the number of requests to X requests per Y seconds with the timer starting when the first request is received, then you could create 2 keys for each user that you want to track: one for the time that the first request was received and another for the number of requests made.
key = "123"
key_count = "ct:#{key}"
key_timestamp = "ts:#{key}"
if (not redis[key_timestamp].nil?) && (not redis[key_count].nil?) && (redis[key_count].to_i > 3)
puts "limit reached"
else
if redis[key_timestamp].nil?
redis.multi do
redis.set(key_count, 1)
redis.set(key_timestamp, 1)
redis.expire(key_timestamp,30)
end
else
redis.incr(key_count)
end
puts redis[key_count].to_s + " : " + redis[key_timestamp].to_s + " : " + redis.ttl(key_timestamp).to_s
end
This is small enough that you might get away with not hashing it.
local f,k,a,b f=redis.call k=KEYS[1] a=f('incrby',k,ARGV[1]) b=f('pttl',k) if b<0 then f('pexpire',k,ARGV[2]) end return a
The parameters are:
KEYS[1] = key name, could be the action to rate limit for example
ARGV[1] = amount to increment, usually 1, but you could batch up per 10 or 100 millisecond intervals on the client
ARGV[2] = window, in milliseconds, to rate limit in
Returns: The new incremented value, which can then be compared to a value in your code to see if it's over the rate limit.
The ttl will not be set back to the base value with this method, it will continue to slide down until the key expires, at which point it will start over with ARGV[2] ttl on the next call.
Requests in Last interval / Sliding window
interval == Amount of time that number of requests(throughput) accepted
throughput == number of requests per interval
RequestTimeList == Each request time added to this list
// Remove older request entries
while (!RequestTimeList.isEmpty() && (now() - RequestTimeList.get(0)) > interval) {
RequestTimeList.remove(0)
}
if (RequestTimeList.length < throughput) {
RequestTimeList.add(now())
} else {
throw err;
}
Requests in Interval / Fixed window
I have tried with LIST, EXPIRE and PTTL
If tps is 5 per second, then
throughput = 5
rampup = 1000 (1000ms = 1sec)
interval = 200ms
local tpsKey = KEYS[1]
local throughput = tonumber(ARGV[1])
local rampUp = tonumber(ARGV[2])
-- Minimum interval to accept the next request.
local interval = rampUp / throughput
local currentTime = redis.call('PTTL', tpsKey)
-- -2 if the key does not exist, so set an year expiry
if currentTime == -2 then
currentTime = 31536000000 - interval
redis.call('SET', tpsKey, 31536000000, "PX", currentTime)
end
local previousTime = redis.call('GET', tpsKey)
if (previousTime - currentTime) >= interval then
redis.call('SET', tpsKey, currentTime, "PX", currentTime)
return true
else
redis.call('ECHO',"0. ERR - MAX PERMIT REACHED IN THIS INTERVAL")
return false
end
another way with List
local counter = KEYS[1]
local throughput = tonumber(ARGV[1])
local rampUp = tonumber(ARGV[2])
local interval = rampUp / throughput
local times = redis.call('LLEN', counter)
if times == 0 then
redis.call('LPUSH', counter, rampUp)
redis.call('PEXPIRE', counter, rampUp)
return true
elseif times < throughput then
local lastElemTTL = tonumber(redis.call('LINDEX', counter, 0))
local currentTTL = redis.call('PTTL', counter)
if (lastElemTTL-currentTTL) < interval then
return false
else
redis.call('LPUSH', counter, currentTTL)
return true
end
else
return false
end
Redis streams (introduced in redis 5.0, 2018) provide a nice way of implementing a sliding window api limiter. Here's my implementation in Python
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
#app.middleware("http")
async def rate_limit(request: Request, call_next):
request_time = time.time()
host = request.client.host
# Settings
window_seconds = 10
max_requests_in_window = 2
# Fetch the oldest element in the stream
# Returns a 0- or 1-element list like: [('1660835163482-0', {'': ''})]
oldest = r.xrange(name=host, min='-', max='+', count=1)
# if:
# - an oldest element exists AND
# - it's inside the time window AND
# - the stream is full
# deny the request
if len(oldest) > 0:
oldest_time = int(oldest[0][0].split('-')[0])/1000
if oldest_time >= request_time - window_seconds:
stream_size = r.xlen(name=host)
if stream_size >= max_requests_in_window:
return JSONResponse(status_code=403, content={'reason': oldest})
# Append this request to the stream and carry on
r.xadd(name=host, fields={'':''}, maxlen=max_requests_in_window, approximate=False)
# Carry on..
response = await call_next(request)
return response