Ordering a List of Pairs - recursion

Can anyone give me a well-written implementation of how to order a list of pairs in scheme using a helper function (based on the value of the car of each of the pairs)? For example, '((3 2) (1 2) (8 4) (0 6)) should be ordered as '((0 6) (1 2) (3 2) (8 4)). This seems like such a simple thing to do, but for some reason I am drawing a blank.

Well, first of all you can use your favorite built-in sort routine, and specify it be sorting by car, e.g. in Common LISP
(sort ls #'< :key #'car)
if your Scheme lacks the ability to specify key, you can emulate this by a comparison procedure
(sort ls (lambda (a b) (< (car a) (car b))))
second, if you want to reimplement this, you could use the approach of mergesort: break up your list into monotone increasing portions, then merge them pairwise until there's only one left. In Haskell,
mergesortBy f xs
| null xs = []
| [s] <- until (null.tail) (pairwise (mergeBy f)) (breakup xs) = s
pairwise g (a:b:t) = g a b : pairwise g t
pairwise _ t = t
breakup xs = [[x] | x <- xs] -- a list of (a list of x) for x in xs
since the portions are monotone increasing (or at least non-decreasing), mergeBy can be easily implemented.
Of course, a "well-written" implementation will replace the rudimentary breakup shown here with an initial phase which will try to make longer chunks, preserving the non-decreasing and reversing the non-increasing chunks on the go (a Haskell example is here). pairwise and mergeBy (and perhaps even breakup) functions will have to be fused into one, to make the overall implementation more on-line, since Scheme is (usually) a strict (i.e. non-lazy) language. You could use explicit suspensions in the internal lists being merged, so that taking a few first elements off a sorted list is an O(n) operation.

Related

Creating a list of ordered pairs in lambda calculus using recursion

My input is two lists being l = [x1, x2, x3,...,xn] and k = [y1, y2, y3,...,yn]
I want a y = [(x1,y1),(x2,y2),(x3,y3)...(xn,yn)] output.
How can I apply recursion to my code? I could do it for the first item with
f = \l k. (cons (pair (head l) (head k)) empty) but I don't understand exactly how do I use recursion to create the other items.
The function "head" returns the first item of a list and the function "tail" returns a list without the first item.
Naturally it depends precisely on how you've implemented tuples, lists, etc. in Lambda Calculus. But assuming standard functional cons lists, and that both lists are the same length, and that you already have defined the following helpers, some of which you have already cited:
cons -- construct a list from a node and another list
empty -- the empty list
head -- retrieve the first node value of a list
tail -- retrieve all but the first node of a list
pair -- pair values into a tuple
isEmpty -- return `true` if a list is `empty`, `false` otherwise
true -- return the first argument
false -- return the second argument
Then we can recursively zip the lists as follows:
ZIP = λlk. isEmpty l -- "if the list is empty…"
empty -- "return an empty result. Else…"
(cons -- "return a new list, containing…"
(pair (head l) (head k)) -- "the zipped heads, and…"
(ZIP (tail l) (tail k))) -- "everything else zipped."
The problem of course is that the raw lambda calculus doesn't have recursion. You cannot refer to a function name within its own definition. The answer is to use a fixed-point combinator, e.g. the famous Y combinator.
ZIP = Y (λzlk. isEmpty l empty (cons (pair (head l) (head k)) (z (tail l) (tail k)))
The definition of Y is:
Y = λf.(λx.f(x x))(λx.f(x x))
Untangling how precisely this works is an impressive bit of mental gymnastics that is not quite in scope for this question, but using it is pretty simple. In general, if you have a desired (but illegal, in raw LC) recursive definition like this:
R = λ ??? . ??? R ???
You can instead write it as the totally legal, non-recursive definition:
R = Y (λr ??? . ??? r ???)
In other words, add a new parameter to your function which stands in for your recursive function, and use Y to wire up everything for you. That Y can invent recursion from scratch is extraordinary and the reason it is so famous.

SMLNJ powerset function

I am trying to print the size of a list created from below power set function
fun add x ys = x :: ys;
fun powerset ([]) = [[]]
| powerset (x::xr) = powerset xr # map (add x) (powerset xr) ;
val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list;
I have the list size function
fun size xs = (foldr op+ 0 o map (fn x => 1)) xs;
I couldnt able to merge these two functions and get the result like
I need something like this:
[(0,[]),(1,[3]),(1,[2]),(2,[2,3]),(1,[1]),(2,[1,3]),(2,[1,2]),(3,[1,2,3])]
Could anyone please help me with this?
You can get the length of a list using the built-in List.length.
You seem to forget to mention that you have the constraint that you can only use higher-order functions. (I am guessing you have this constraint because others these days are asking how to write powerset functions with this constraint, and using foldr to count, like you do, seems a little constructed.)
Your example indicates that you are trying to count each list in a list of lists, and not just the length of one list. For that you'd want to map the counting function across your list of lists. But that'd just give you a list of lengths, and your desired output seems to be a list of tuples containing both the length and the actual list.
Here are some hints:
You might as well use foldl rather than foldr since addition is associative.
You don't need to first map (fn x => 1) - this adds an unnecessary iteration of the list. You're probably doing this because folding seems complicated and you only just managed to write foldr op+ 0. This is symptomatic of not having understood the first argument of fold.
Try, instead of op+, to write the fold expression using an anonymous function:
fun size L = foldl (fn (x, acc) => ...) 0 L
Compare this to op+ which, if written like an anonymous function, would look like:
fn (x, y) => x + y
Folding with op+ carries some very implicit uses of the + operator: You want to discard one operand (since not its value but its presence counts) and use the other one as an accumulating variable (which is better understood by calling it acc rather than y).
If you're unsure what I mean about accumulating variable, consider this recursive version of size:
fun size L =
let fun sizeHelper ([], acc) = acc
| sizeHelper (x::xs, acc) = sizeHelper (xs, 1+acc)
in sizeHelper (L, 0) end
Its helper function has an extra argument for carrying a result through recursive calls. This makes the function tail-recursive, and folding is one generalisation of this technique; the second argument to fold's helper function (given as an argument) is the accumulating variable. (The first argument to fold's helper function is a single argument rather than a list, unlike the explicitly recursive version of size above.)
Given your size function (aka List.length), you're only a third of the way, since
size [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
gives you 8 and not [(0,[]),(1,[3]),(1,[2]),(2,[2,3]),...)]
So you need to write another function that (a) applies size to each element, which would give you [0,1,1,2,...], and (b) somehow combine that with the input list [[],[3],[2],[2,3],...]. You could do that either in two steps using zip/map, or in one step using only foldr.
Try and write a foldr expression that does nothing to an input list L:
foldr (fn (x, acc) => ...) [] L
(Like with op+, doing op:: instead of writing an anonymous function would be cheating.)
Then think of each x as a list.

Checking if numbers are even or odd in lisp

I need to write a recursive method in lisp that doubles the odd values and leaves the even values alone.
So far i have:
(defun MY-DOUBLE-ODD (n)
(if (oddp n)
(setq n (* n 2)))
n)
However, I just can't figure out how to have this recursive method go through an entire list.
How do I fix it to make it iterate through (MY-DOUBLE-ODD (1 2 3 4 5 6))
??
Your solution should not involve setq at all. The recursion should be used to iterate the list of arguments, using car to get the first element, cdr to get the rest of the list to recurse on, and cons to construct the result on return from the recursive call.

Simple functions for SML/NJ

I was required to write a set of functions for problems in class. I think the way I wrote them was a bit more complicated than they needed to be. I had to implement all the functions myself, without using and pre-defined ones. I'd like to know if there are any quick any easy "one line" versions of these answers?
Sets can be represented as lists. The members of a set may appear in any order on the list, but there shouldn't be more than one
occurrence of an element on the list.
(a) Define dif(A, B) to
compute the set difference of A and B, A-B.
(b) Define cartesian(A,
B) to compute the Cartesian product of set A and set B, { (a, b) |
a∈A, b∈B }.
(c) Consider the mathematical-induction proof of the
following: If a set A has n elements, then the powerset of A has 2n
elements. Following the proof, define powerset(A) to compute the
powerset of set A, { B | B ⊆ A }.
(d) Define a function which, given
a set A and a natural number k, returns the set of all the subsets of
A of size k.
(* Takes in an element and a list and compares to see if element is in list*)
fun helperMem(x,[]) = false
| helperMem(x,n::y) =
if x=n then true
else helperMem(x,y);
(* Takes in two lists and gives back a single list containing unique elements of each*)
fun helperUnion([],y) = y
| helperUnion(a::x,y) =
if helperMem(a,y) then helperUnion(x,y)
else a::helperUnion(x,y);
(* Takes in an element and a list. Attaches new element to list or list of lists*)
fun helperAttach(a,[]) = []
helperAttach(a,b::y) = helperUnion([a],b)::helperAttach(a,y);
(* Problem 1-a *)
fun myDifference([],y) = []
| myDifference(a::x,y) =
if helper(a,y) then myDifference(x,y)
else a::myDifference(x,y);
(* Problem 1-b *)
fun myCartesian(xs, ys) =
let fun first(x,[]) = []
| first(x, y::ys) = (x,y)::first(x,ys)
fun second([], ys) = []
| second(x::xs, ys) = first(x, ys) # second(xs,ys)
in second(xs,ys)
end;
(* Problem 1-c *)
fun power([]) = [[]]
| power(a::y) = union(power(y),insert(a,power(y)));
I never got to problem 1-d, as these took me a while to get. Any suggestions on cutting these shorter? There was another problem that I didn't get, but I'd like to know how to solve it for future tests.
(staircase problem) You want to go up a staircase of n (>0) steps. At one time, you can go by one step, two steps, or three steps. But,
for example, if there is one step left to go, you can go only by one
step, not by two or three steps. How many different ways are there to
go up the staircase? Solve this problem with sml. (a) Solve it
recursively. (b) Solve it iteratively.
Any help on how to solve this?
Your set functions seem nice. I would not change anything principal about them except perhaps their formatting and naming:
fun member (x, []) = false
| member (x, y::ys) = x = y orelse member (x, ys)
fun dif ([], B) = []
| dif (a::A, B) = if member (a, B) then dif (A, B) else a::dif(A, B)
fun union ([], B) = B
| union (a::A, B) = if member (a, B) then union (A, B) else a::union(A, B)
(* Your cartesian looks nice as it is. Here is how you could do it using map: *)
local val concat = List.concat
val map = List.map
in fun cartesian (A, B) = concat (map (fn a => map (fn b => (a,b)) B) A) end
Your power is also very neat. If you call your function insert, it deserves a comment about inserting something into many lists. Perhaps insertEach or similar is a better name.
On your last task, since this is a counting problem, you don't need to generate the actual combinations of steps (e.g. as lists of steps), only count them. Using the recursive approach, try and write the base cases down as they are in the problem description.
I.e., make a function steps : int -> int where the number of ways to take 0, 1 and 2 steps are pre-calculated, but for n steps, n > 2, you know that there is a set of combinations of steps that begin with either 1, 2 or 3 steps plus the number combinations of taking n-1, n-2 and n-3 steps respectively.
Using the iterative approach, start from the bottom and use parameterised counting variables. (Sorry for the vague hint here.)

Algorithm to return all possible combinations of n objects taken from different bins

To make it more specific, I need an algorithm (recursive or not) that, given a integer n and a matrix as input, will return me all of the combinations that will have:
1) At least 1 object from each line
2) Will have n objects total
I feel I could solve this easier if I just tried all combinations and use the ones that have n objects and 1 from each line, but I believe that the algorithm can be a lot more efficient than that.
I have also successfully coded an algorithm that will return all combinations of 1 object per line, but couldn't expand it to more. I've been coding in Python, but any language is fine. Extra points for consideration that python passes objects per reference. =)
Assume the matrix is squared. If anyone wants to know why, this is part of a more complex graph algorithm I'm trying to solve.
Thanks all!
Assume the matrix m is a list of lists; here is a Racket function for it:
(define (combinations m n)
(cond
((and (zero? n) (null? m)) '(()))
((zero? n) '())
((null? m) '())
((null? (car m)) '())
(else
(append (combinations (cons (cdar m) (cdr m)) n)
(map (lambda (ls) (cons (caar m) ls))
(append
(combinations (cons (cdar m) (cdr m)) (sub1 n))
(combinations (cdr m) (sub1 n))))))))
Thanks for all the answers, they were close to what I was looking for. I managed to do it under Python (so I didn't check the results posted here), my problem was actually Python passing reference vs copy in function calls. I thought a shallow copy would have been enough, but apparently I needed a deep copy (haven't thought it through why shallow wasn't enough).
This is how I did it:
PS1: Graphs here are dictionaries of lists. n_edges is the number of edges to be picked from the graph
PS2: Size calculation here is pretty inefficient, haven't taken time to fix it yet.
PS3: In order to iterate orderly over a dictionary, I created two lists: a list-of-lists representation of the graph (lol) and an index array that matches it (lolindex).
PS4: Adapted to fit the question I posted, the real method I used has more problem specific code to it. Haven't tested the code in the way I put it here.
def pickEdges(n_edges, newgraph):
size = sum(len(v) for v in newgraph.itervalues())
if (size == n_edges):
print newgraph
return
for i in range(len(lol)):
for j in range(len(lol[i])):
tmpgraph = copy.deepcopy(newgraph)
if (lol[i][j] not in tmpgraph[lolindex[i]]):
tmpgraph[lolindex[i]].append(lol[i][j])
pickEdges(n_edges, tmpgraph)
Most likely you want to modify the task and list all combinations of a simple list?
Below is a Javascript function that will do this for you:
function getWayStr(curr) {
var nextAbove = -1;
for (var i = curr + 1; i < waypoints.length; ++i) {
if (nextAbove == -1) {
nextAbove = i;
} else {
wayStr.push(waypoints[i]);
wayStr.push(waypoints[curr]);
}
}
if (nextAbove != -1) {
wayStr.push(waypoints[nextAbove]);
getWayStr(nextAbove);
wayStr.push(waypoints[curr]);
}
}
What a great question! To be consistent with terminology, I will refer to the lines in your matrix as "input bags" and the items in the input bags as "objects". A bag (or multiset) is a container that allow members to appear more than once but whose members do not have an inherent order (unlike lists).
We are looking for a function with the following signature:
set of valid combinations =
generate_combinations(list of input bags, number of objects in valid combination)
Since it is possible that the set of valid combinations exceeds the memory available to Python, generate_combinations should return a generator rather than an explicit list.
A valid result must satisfy the following requirements:
At least 1 object from each input bag
Will have n objects total
I am assuming the following:
The order of the objects in a result does not matter
An input bag can contain duplicate objects
Two input bags can contain duplicate objects (in the degenerate case, two input bags can be identical)
A valid result pulls objects without replacement
Requirement #1 and Assumption #4 imply number of input bags <= n <= total number of objects in all bags
Data Structures
Since input bags are allowed to contain duplicate values (per Assumption #2), we cannot use set/frozenset to store these. Python lists are suitable for this task. An alternative container could be collections.Counter, which has constant-time membership test and better spatial efficiency for lists with many duplicates.
Each valid combination is also a bag
Order does not matter for the list of input bags, so this could be generalized as a bag of input bags. For sanity, I'll leave it as is.
I will use Python's built-in itertools module to generate combinations, which was introduced in v2.6. If you are running an older version of Python, use a recipe. For these code-examples, I have implicitly converted generators into lists for clarity.
>>> import itertools, collections
>>> input_bags = [Bag([1,2,2,3,5]), Bag([1,4,5,9]), Bag([12])]
>>> output_bag_size = 5
>>> combos = generate_combinations(input_bags, output_bag_size)
>>> combos.next() #an arbitrary example
Bag([1,1,2,4,12])
Realize that the problem as stated above can be reduced to one that is immediately solvable by Python's built-in itertools module, which generates combinations of sequences. The only modification we need to do is eliminate Requirement #1. To solve the reduced problems, combine the members of the bags into a single bag.
>>> all_objects = itertools.chain.from_iterable(input_bags)
>>> all_objects
generator that returns [1, 2, 2, 3, 5, 1, 4, 5, 9, 12]
>>> combos = itertools.combinations(all_objects, output_bag_size)
>>> combos
generator that returns [(1,2,2,3,5), (1,2,2,3,1), (1,2,2,3,4), ...]
To reinstate requirement #1, each valid combination (output bag) needs to contain 1 element from each input bag plus additional elements from any of the bags until the output bag size reaches the user-specified value. If the overlap between [1 element from each input bag] and [additional elements from any of the bags] is ignored, the solution is just the cartesian product of the possible combinations of the first and the possible combinations of the second.
To handle the overlap, remove the elements from [1 element from each input bag] from the [additional elements from any of the bags], and for-loop away.
>>> combos_with_one_element_from_each_bag = itertools.product(*input_bags)
>>> for base_combo in combos_with_one_element_from_each_bag:
>>> all_objects = list(itertools.chain.from_iterable(input_bags))
>>> for seen in base_combo:
>>> all_objects.remove(seen)
>>> all_objects_minus_base_combo = all_objects
>>> for remaining_combo in itertools.combinations(all_objects_minus_base_combo, output_bag_size-len(base_combo)):
>>> yield itertools.chain(base_combo, remaining_combo)
The remove operation is supported on lists but isn't supported on generators. To avoid storing all_objects in memory as a list, create a function that skips over the elements in base_combo.
>>> def remove_elements(iterable, elements_to_remove):
>>> elements_to_remove_copy = Bag(elements_to_remove) #create a soft copy
>>> for item in iterable:
>>> if item not in elements_to_remove_copy:
>>> yield item
>>> else:
>>> elements_to_remove_copy.remove(item)
An implementation of the Bag class might look like this:
>>> class Bag(collections.Counter):
>>> def __iter__(self):
>>> return self.elements()
>>> def remove(self, item):
>>> self[item] -= 1
>>> if self[item] <= 0:
>>> del self[item]
Complete code
import itertools, collections
class Bag(collections.Counter):
def __iter__(self):
return self.elements()
def remove(self, item):
self[item] -= 1
if self[item] <= 0:
del self[item]
def __repr__(self):
return 'Bag(%s)' % sorted(self.elements())
def remove_elements(iterable, elements_to_remove):
elements_to_remove_copy = Bag(elements_to_remove) #create a soft copy
for item in iterable:
if item not in elements_to_remove_copy:
yield item
else:
elements_to_remove_copy.remove(item)
def generate_combinations(input_bags, output_bag_size):
combos_with_one_element_from_each_bag = itertools.product(*input_bags)
for base_combo in combos_with_one_element_from_each_bag:
all_objects_minus_base_combo = remove_elements(itertools.chain.from_iterable(input_bags), base_combo)
for remaining_combo in itertools.combinations(all_objects_minus_base_combo, output_bag_size-len(base_combo)):
yield Bag(itertools.chain(base_combo, remaining_combo))
input_bags = [Bag([1,2,2,3,5]), Bag([1,4,5,9]), Bag([12])]
output_bag_size = 5
combos = generate_combinations(input_bags, output_bag_size)
list(combos)
Finish this off by adding in error-checking code (such as output_bag_size >= len(input_bags).
The benefits of this approach are:
1. Less code to maintain (namely itertools)
2. No recursion. Python performance degrades with call stack height, so minimizing recursion is beneficial.
3. Minimum memory consumption. This algorithm requires constant-space memory beyond what's consumed by the list of input bags.

Resources