Solving a recursive method - algorithm

I have three variables
Group-Set of Persons ex: {{David, Sebastian, Yousef}, {Boris, Mark}}
Person-Set ex: {David, Mark, Sebastian, Boris, Yousef}
Relation-Set ex: {{David, Mark}, {Sebastian, Boris}}
A Group-Set cannot have any person that are friends with each other.
A Group-Set cannot have duplicates.
I need to create a divide method thats called
divide(person-set, relation-set) and returns a group-set as the example above.
It needs to be solved recursively and loops are not allowed.
I already have a method called areFriends(Person, Person) that returns a boolean if they are friends or not.
This is what I got so far:
divide(ps, r){
divide(ps, r, gs){
let p1 = getRandom(ps);
p2 = getRandom(ps);
if(areFriends(p1, p2) = false){
gs.add(p1);
gs.add(p2);
}
remove(p1, ps);
if(getRandom(ps) != 0){
divide(ps, r, gs);
}
}
I've been dealing with this problem for a long time now and really need help with it. Thanks!

Based on a new constraint (without no loop constraint), we need an indicator (g_ind) for considering groups in the function:
divide(ps, r, g = [[]], g_ind = 0)
p <- empty
if there is any person in ps:
p <- take the first person from ps
else:
return
if g_ind >= len(g):
// all current divisions in g have a friend of p
g.add([p]) // add a new division with initial member p
remove p from ps
divide(ps, r, g, 0)
return
else if any friends of p in r exists in g[g_ind]:
divide(ps, r, g, ++g_ind)
return
else:
g[g_ind].add(p)
remove p from ps
divide(ps, r, g, 0)
return

Related

Mathematical modeling from gurobipy to pyomo: How to enumerate over a set in pyomo?

I implemented a course planning problem in gurobipy. It all works well. My next task is to rewrite it in pyomo. I had difficulties with one specific equation (written in gurobipy):
model.addConstrs((quicksum(gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau < len(T))
>= dur[m] * start[l, k, s, t] for index_t, t in enumerate(T) for m in M
for k in KM[m] for l in LM[m] for s in SM[m]), name='Hintereinander')
gamma[lkst] and start[lkst] are binary decision variables. l,k,s,t are indices where t are periods. So the set T is a list of the periods i have. Here in this equation i need the ord(t) to be able to do the calculations in the sum. Therefore I perform an enumeration(T) at the end of the euqation.(When looping over all needed indices).
My data is given beforehand, so i formulate a ConcreteModel() in pyomo. I have difficulties in including the enumeration of the Set T in pyomo.
What I already have:
def gamma_hintereinander_rule(model,m,k,l,s):
for index_t,t in enumerate(T):
if k in KM[m]:
if l in LM[m]:
if s in SM[m]:
return sum(model.gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau< len(T)) >= dur[m] * model.start[l, k, s, t]
else:
return Constraint.Skip
else:
return Constraint.Skip
else:
return Constraint.Skip
model.gamma_hintereinander = Constraint(M, K, L, S,rule=gamma_hintereinander_rule)
It doesn't work correctly.
I'd be really happy and thankful if someone could help me!
Best regards!
Zeineb
The problem is the for-loop inside of the constraint rule. You are exiting the rule after the first return statement is encountered and so only 1 constraint or Constraint.Skip is returned despite the for-loop. I think the best approach is to index your Constraint by T something like:
def gamma_hintereinander_rule(model,m,k,l,s,t):
index_t = T.index(t)
if k in KM[m]:
if l in LM[m]:
if s in SM[m]:
return sum(model.gamma[l, k, s, T[tau]] for tau in range(index_t, index_t + dur[m]) if tau< len(T)) >= dur[m] * model.start[l, k, s, t]
else:
return Constraint.Skip
else:
return Constraint.Skip
else:
return Constraint.Skip
model.gamma_hintereinander = Constraint(M, K, L, S, T, rule=gamma_hintereinander_rule)

Finding size of 'shortest range of indices' which lookup all unique path is passed

Given an array of String, Finding the size of 'shortest range of indices' which lookup all unique path is passed.
Example, A = { E, R, E, R, A, R, T, A }, it should be 5. As we can see, ranges of A[2] = E and A[6] = T contains all unique path. (In this case, E, R, A, T)
I can solved with multiple loop like below. (solved by Kotlin.)
fun problem(array: Array<String>): Int {
if (array.isEmpty()) return 0
val unique = array.distinct()
var result = 200000
for (i in 0 until A.size) {
val tempSet = HashSet<String>()
val remaining = A.sliceArray(i until array.size)
var count = 0
while (true) {
tempSet.add(remaining[count])
if (unique.size == tempSet.size) break
count++
if (count == remaining.size) {
count = 200000
break
}
}
result = Math.min(result, count + 1)
}
return result
}
But when a large array (about 100,000) comes in, I don't know how to reduce the time. How can i do?
Some Test case:
[E, R, E, R, A, R, T, A] -> 5. Because [2..6] contains all unique path. (E, R, A, T)
[C, A, A, R, C, A, A, R] -> 3. Because [3..5] contains all unique path. (C, A, R)
[R, T, A, R, A, R, E, R] -> 6. Because [1..6] contains all unique path. (T, A, R, E)
[A, R, R, C, T, E, A, R] -> 5. Because [2..6] contains all unique path. (R, C, T, E, A)
This problem might be effectively solved with "two-pointers" approach.
Make dictionary structure containing char as key and counter as value (in the simplest case - array of int)
Set two indexes L and R in 0.
Move R right, for current char increment counter of corresponding dict element.
When dict size (in case of array - number of non-zero elements) becomes equal to unique , stop
Now move L right, for current char decrement counter of corresponding dict element, removing element when counter becomes zero. When dict size becomes smaller than unique, stop. At the last step L..R interval contains all possible items.
Continue with R and so on
Choose the shortest interval during scanning.
Python code for alike question here
The phrase "all unique path" I will interpret to mean "all possible values".
For a string of length n with k unique values this is solvable in time O(n log(k)) using both a dictionary and a priority queue. The key ideas are this:
On a first pass, find all possible values.
The second time around, keep a dictionary most_recently_found of where each value was most recently found.
Keep a priority queue longest_since of which value it has been the longest since it has been found.
Keep a running minimum of the shortest gap.
And now when you go back through and have found all the values, you follow per iteration logic that looks something like this:
most_recently_found[current_value] = current_position
oldest = longest_since.top()
if current_value == oldest.value:
while oldest.position() != most_recently_found[oldest.position()]:
longest_since.pop()
longest_since.push({value: top.value, position: most_recently_found[oldest.position()]
oldest = longest_since.top()
if current_position - oldest.position() < best_gap:
best_gap = current_position - oldest.position()
The point being that for each value found, you have to update the dictionary (O(1)), might have to take it off the priority queue (O(k)), might have to put something new on the priority queue (O(k)) and might have to do some arithmetic (O(1)). Hence O(n log(k)) for everything.

Church numerals in lambda calculus

I need to find a function P such that (using Beta - reduction)
P(g, h, i) ->* (h, i, i+1).
I am allowed to use the successor function succ. From wikipedia I got
succ = λn.λf.λx.f(n f x)
My answer is P = λx.λy.λz.yz(λz.λf.λu.f(z f u))z
but I'm not quite sure about it. My logic was the λx would effectively get rid of the g term, then the λy.λz would bring in the h and i via the yz. Then the succ function would bring in i+1 last. I just don't know if my function actually replicates this.
Any help given is appreciated
#melpomene points out that this question is unanswerable without a specific implementation in mind (e.g. for tuples). I am going to presume that your tuple is implemented as:
T = λabcf.f a b c
Or, if you prefer the non-shorthand:
T = (λa.(λb.(λc.(λf.f a b c))))
That is, a function which closes over a, b, and c, and waits for a function f to pass those variables.
If that is the implementation in mind, and assuming normal Church numerals, then the function you spec:
P(g, h, i) ->* (h, i, i+1)
Needs to:
take in a triple (with a, b, and c already applied)
construct a new triple, with
the second value of the old triple
the third value of the old triple
the succ of the third value of the old triple
Here is such a function P:
P = λt.t (λghi.T h i (succ i))
Or again, if you prefer non-shorthand:
P = (λt.t(λg.(λh.(λi.T h i (succ i)))))
This can be partially cleaned up with some helper functions:
SND = λt.t (λabc.b)
TRD = λt.t (λabc.c)
In which case we can write P as:
P = λt.T (SND t) (TRD t) (succ (TRD t))

sort list so that the gap between equal elements is as large as possible

Lets assume I've got an unsorted List containing a, a, b, b, a, c and I want this sequence sorted so that the gaps between equal elements are as large as possible. So in case of this sample sequence a possible output could be b, a, c, a, b, a. In my application it wouldn't be that important that the gaps are at its exact average maximum, but there shouldn't be two equal elements next to each other whenever possible. So my indention is to maximize the smallest gaps.
I'd start from measuring frequency per each unique element:
scala> val l = List("a", "a", "b", "b", "a", "c")
l: List[String] = List(a, a, b, b, a, c)
scala> val in = l.toSet[String].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse
in: List[(String, Int)] = List((a,3), (b,2), (c,1))
So now you can generate more-less scattered list:
def shuffle[T](l: List[T]) = {
def fill(n: Int, l: List[List[T]], s: T) =
l.take(n + 1).reduce(_ ++ List(s) ++ _) ++ l.drop(n + 1).flatten
val in = l.toSet[T].map(x => x -> l.count(x==)).toList.sortBy(_._2).reverse
val initial = in.head._2 -> List.fill(in.head._2)(in.head._1)
in.tail.foldLeft(initial){case ((size, acc), (value, count)) =>
count -> fill(count, acc.grouped(acc.size / size).toList, value)
}._2
}
scala> shuffle(l)
res32: List[String] = List(a, b, c, a, b, a)
Every next iteration here is based on previous one with higher frequency: elements just inserted into list (from previous iteration) as broad as possible. So it may not be so effective if frequency is dropping down significantly between iterations as high frequent elements may not be "scrumbled" enough.
This algorithm isn't trying to maximise every distance - it's trying to reduce probabilty of grouped elements appearance to the minimum. Just random shuffling should do the simillar thing if you're fine with less precise result as it produces groups with still small but a bit higher probability here:
scala> scala.util.Random.shuffle(l)
res34: List[String] = List(a, b, c, b, a, a)
As the commenter said, there is no unique solution because it depends on your cost function. My idea would be along the following line, looking only for right neighbours and assigning them a score of list.size if there is no other equal element:
def maxGaps[A](in: List[A]): List[A] = {
if (in.isEmpty) return in
def noPairs(xs: List[A]): Boolean =
xs.sliding(2, 1).forall { case List(a, b) => a != b }
val (good, bad) = in.permutations.partition(noPairs)
val candidates = if (good.nonEmpty) good else bad
val maxDist = in.size
def calcScore(xs: List[A], accum: Int = 0): Int =
xs match {
case head :: tail =>
val i = tail.indexOf(head)
val j = if (i < 0) maxDist else i
calcScore(tail, accum + j)
case Nil => accum
}
candidates.maxBy(calcScore(_))
}
maxGaps("aabbac".toList) // abacab

F# Tree: Node Insertion

This is a question that extends F# Recursive Tree Validation, which I had nicely answered yesterday.
This question concerns inserting a child in an existing tree. This is the updated type I'd like to use:
type Name = string
type BirthYear = int
type FamilyTree = Person of Name * BirthYear * Children
and Children = FamilyTree list
My last question concerned checking the validity of the tree, this was the solution I decided to go with:
let rec checkAges minBirth = function
| Person(_,b,_) :: t -> b >= minBirth && checkAges b t
| [] -> true
let rec validate (Person(_,b,c)) =
List.forall isWF c && checkAges (b + 16) c
Now I would like to be able to insert a Person Simon as a child of specific Person Hans in the following form
insertChildOf "Hans" simon:Person casperFamily:FamilyTree;;
So, input should be parent name, child and the family tree. Ideally it should then return a modified family tree, that is FamilyTree option
What I am struggling with is to incorporating the validate function to make sure it is legal, and a way to insert it properly in the list of children, if the insertion Person is already a parent - maybe as a seperate function.
All help is welcome and very appreciated - thanks! :)
After your comment here's a code that will behave as expected:
let insert pntName (Person(_, newPrsnYear, _) as newPrsn) (Person (n,y,ch)) =
let rec ins n y = function
| [] -> if y < newPrsnYear && n = pntName then Some [newPrsn] else None
| (Person (name, year, childs) as person) :: bros ->
let tryNxtBros() = Option.map (fun x -> person::x) (ins n y bros)
if y < newPrsnYear && n = pntName then // father OK
if newPrsnYear < year then // brother OK -> insert here
Some (newPrsn::person::bros)
else tryNxtBros()
else // keep looking, first into eldest child ...
match ins name year childs with
| Some i -> Some (Person (name, year, i) :: bros)
| _ -> tryNxtBros() // ... then into other childs
Option.map (fun x -> Person (n, y, x)) (ins n y ch)
As in my previous answer I keep avoiding using List functions since I don't think they are a good fit in a tree structure unless the tree provides a traverse.
I might be a bit purist in the sense I use either List functions (with lambdas and combinators) or pure recursion, but in general I don't like mixing them.

Resources