Maximizing a boolean function of AND and XOR on paritions of set - algorithm

Given a set of distinct positive integers S we need to partition a set in such a way that the following function is maximize. Let S1, S2, ... Sn be the parition. n can be atleast 2.
F(S1, S2, ..., Sn) = AND(XOR(S1), XOR(S2), ..., XOR(Sn)))
where, AND is bitwise AND operation and XOR is bitwise XOR operation
We need to print the all such partitions possible.
I have tried the exponential approach as shown below.
I am looking for a solution with lesser complexity.
This problem is part of a homework, so only provide the hint.
from functools import reduce
from collections import defaultdict
def partition(collection):
if len(collection) == 1:
yield [ collection ]
return
first = collection[0]
for smaller in partition(collection[1:]):
# insert `first` in each of the subpartition's subsets
for n, subset in enumerate(smaller):
yield smaller[:n] + [[ first ] + subset] + smaller[n+1:]
# put `first` in its own subset
yield [ [ first ] ] + smaller
# print("END OF THE LOOP")
x = 4
initialAssum = [2, 4, 8, 16]
something = initialAssum
def andxor(xs):
def xorlist(xs):
return reduce(lambda i, j: i ^ j, xs)
tmp = [xorlist(x) for x in xs]
return reduce(lambda i, j: i & j, tmp)
ans = defaultdict(list)
for n, p in enumerate(partition(something), 1):
r = andxor(p)
if len(p) > 1:
ans[r].append(p)
m = max(ans.keys())
for a in ans[m]:
print(a)
#print(a, len(a))
print(f'{m}')
INPUT: the set itself
OUTPUT: max value possible followed by the all the partitions producing it
INPUT:
[2, 3, 4]
OUTPUT:
2
[[4, 2], [3]]
[[2], [4, 3]]
INPUT:
[2, 4, 6, 8]
OUTPUT:
0
[[2], [4, 8, 16]]
[[2, 4], [8, 16]]
[[4], [2, 8, 16]]
[[2], [4], [8, 16]]
[[2, 4, 8], [16]]
[[4, 8], [2, 16]]
[[2], [4, 8], [16]]
[[2, 8], [4, 16]]
[[8], [2, 4, 16]]
[[2], [8], [4, 16]]
[[2, 4], [8], [16]]
[[4], [2, 8], [16]]
[[4], [8], [2, 16]]
[[2], [4], [8], [16]]

This problem is part of a homework, so only provide the hint.
Hint: if we consider each bit separately from the highest to lowest, we can consider bit k as being set in the result if and only if that bit can appear an odd number of times in each part of the partition.

Related

Are there any algorithm that solves the following problem in time less than O(n!)?

Are there any algorithm that solves the following problem in time less than O(n!), like polynomial time?
Otherwise, for this problem, does not anyone have found any polynomial time algorithm, like NP problems?
Input: n (number of elements)
Output: a list of all combinations of two, where, from top of the list, each unit of combinations of n/2 must have all elements.
Example 1
Input: n=4
Output:
[0, 1], [2, 3],
[0, 2], [1, 3],
[0, 3], [1, 2]
Example 2
Input: n=8
Output:
[0, 1], [2, 3], [4, 5], [6, 7],
[0, 2], [1, 3], [4, 6], [5, 7],
[0, 3], [1, 2], [4, 7], [5, 6],
[0, 4], [1, 5], [2, 6], [3, 7],
[0, 5], [1, 4], [2, 7], [3, 6],
[0, 6], [1, 7], [2, 4], [3, 5],
[0, 7], [1, 6], [2, 5], [3, 4]
P.S.
The following answer does not meet the requirements.
The first two (= n/2) pairs ([0, 1], [0, 2]) do not have "3", so the answer does not meet the condition where "0" and "1", "2", "3" must be in the first two pairs.
>>> n=4
>>> for i in range(0, n-1):
... for j in range(i+1,n):
... print( [i, j] )
...
[0, 1]
[0, 2]
[0, 3]
[1, 2]
[1, 3]
[2, 3]
As I said in my comment, this appears to be a type of (relaxed) Sports League Scheduling problem. If I understand what you are asking for, it can be summarized as follows:
Given a positive even integer N generate a set of n/2 "rounds" of pairings with the following qualities:
A pairing is a pair of two different integers [a, b] such that a and b are integers from 0..n-1 and a < b.
A round consists of n/2 pairings, such that every element from 0..n-1 appears exactly once in a pairing in the round, and
All pairings are unique across all rounds (that is no pairing ever appears more than once in the complete solution).
Assuming that this is a correct formulation of your problem, then the answer is
Yes, this can be done in O(n^2).
Further, not only can it be done, there exists a simple method to solve it for any even N:
For the first round, make n-1 pairs, filling in the first element of the pairs with the integers from 0 to (n/2)-1 going left-to-right. This how it would look for N=8:
[0, ], [1, ], [2, ], [3, ]
Then, fill in the second elements with (n/2) to n-1, but going right-to-left:
[0, 7], [1, 6], [2, 5], [3, 4]
This completes your first round.
For the next round, copy the first round, but keeping 0 in the same place, move the remaining left-side elements up the list, and the right-side elements down the list. When an element reaches the end of the list, reverse direction and swap them from first elements to second elements (or vice-versa):
----------------------->
[0, 7], [1, 6], [2, 5], [3, 4]
<-----------------------
Becomes
----------------------->
[0, 6], [7, 5], [1, 4], [2, 3]
<-----------------------
Now you just continue this process until you have N/2 rounds:
[0, 7], [1, 6], [2, 5], [3, 4]
[0, 6], [7, 5], [1, 4], [2, 3]
[0, 5], [6, 4], [7, 3], [1, 2]
[0, 4], [5, 3], [6, 2], [7, 1]
Finally swap any pairings where the first element happens to be greater than the second:
[0, 7], [1, 6], [2, 5], [3, 4]
[0, 6], [5, 7], [1, 4], [2, 3]
[0, 5], [4, 6], [3, 7], [1, 2]
[0, 4], [3, 5], [2, 6], [1, 7]
If you check this solution you will find that it fulfills all of the constraints. This solutions works for any even value of N and obviously runs in O(n^2) time.
Yes, this problem can be solved in quadratic time. It is not too hard to explicitly construct these pairings.
It is quite helpful to consider a regular (n-1)-gon with one additional point in the middle. Then take the lines through one of the (n-1) endpoints and the midpoint and choose the pairs given by the symmetry of this line.

Problems using `elsif` in a `sort` block

I have this array:
ary = [[1, 6, 7], [1, 4, 9], [1, 8, 3]]
I want to sort it by the first odd number, or the last number if they are all even, in each subarray.
Since the first element in each array is the same object 1 for this particular ary, I can solve this like this:
ary2 = ary.sort_by { |a, b, c| b.odd? ? b : c }
But when I try a more general one:
arr2 = ary.sort_by { |a, b, c| a.odd? ? a : b.odd? ? b : c }
ary2 comes back unsorted.
I tried removing the ternary operators like this:
ary2 = ary.sort_by do |a, b, c|
if a.odd?
a
elsif b.odd?
b
else
c
end
end
with the same effect (i.e., none).
Is there some reason that elsif can't be used in blocks passed to the sort_by method?
Edit: Axiac pointed out the problem with my logic. It looks like conditional logic has to deal with all of the possible permutations of odd and even values. This works:
arr2 = arr.sort_by do |a, b, c|
if a.odd?
if b.odd?
if c.odd?
[a, b, c]
else
[a, b]
end
elsif c.odd?
[a, c]
else
a
end
elsif b.odd?
if c.odd?
[b, c]
else
b
end
else
c
end
end
Maybe there's a more succinct and less brittle way to do it, but it's probably a good idea to do it this way instead:
arr2 = arr.sort_by do |sub_arr|
temp = sub_arr.select do |e|
e.odd?
end
temp.empty? ? Array(sub_arr.last) : temp
end
I'll see myself out.
Regarding your original question, just as axiac points out in the comment, the result of the sorting should be exactly the same as the input array because they are all sorted by the first odd element in each subarray, which is 1, and the sort method is stable in MRI.
Regarding your question after the edit, my answer would be:
ary.sort_by{|a| a[0...-1].select(&:odd?) << a.last}
# => [[1, 8, 3], [1, 6, 7], [1, 4, 9]]
I am pretty confident that this is what you wrote after the edit that you wanted, but I am not sure if this is what you wanted since the sorting mechanism looks strange to me.
I find the statement of the question ambiguous. I will give an answer that is consist with one interpretation. If that is not what you want, please clarify hte question.
def my_sort(arr)
arr.sort_by {|a| a.any?(&:odd?) ? a.map {|e| e.odd? ? e : Float::INFINITY} : [a.last]}
end
my_sort [[1, 6, 7], [1, 4, 9], [1, 2, 3]]
#=> [[1, ∞, 7], [1, ∞, 9], [1, ∞, 3]] (sort_by)
#=> [[1, 2, 3], [1, 6, 7], [1, 4, 9]]
my_sort [[3, 6, 7], [4, 1, 9], [5, 8, 1]]
#=> [[3, ∞, 7], [∞, 1, 9], [5, ∞, 1]] (sort_by)
#=> [[3, 6, 7], [5, 8, 1], [4, 1, 9]]
my_sort [[2, 6, 8], [4, 1, 4], [8, 6, 2]]
#=> [[8], [∞, 1, ∞], [2]] (sort_by)
#=> [[8, 6, 2], [2, 6, 8], [4, 1, 4]]
my_sort [[8, 6, 2], [5, 1, 1], [6, 8, 4]]
#=> [[2], [5, 1, 1], [4] (sort_by)
#=> [[8, 6, 2], [6, 8, 4], [5, 1, 1]]
For each example I've shown the arrays used by sort_by to produce the sort shown on the following line.

How to generate partially repeated permutations in ruby?

I have a range of numbers R = (1..n). I also have another character 'a'. I want to generate strings of length L (L > n + 2) that have all the numbers in the same order, but go through every repeated permutation of 'a' to fill the length L. For example, if n = 3, and L = 7, then some valid strings would be :
"123aaaa",
"1a23aaa",
"1aa2a3a",
"aaaa123"
while the following strings would be invalid:
"213aaaa", # invalid, because 1,2,3 are not in order
"123a", #invalid, because length < L
"1123aaa", # invalid because a number is repeated
I am currently doing this, which is way too inefficient:
n = 3
L = 7
all_terms = (1..n).to_a + Array.new(L - n, 'a')
all_terms.permutation.each do |permut|
if(valid_permut? permut) # checks if numbers are in their natural order
puts permut.join
end
end
How do I directly generate valid strings more efficiently?
The problem is equivalent to: select n elements from index 0 to L - 1, fill these with 1 to n accordingly, and fill the rest with some constant character.
In your example, it's taking 3 elements from 0..6:
(0..6).to_a.combination(3).to_a
=> [[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 2, 3], [0, 2, 4],
[0, 2, 5], [0, 2, 6], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [0, 5, 6],
[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5],
[1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6],
[3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6]]
Every subarray here represents a possible result. For example, [0, 2, 3] corresponds to '0a12aaa', [3, 5, 6] corresponds to 'aaa0a12', etc. The code for this conversion is straight-forward.
You can model this as all possible interleavings of two strings, where relative order of the input elements is preserved. Here's a recursive solution. It works by choosing an element from one list, and prepending it to all possible subproblems, then doing it again where an element is chosen from the second list instead, and combining the two solution sets at the end.
# Returns an array of all possible interleaving of two strings
# Maintains relative order of each character of the input strings
def interleave_strings_all(a1, a2)
# Handle base case where at least one input string is empty
return [a1 + a2] if a1.empty? || a2.empty?
# Place element of first string, and prepend to all subproblems
set1 = interleave_strings_all(a1[1..-1], a2).map{|x| a1[0] + x}
# Place element of second string and prepend to all subproblems
set2 = interleave_strings_all(a1, a2[1..-1]).map{|x| a2[0] + x}
# Combine solutions of subproblems into overall problem
return set1.concat(set2)
end
if __FILE__ == $0 then
l = 5
n = 3
a1 = (1..n).to_a.map{|x| x.to_s}.join()
a2 = 'a' * (l - n)
puts interleave_strings_all(a1, a2)
end
The output is:
123aa
12a3a
12aa3
1a23a
1a2a3
1aa23
a123a
a12a3
a1a23
aa123

How do I find all subsets of an array that sum to zero using recursion? (In Ruby)

I'm new to coding and new to Ruby. I'm working on this problem in my spare time since I am new to ruby and am having a difficult time getting my code to iterate through every created subset.
Here is my code:
#Given a set of integers, and a value sum, i.e. value sum of 0
#determine if there is a subset of the given set with sum equal to given sum.
class Array
def SubSetSumtoZero
if self.collect{|sum,x| sum + x == 0}
detected = self.select {|sum,x| sum + x == 0}
puts "\r\n #{detected} Sums to Zero \r\n"
else self.collect{|sum,x| sum + x -= 0}
notdetected = self.select {|sum, x| sum + x -= 0}
puts "\r\n#{notdetected} Does not sum to Zero\r\n"
end
end
end
originalSet = [-9, -7, -2, 2, 7, 9]
arr = []
for i in 2..(originalSet.length) do
arr = arr + originalSet.combination(i).to_a
arr.SubSetSumtoZero
end
And here are my results:
[[-9, 9], [-7, 7], [-2, 2]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[[-9, 9], [-7, 7], [-2, 2], [-7, 7, 9], [-2, 2, 7], [-2, 2, 9], [-2, 2, 7, 9]] Sums to Zero
[Finished in 0.1s]
I know that at some point the entire array will sum up to zero. Any ideas why this is happening?
I know you specifically asked for a recursive solution, but since #hjing has provided one, I would like to show you how your question can be answered in a more compact and straightforward way by using powerful, built-in methods from Ruby's Enumerable module and Array class.
Code
def find_it(array, tot)
(1..array.size).each_with_object([]) { |n,arr|
array.combination(n).each { |a| arr << a if a.reduce(:+) == tot } }
end
Example
find_it([-9, -7, -2, 2, 7, 9], 0) #=> [-9, 9]
#=> [[-9, 9], [-7, 7], [-2, 2],
# [-9, 2, 7], [-7, -2, 9],
# [-9, -7, 7, 9], [-9, -2, 2, 9], [-7, -2, 2, 7],
# [-9, -7, -2, 2, 7, 9]]
Explanation
array = [-9, -7, -2, 2, 7, 9]
tot = 0
r = 1..array.size #=> 1..6 (Range object)
Each value of this range is size of subsets that will be considered. We will first examine subsets of size 1, then subsets of size 2, and so on, up to subsets of size 6, of which there is but one (array).
enum1 = r.each_with_object([]) # => #<Enumerator: 1..6:each_with_object([])>
To see the values that the enumerator enum1 will pass to its block, we can convert it to an array:
enum1.to_a #=> [[1, []], [2, []], [3, []], [4, []], [5, []], [6, []]]
Enumerable#each_with_object creates an initially empty array that is represented by the block variable arr. That first value enum passes to its block is the array [0, []], causing the block variables to be assigned as follows:
n => 1
arr => []
enum2 = array.combination(n) #=> array.combination(1)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(1)>
Here Array#combination generates all combinations of one element from array. enum2 will therefore pass the following elements to its block:
enum2.to_a
#=> [[-9], [-7], [-2], [2], [7], [9]]
The first element enum2 passes to its block is [-9], causing the bloc block variable to be assigned as follows:
a => [-9]
so the block expression becomes:
arr << a if a.reduce(:+) == tot #=> arr << [-9] if [-9].reduce(:+) == 0
Enumerable#reduce (aka, inject) with argument :+ (the addition method) merely sums the elements of its receiver, [-9], which obviously is -9. As -9 != 0, [-9] is not appended to arr. Clearly, the only array containing a single element that sums to zero is [0], but that array is not present in this example. Therefore, arr remains empty after enum2 has enumerated all its elements.
enum1 now passes the element [2, []] to its block, setting the block variables to:
n => 2
arr => []
resulting in:
enum2 = array.combination(n) #=> array.combination(2)
#=> #<Enumerator: [-9, -7, -2, 2, 7, 9]:combination(2)>
enum2.to_a
#=> [[-9, -7], [-9, -2], [-9, 2], [-9, 7], [-9, 9], [-7, -2], [-7, 2],
# [-7, 7], [-7, 9], [-2, 2], [-2, 7], [-2, 9], [ 2, 7], [ 2, 9], [7, 9]]
We find that elements [-9, 9], [-7, 7] and [-2, 2] each sum to zero, so arr becomes:
arr => [[-9, 9], [-7, 7] and [-2, 2]]
after all combinations of two elements have been enumerated. Next combinations of three are considered, and so on.
A straightforward recursive solution would be to write a function that computes the powerset of an array. Afterwards, select all elements in the powerset that fulfills your desired predicate.
An example implementation:
def powerset(array)
if array.empty?
[[]]
else
first_elem, *rest_elems = array
subsets = []
powerset(rest_elems).each do |subset|
subsets.push(subset)
subsets.push(subset.clone.push(first_elem))
end
subsets
end
end
def sums_to_zero?(array)
array.reduce(0, :+) == 0
end
def subsets_that_sum_to_zero(array)
powerset(array).select { |subset| sums_to_zero?(subset) }
end
original_set = [-9, -7, -2, 2, 7, 9]
subsets_that_sum_to_zero(original_set).each do |subset|
puts "The subset #{subset} sums to zero!"
end
# The subset [] sums to zero!
# The subset [2, -2] sums to zero!
# The subset [7, -7] sums to zero!
# The subset [7, 2, -9] sums to zero!
# The subset [7, 2, -2, -7] sums to zero!
# The subset [9, -9] sums to zero!
# The subset [9, -2, -7] sums to zero!
# The subset [9, 2, -2, -9] sums to zero!
# The subset [9, 7, -7, -9] sums to zero!
# The subset [9, 7, 2, -2, -7, -9] sums to zero!
See wikipedia for an explanation of the powerset algorithm.
Here is a straight forward recursive solution for zero sum:
def find_subsets(arr)
return arr if arr.empty?
result = (0...arr.length).flat_map do |i|
find_subsets(arr[0...i] + arr[i+1..-1])
end
result << arr if arr.inject(:+) == 0
result.uniq
end
It collects all the results from dropping a single element from the array (this is the recursion), and adds to it the array itself, if it fits the requirement (sums to zero).
It is not the most efficient solution since it may repeat the calculation for subarrays coming from several paths (that it why the last line uniqs the result) - but it is the easiest implementation.

Fill sparse array

I have a sparse array, for example:
rare = [[0,1], [2,3], [4,5], [7,8]]
I want to plot a chart with these data, each pair are point coordinates.
As you can see I don't have points for x=1, x=3 , x=5, x=6
I want to fill the array with the previous values, so for the above example I will get:
filled = [[0,1], [1,1], [2,3], [3,3], [4,5], [5,5], [6,5], [7,8]
As you can see, for calculating the y value, I simply take the last y value I used.
What is the best aproach to accomplish this ?
Range.new(*rare.transpose.first.sort.values_at(0,-1)).inject([]){|a,i|
a<<[i, Hash[rare][i] || a.last.last]
}
Step-by-step explanation:
rare.transpose.first.sort.values_at(0,-1) finds min and max x ([0,7] in your example)
Range.new() makes a range out of it (0..7)
inject iterates through the range and for every x returns pair [x,y], where y is:
y from input array, where defined
y from previously evaluated pair, where not
Note: here are some other ways of finding min and max x:
[:min,:max].map{|m| Hash[rare].keys.send m}
rare.map{|el| el.first}.minmax # Ruby 1.9, by steenslag
rare = [[0,1], [2,3], [4,5], [7,8]]
filled = rare.inject([]) do |filled, point|
extras = if filled.empty?
[]
else
(filled.last[0] + 1 ... point[0]).collect do |x|
[x, filled.last[1]]
end
end
filled + extras + [point]
end
p filled
# => [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]
An inject solution:
filled = rare.inject([]) do |filled_acc, (pair_x, pair_y)|
padded_pairs = unless filled_acc.empty?
last_x, last_y = filled_acc.last
(last_x+1...pair_x).map { |x| [x, last_y] }
end || []
filled_acc + padded_pairs + [[pair_x, pair_y]]
end
More about Enumerable#inject and functional programming with Ruby here.
irb(main):001:0> rare = [[0,1], [2,3], [4,5], [7,8]]
=> [[0, 1], [2, 3], [4, 5], [7, 8]]
irb(main):002:0> r=rare.transpose
=> [[0, 2, 4, 7], [1, 3, 5, 8]]
irb(main):003:0> iv = (r[0][0]..r[0][-1]).to_a.select {|w| !r[0].include?(w) }
=> [1, 3, 5, 6]
irb(main):004:0> r[1][-1]=r[1][-2]
=> 5
irb(main):005:0> p (iv.zip(r[1]) + rare).sort
[[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]
=> [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]

Resources