Convert OR Tools IntervalVars into Binary List - python

Good Morning,
I'm trying to find a way to convert IntervalVars into a List of BooleanVars with or tools in order to use the binary list as a sort of field in which the booleans indicate where the Interval is located in the window between time 0 and horizon.
I've got it working with just one Interval, i.e. when i print all Solutions it shows the interval in all possible positions:
all combination/solutions:
[
[0, 0, 1, 1, 0],
[0, 1, 1, 0, 0],
[0, 0, 0, 1, 1],
[1, 1, 0, 0, 0]
]
working model:
duration = 2
horizon = 5
model = cp_model.CpModel()
bool_vars = []
start_var = model.NewIntVar(0, horizon, "start")
interval_var = model.NewFixedSizeIntervalVar(start_var, duration, "interval")
for i in range(horizon):
bool_var = model.NewBoolVar(f"bool_{i}")
model.Add(interval_var.StartExpr() <= i).OnlyEnforceIf(bool_var)
model.Add(interval_var.EndExpr() > i).OnlyEnforceIf(bool_var)
bool_vars.append(bool_var)
model.Add(sum(bool_vars) == duration)
Now if i try to extend this method to two intervals it doesn't work.
durations = [1,2]
horizon = 5
model = cp_model.CpModel()
bool_vars = [model.NewBoolVar(f"bool_{i}") for i in range(horizon)]
for duration in durations:
start_var = model.NewIntVar(0, horizon, f"start_{duration}")
interval_var = model.NewFixedSizeIntervalVar(start_var, duration, f"interval_{duration}")
for i in range(horizon):
model.Add(interval_var.StartExpr() <= i).OnlyEnforceIf(bool_vars[i])
model.Add(interval_var.EndExpr() > i).OnlyEnforceIf(bool_vars[i])
model.Add(sum(bool_vars) == sum(durations))
I suspect its the lines
model.Add(interval_var.StartExpr() <= i).OnlyEnforceIf(bool_var)
model.Add(interval_var.EndExpr() > i).OnlyEnforceIf(bool_var)
I know theres something fundamental which I'm missing but I cant think of another solution at the moment
Any input and criticism is appreciated! <3
The concrete Problem I'm trying to solve in this current step is:
Modify the current method (utilizing Google OR Tools) such that: given a list of durations and a horizon, find all possible combinations. With the constraint that sequences are separated by a gap/pause with duration_of_gap >= 1.
Example 1:
inputs:
durations = [1,2]
horizon = 5
solution:
combinations = [
[1, 0, 1, 1, 0],
[1, 0, 0, 1, 1],
[0, 1, 0, 1, 1],
]
Example 2:
inputs:
durations = [3,1,2]
horizon = 10
solution:
combinations = [
[1, 1, 1, 0, 1, 0, 1, 1, 0, 0],
[1, 1, 1, 0, 1, 0, 0, 1, 1, 0],
[1, 1, 1, 0, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 1, 0, 1, 1, 0],
[1, 1, 1, 0, 0, 1, 0, 0, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 0, 1, 1],
[0, 1, 1, 1, 0, 1, 0, 1, 1, 0],
[0, 1, 1, 1, 0, 1, 0, 0, 1, 1],
[0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
[0, 0, 1, 1, 1, 0, 1, 0, 1, 1]
]

Related

Setting indicators based in index per row in numpy

I am looking for an efficient way to set a indicators from zero to a known number (which differs for each row).
e.g.
a =
array([[1, 1, 1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 0]])
and I know the vector with the index when a goes from 1 to zero.
b = [3, 1, 6, 2, 8]
Rather than filling all the rows of a using a for-loop, I want to know if there is a fast way to set these indicators.
Use outer-comparison on ranged array vs. b -
In [16]: ncols = 9
In [17]: b
Out[17]: [3, 1, 6, 2, 8]
In [19]: np.greater.outer(b,np.arange(ncols)).view('i1')
Out[19]:
array([[1, 1, 1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 0]], dtype=int8)
Other similar ways to express the same -
(np.asarray(b)[:,None] > np.arange(ncols)).view('i1')
(np.asarray(b)[:,None] > np.arange(ncols)).astype(int)
With b being an array, simplifies further, as we can skip the array conversion with np.asarray(b).
Simplest way I can think of is:
result=[]
for row in array:
result.append(row.tolist().index(0))
print(result)
[3, 1, 6, 2, 8]
The reason this works is, that list has a method called index, which tells the first occurrence of a specific item in the list. So I am iterating over this 2-dimentional array, converting each of it to list and using index of 0 on each.
You can store these values into another list and append to it for each row and that's it.
You can use broadcasting to do an outer comparison:
b = np.asarray([3, 1, 6, 2, 8])
a = (np.arange(b.max() + 1) < b[:, None]).astype(int)
# array([[1, 1, 1, 0, 0, 0, 0, 0, 0],
# [1, 0, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 1, 1, 1, 1, 0, 0, 0],
# [1, 1, 0, 0, 0, 0, 0, 0, 0],
# [1, 1, 1, 1, 1, 1, 1, 1, 0]])

Flood fill working only on squared matrix?

I'm trying to implement flood fill to find all available cells in a grid
from which my robot can move to. if a cell is occupied its value will be 1,
and if a cell is free its value will be 0. my code seems to work on squared
matrices but not on other matrices. In my code I mark the reachable cells with
the number 2.
Here is my code:
def floodfill(matrix, x, y):
if matrix[x][y] == 0:
matrix[x][y] = 2
if x > 0:
floodfill(matrix,x-1,y)
if x < len(matrix[y]) - 1:
floodfill(matrix,x+1,y)
if y > 0:
floodfill(matrix,x,y-1)
if y < len(matrix) - 1:
floodfill(matrix,x,y+1)
This matrix seems to work:
def main():
maze = [[0, 1, 1, 1, 1, 0, 0, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 0, 0, 1, 1, 0, 1, 0, 1, 0]]
floodfill(maze, 0,0)
print(maze)
And this matrix does not (same matrix with last column removed):
def main():
maze = [[0, 1, 1, 1, 1, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 0, 1],
[0, 0, 0, 1, 1, 0, 1, 0, 1]]
floodfill(maze, 0,0)
print(maze)
Would appreciate your help.
Thanks!
Your first matrix works because it is a square matrix where the number of rows and the numbers of columns are equal = 10.
In your second case, your matrix is not a square matrix because you have 10 rows (x variable) but only 9 columns (y variable). Hence, when you do
y < len(matrix) - 1
len(matrix) is 10 which means you are going up to y < 9. Otherwise, you will get "List Index Out of Range Error". To get the correct numbers, you should check against the length of your rows which gives you the number of columns. One way is to use the length of first row as len(matrix[0]).
Similarly, for the x you should use the corresponding number of rows which can be accessed using len(matrix) which is 10 in your case. So, you should use
if x < len(matrix) - 1
instead of if x < len(matrix[y]) - 1: as juvian also pointed it out in the comments.
Other way is to convert your list of lists to a NumPy array and use the shape command to get the corresponding number of rows and columns.
When accessing elements in the matrix, the row index comes first (the matrix is an array of rows), followed by the column index (each row is an array of numbers).
You want matrix[y][x], not matrix[x][y].

Error shuffling list into new list

I am creating a list by shifting an old list out_g, item by item, and appending the result to the new one, new_sets. As I am iterating, I check the resulting shift, and it is correct. After this is complete, I print out the new list, and it is all a single object repeated. What am I missing?
The error occurs during the for loop at the end, where I append the results to new_sets.
#!/usr/bin/python
import math
def LFSR(register, feedback, output):
"""
https://natronics.github.io/blag/2014/gps-prn/
:param list feedback: which positions to use as feedback (1 indexed)
:param list output: which positions are output (1 indexed)
:returns output of shift register:
"""
# calculate output
out = [register[i-1] for i in output]
if len(out) > 1:
out = sum(out) % 2
else:
out = out[0]
# modulo 2 add feedback
fb = sum([register[i-1] for i in feedback]) % 2
# shift to the right
for i in reversed(range(len(register[1:]))):
register[i+1] = register[i]
# put feedback in position 1
register[0] = fb
return out
def shiftInPlace(l, n):
# https://stackoverflow.com/questions/2150108/efficient-way-to-shift-a-list-in-python
n = n % len(l)
head = l[:n]
l[:n] = []
l.extend(head)
return l
##########
## Main ##
##########
n = 3
# init register states
if n == 5 :
LFSR_A = [1,1,1,1,0]
LFSR_B = [1,1,1,0,1]
LFSR_A_TAPS =[5,4,3,2]
LFSR_B_TAPS =[5,3]
elif n == 7:
LFSR_A = [1,0,0,1,0,1,0]
LFSR_B = [1,0,0,1,1,1,0]
LFSR_A_TAPS = [7,3,2,1]
LFSR_B_TAPS = [7,3]
elif n == 3:
LFSR_A = [1,0,1]
LFSR_B = [0,1,1]
LFSR_A_TAPS = [3,2]
LFSR_B_TAPS = [3,1]
output_reg = [n]
N = 2**n-1
out_g = []
for i in range(0,N): #replace N w/ spread_fact
a = (LFSR(LFSR_A, LFSR_A_TAPS, output_reg))
b = (LFSR(LFSR_B, LFSR_B_TAPS, output_reg))
out_g.append(a ^ b)
# FOR BALANCED GOLD CODES NUMBER OF ONES MUST BE ONE MORE THAN NUMBER
# OF ZEROS
nzeros = sum(x == 0 for x in out_g)
nones = sum(x == 1 for x in out_g)
print "Gold Code Output Period[%d] of length %d -- {%d} 0's, {%d} 1's" % (N,N,nzeros,nones)
# produce all time shifted versions of the code
new_sets = []
for i in range(0,N-1):
new_sets.append(shiftInPlace(out_g,1))
# a=shiftInPlace(out_g,1)
# new_sets.append(a)
print new_sets[i]
print new_sets
My output :
Gold Code Output Period[7] of length 7 -- {3} 0's, {4} 1's
[1, 1, 0, 1, 0, 1, 0]
[1, 0, 1, 0, 1, 0, 1]
[0, 1, 0, 1, 0, 1, 1]
[1, 0, 1, 0, 1, 1, 0]
[0, 1, 0, 1, 1, 0, 1]
[1, 0, 1, 1, 0, 1, 0]
[[1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0]]
Correct values are printing on the iteration, but the final list has all the same values.
The problem should be obvious from your output - you are seeing the same list because you are appending the same list. Consider - you even name your function "shift in place", so that returns a mutated version of the same list you passed in, and then you append that same list. So one quick fix is to make a copy which you end up appending:
new_sets = []
for i in range(0,N-1):
new_sets.append(shiftInPlace(out_g,1)[:]) # append copy
# a=shiftInPlace(out_g,1)
# new_sets.append(a)
print new_sets[i]
This gives the output:
Gold Code Output Period[7] of length 7 -- {3} 0's, {4} 1's
[1, 1, 0, 1, 0, 1, 0]
[1, 0, 1, 0, 1, 0, 1]
[0, 1, 0, 1, 0, 1, 1]
[1, 0, 1, 0, 1, 1, 0]
[0, 1, 0, 1, 1, 0, 1]
[1, 0, 1, 1, 0, 1, 0]
[[1, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 1], [1, 0, 1, 0, 1, 1, 0], [0, 1, 0, 1, 1, 0, 1], [1, 0, 1, 1, 0, 1, 0]]
As an aside, for efficient in-place rotations, consider changing your data-structure to a collections.deque, which implements a doubly-linked list:
In [10]: from collections import deque
...: d = deque([1, 1, 0, 1, 0, 1, 0])
...: print(d)
...: for i in range(0, N-1):
...: d.rotate(-1)
...: print(d)
...:
deque([1, 1, 0, 1, 0, 1, 0])
deque([1, 0, 1, 0, 1, 0, 1])
deque([0, 1, 0, 1, 0, 1, 1])
deque([1, 0, 1, 0, 1, 1, 0])
deque([0, 1, 0, 1, 1, 0, 1])
deque([1, 0, 1, 1, 0, 1, 0])
deque([0, 1, 1, 0, 1, 0, 1])
You might try creating your list of rotations like this:
>>> li=[1,0,1,1,0,0]
>>> [li[r:]+li[:r] for r in range(len(li))]
[[1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 0, 1], [1, 1, 0, 0, 1, 0], [1, 0, 0, 1, 0, 1], [0, 0, 1, 0, 1, 1], [0, 1, 0, 1, 1, 0]]
... following up on my comment to juanpa's answer ...
When you append in this fashion, you append a reference to the in-place list. Your two-line code with variable a works the same way. You've appended 6 copies of the same variable reference; every time you shift the list, you shift the underlying object. All of the appended references point to that object.
Here's detailed output tracing your program. Note how all of the elements of new_sets change on every iteration. In my repair, I used the two-line assignment, but added a copy like this: new_sets.append(a[:])
Gold Code Output Period[7] of length 7 -- {3} 0's, {4} 1's
TRACE out_g = [0, 1, 1, 0, 1, 0, 1]
ENTER shiftInPlace, l= [0, 1, 1, 0, 1, 0, 1]
LEAVE shiftInPlace, head= [0] l= [1, 1, 0, 1, 0, 1, 0]
TRACE a= [1, 1, 0, 1, 0, 1, 0] new_sets= [[1, 1, 0, 1, 0, 1, 0]]
TRACE out_g = [1, 1, 0, 1, 0, 1, 0]
ENTER shiftInPlace, l= [1, 1, 0, 1, 0, 1, 0]
LEAVE shiftInPlace, head= [1] l= [1, 0, 1, 0, 1, 0, 1]
TRACE a= [1, 0, 1, 0, 1, 0, 1] new_sets= [[1, 0, 1, 0, 1, 0, 1], [1, 0, 1, 0, 1, 0, 1]]
TRACE out_g = [1, 0, 1, 0, 1, 0, 1]
ENTER shiftInPlace, l= [1, 0, 1, 0, 1, 0, 1]
LEAVE shiftInPlace, head= [1] l= [0, 1, 0, 1, 0, 1, 1]
TRACE a= [0, 1, 0, 1, 0, 1, 1] new_sets= [[0, 1, 0, 1, 0, 1, 1], [0, 1, 0, 1, 0, 1, 1], [0, 1, 0, 1, 0, 1, 1]]
TRACE out_g = [0, 1, 0, 1, 0, 1, 1]
ENTER shiftInPlace, l= [0, 1, 0, 1, 0, 1, 1]
LEAVE shiftInPlace, head= [0] l= [1, 0, 1, 0, 1, 1, 0]
TRACE a= [1, 0, 1, 0, 1, 1, 0] new_sets= [[1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 1, 0], [1, 0, 1, 0, 1, 1, 0]]
TRACE out_g = [1, 0, 1, 0, 1, 1, 0]
ENTER shiftInPlace, l= [1, 0, 1, 0, 1, 1, 0]
LEAVE shiftInPlace, head= [1] l= [0, 1, 0, 1, 1, 0, 1]
TRACE a= [0, 1, 0, 1, 1, 0, 1] new_sets= [[0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 1, 1, 0, 1]]
TRACE out_g = [0, 1, 0, 1, 1, 0, 1]
ENTER shiftInPlace, l= [0, 1, 0, 1, 1, 0, 1]
LEAVE shiftInPlace, head= [0] l= [1, 0, 1, 1, 0, 1, 0]
TRACE a= [1, 0, 1, 1, 0, 1, 0] new_sets= [[1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0]]
[[1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0], [1, 0, 1, 1, 0, 1, 0]]

Permutation without duplicates in Python

I have N positions, and each position can be either 0 or 1. I have fixed number of 1s, and I want to permutate these fixed number of 1s in these N positions.
from itertools import permutations
p = [0 for k in xrange(6)]
for k in xrange(0,3):
p[k] = 1
print(list(permutations(p)))
But above result contains four [0,0,0,1,1,1] in the list. I only want one of them. How can I get rid of these duplicates?
You could grab the positions of the 1s instead:
from itertools import combinations
def place_ones(size, count):
for positions in combinations(range(size), count):
p = [0] * size
for i in positions:
p[i] = 1
yield p
In action:
>>> list(place_ones(6, 3))
[
[1, 1, 1, 0, 0, 0],
[1, 1, 0, 1, 0, 0],
[1, 1, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 1],
[1, 0, 1, 1, 0, 0],
[1, 0, 1, 0, 1, 0],
[1, 0, 1, 0, 0, 1],
[1, 0, 0, 1, 1, 0],
[1, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 1, 1],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 0, 1, 0],
[0, 1, 1, 0, 0, 1],
[0, 1, 0, 1, 1, 0],
[0, 1, 0, 1, 0, 1],
[0, 1, 0, 0, 1, 1],
[0, 0, 1, 1, 1, 0],
[0, 0, 1, 1, 0, 1],
[0, 0, 1, 0, 1, 1],
[0, 0, 0, 1, 1, 1],
]
Set is perfect for this, as set does not not contain any duplicated element:
set(permutations(p))

How to increase a grid world's size by 1000 times

I'm using a program in which I have to input the environment's map. The input form looks like this.
self.map=[ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
I want to increase the size of the given structure by thousand times and maintain the form of the structure. After increasing the structure size will be 18000x6000. The code looks like this
Can someone suggest me a way to achieve this or any alternate way.
If you really want to use Python's lists (numpy's arrays are better for large matrices) you could use
repeatfactor = 1000
mat = self.map # copy reference, not data
m = len(mat)
n = len(mat[0])
newmatrix = [[mat[r % m][c % n]
for c in range(n * repeatfactor)]
for r in range(m * repeatfactor)]
Try np.repeat twice--once in each axis. Not the prettiest, but should work. So something like this:
map_array = np.array(self.map)
map_array = np.repeat(map_array, 1000, axis=0)
map_array = np.repeat(map_array, 1000, axis=1)

Categories

Resources