Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Andrew Childs
reversal-sort
Commits
98e18fc2
Commit
98e18fc2
authored
Feb 23, 2021
by
Hrishee Shastri
Browse files
Implementation of a Reversal Class and helpful methods, as well as an
implementation of odd-even sort
parent
dcf8876e
Changes
1
Hide whitespace changes
Inline
Side-by-side
SBR.py
0 → 100644
View file @
98e18fc2
"""
Interface for a Reversal Class.
"""
# Returns the cost of the given reversal
def
rev_cost
(
reversal
):
return
abs
(
reversal
.
beg
-
reversal
.
end
)
+
2
# Currently omits the 1/3 factor
class
Reversal
:
def
__init__
(
self
,
i
,
j
,
time
=
0
):
if
i
>
j
:
raise
ValueError
(
'Reversal
\'
s left index greater than right index'
)
self
.
beg
=
i
self
.
end
=
j
if
time
!=
0
:
self
.
time_remaining
=
time
else
:
self
.
time_remaining
=
rev_cost
(
self
)
# Decrease the time remaining for the reversal by the given time (does not fall below zero)
# Returns the subsequent time remaining
def
dec_time
(
self
,
t
):
self
.
time_remaining
=
max
(
0
,
self
.
time_remaining
-
t
)
return
self
.
time_remaining
def
get_time_remaining
(
self
):
return
self
.
time_remaining
def
get_length
(
self
):
return
abs
(
self
.
beg
-
self
.
end
)
+
1
def
__lt__
(
self
,
other
):
return
self
.
beg
<
other
.
beg
def
__str__
(
self
):
return
"("
+
str
(
self
.
beg
)
+
", "
+
str
(
self
.
end
)
+
")"
# Perform the given reversal on the given permutation
def
reverse
(
permutation
,
reversal
):
i
=
reversal
.
beg
j
=
reversal
.
end
permutation
[
i
:
j
+
1
]
=
permutation
[
i
:
j
+
1
][::
-
1
]
# Determines if the reversals in the given list are independent, where perm_length is the length of the permutation
def
independent
(
rev_list
,
perm_length
):
busy
=
[
0
]
*
perm_length
for
rev
in
rev_list
:
for
i
in
range
(
rev
.
beg
,
rev
.
end
+
1
):
if
busy
[
i
]:
return
False
busy
[
i
]
=
1
return
True
# Simpler function that checks if rev is independent to all reversals in the
# active rev list, when we know that the latter are already all indepdendent
def
check_independent
(
rev
,
active_rev_list
):
for
a_rev
in
active_rev_list
:
if
not
(
rev
.
beg
>
a_rev
.
end
or
rev
.
end
<
a_rev
.
beg
):
return
False
return
True
# Checks whether the item at index i is busy; namely, if i is participating in
# a reversal in the rev_list
def
is_busy
(
rev_list
,
i
):
for
rev
in
rev_list
:
if
rev
.
beg
<=
i
and
rev
.
end
>=
i
:
return
True
return
False
# Determines if the permutation is sorted (i.e. if it is the identity permutation from start to end, inclusive)
def
is_sorted
(
permutation
,
start
,
end
):
return
permutation
==
list
(
range
(
start
,
end
+
1
))
# Determines if the permutation is a valid permutation on the elements from start to end, inclusive
def
is_valid_permutation
(
permutation
,
start
,
end
):
return
sorted
(
permutation
)
==
list
(
range
(
start
,
end
+
1
))
# Determines the time (in time steps) taken to perform the reversals in the given list in the given order in parallel
def
compress_reversals
(
revlist
,
permsize
):
timesteps
=
[]
for
rev
in
revlist
:
# print(rev, ' cost =', rev_cost(rev))
init_step
=
len
(
timesteps
)
# if rev.beg == 5 and rev.end == 7:
# print('Here')
for
step
in
timesteps
[::
-
1
]:
busy
=
False
for
i
in
range
(
rev
.
beg
,
rev
.
end
+
1
):
if
step
[
i
]:
busy
=
True
break
if
busy
:
break
init_step
-=
1
while
init_step
+
rev_cost
(
rev
)
-
1
>
len
(
timesteps
)
-
1
:
timesteps
.
append
([
0
]
*
permsize
)
# if init_step + rev_cost(rev) - 1 > len(timesteps) - 1:
# timesteps += [[0] * permsize] * (init_step + rev_cost(rev) - 1 - (len(timesteps) - 1))
for
i
in
range
(
init_step
,
init_step
+
rev_cost
(
rev
)):
# print('Affecting row', i)
for
j
in
range
(
rev
.
beg
,
rev
.
end
+
1
):
timesteps
[
i
][
j
]
=
1
# for t in range(len(timesteps)):
# print(t, '\t-->', timesteps[t])
# print()
return
len
(
timesteps
)
class
ReversalCompresser
:
"""
Alternate implementation of the compress_reversals function.
"""
def
__init__
(
self
):
"""
List to be sorted
"""
self
.
model
=
[]
self
.
active_revs
=
[]
self
.
counter
=
0
def
reset
(
self
):
self
.
__init__
()
def
is_busy
(
self
,
start_index
,
end_index
):
"""
checks if chain is busy between start index and end index, inclusive
"""
return
1
in
self
.
model
[
start_index
:
end_index
+
1
]
def
make_busy
(
self
,
start_index
,
end_index
):
"""inclusive"""
for
i
in
range
(
start_index
,
end_index
+
1
):
self
.
model
[
i
]
=
1
def
make_free
(
self
,
start_index
,
end_index
):
for
i
in
range
(
start_index
,
end_index
+
1
):
self
.
model
[
i
]
=
0
def
independent
(
self
,
rev
,
revlist
):
"""
checks if rev is independent of all reversals in revlist, when we allow None in revlist
"""
for
a_rev
in
revlist
:
if
a_rev
is
None
:
continue
if
not
(
rev
.
beg
>
a_rev
.
end
or
rev
.
end
<
a_rev
.
beg
):
return
False
return
True
def
update
(
self
):
for
rev
in
self
.
active_revs
:
rev
.
step
-=
1
if
rev
.
step
==
0
:
self
.
make_free
(
rev
.
beg
,
rev
.
end
)
self
.
active_revs
=
[
rev
for
rev
in
self
.
active_revs
if
rev
.
step
>
0
]
self
.
counter
+=
1
def
compress
(
self
,
revlist
,
permsize
):
revlist
=
revlist
[:]
self
.
reset
()
self
.
model
=
[
0
]
*
permsize
self
.
active_revs
=
[]
while
len
(
revlist
)
>
0
:
for
r
in
range
(
len
(
revlist
)):
rev
=
revlist
[
r
]
if
not
self
.
is_busy
(
rev
.
beg
,
rev
.
end
)
and
self
.
independent
(
rev
,
revlist
[:
r
]):
self
.
make_busy
(
rev
.
beg
,
rev
.
end
)
self
.
active_revs
.
append
(
rev
)
rev
.
step
=
rev
.
get_length
()
+
1
# to account for the + 1 in the cost fucntion
revlist
[
r
]
=
None
revlist
=
list
(
filter
(
lambda
i
:
i
is
not
None
,
revlist
))
self
.
update
()
# wait for final reversals to finish, if there are any
while
self
.
active_revs
!=
[]:
self
.
update
()
return
self
.
counter
def
odd_even_sort
(
L
):
"""
L: List to be sorted. Since we can reduce the problem of sorting according to a permutation
pi to just sorting according to the identity permutation, we just sort normally.
Odd even sort is performed in parallel. Each pass is an odd pass or even pass, where we look
at every odd/even pair and swap if they are out of order. Each pass takes time 1, since there are
n/2 swaps per pass (each taking time 1) done in parallel.
sorts in place. Returns the cost
"""
cost
=
0
sortflag
=
False
addflag
=
False
while
not
sortflag
:
sortflag
=
True
addflag
=
False
for
i
in
range
(
1
,
len
(
L
)
-
1
,
2
):
if
L
[
i
]
>
L
[
i
+
1
]:
L
[
i
],
L
[
i
+
1
]
=
L
[
i
+
1
],
L
[
i
]
sortflag
=
False
addflag
=
True
cost
+=
int
(
addflag
)
addflag
=
False
for
i
in
range
(
0
,
len
(
L
)
-
1
,
2
):
if
L
[
i
]
>
L
[
i
+
1
]:
L
[
i
],
L
[
i
+
1
]
=
L
[
i
+
1
],
L
[
i
]
sortflag
=
False
addflag
=
True
cost
+=
int
(
addflag
)
return
cost
def
apply_revs
(
revs
,
perm
):
"""
Applies reversals in list revs in order to permutation perm, in place
"""
for
rev
in
revs
:
reverse
(
perm
,
rev
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment