How to get the indicies from sort or member commands in MAXIMA - sorting

The sort or member functions in MAXIMA do not return the indicies of elements sorted or the index of element being searched for. Is there a sort function that returns indices? Thanks.
Sven

There aren't built-in functions for those tasks, but I think you can write something fairly easily:
member_index (x, l) :=
(sublist_indices (l, lambda ([y], x = y)),
if %% = [] then false else first (%%));
This member_index function returns the index of the first instance of x. If you want indices for all instances, just remove the if expression and return %% instead.
ranks (l) :=
block ([l1, l2],
makelist ([l[i], i], i, length (l)),
l1 : sort (%%, lambda ([x, y], orderlessp (x, y))),
l2 : makelist (0, length (l)),
for i thru length (l) do l2[l1[i][2]] : i,
l2);
This ranks function returns integer values when there are ties (i.e. same values). Sometimes it is preferable to return the average rank for ties; that take a little more code. There is a ranks function in share/amatrix/wilcoxon.mac which does average ties. You can load that function via load(wilcoxon);.

Related

Algorithm to find list given dot product and another list

I need to write a function findL that takes a list L1 of integers and a desired dot product n, and returns a list L2 of nonnegative integers such that L1 · L2 = n. (By "dot product" I mean the sum of the pairwise products; for example, [1,2] · [3,4] = 1·3+2·4 = 11.)
So, for example, findL(11, [1,2]) might return SOME [3,4]. If there's no possible list, I return NONE.
I'm using a functional language. (Specifically Standard ML, but the exact language isn't so important, I'm just trying to think of an FP algorithm.) What I have written so far:
Let's say I have findL(n, L1):
if L1 = [], I return NONE.
if L1 = [x] (list of length 1)
if (n >= 0 and x > 0 and n mod x = 0), return SOME [n div x]
else return NONE
If L1 has length greater than 1, I recurse on findL (n, L[1:]). If that returns a list L2, I return [1] concatenated to L2. If the recursive call returns NONE, I did another recursive call on findL (0, L[1:]) and prepended [n div x] to the result if it wasn't NONE. This works on many inputs but are failing on others.
I need to change part 3, but I'm not sure if I have the right idea. I would appreciate any tips!
Unless you need to say that empty lists in the input are always bad (even n = 0 with the list []), I'd recommend returning something different for an empty list based on whether you've reached 0 at the end (everything has been subtracted away) or not, then recurse when receiving any nonempty list rather than special-casing a one-element list.
As far as step three, you need to test every possible positive integer multiple of the first element of your input list until they exceed n, not just the first and last. The first non-None value you get is good enough, so you just prepend the multiplier (not the multiple) to the return list. If everything gives you Nones, you return None.
I don't know SML, but here's how I'd do it in Haskell:
import Data.Maybe (isJust, listToMaybe)
-- Find linear combinations of positive integers
solve :: Integer -> [Integer] -> Maybe [Integer]
-- If we've made it to the end with zero left, good!
solve 0 [] = Just []
-- Otherwise, this way isn't the way to go.
solve _ [] = Nothing
-- If one of the elements of the input list is zero, just multiply that element by one.
solve n (0:xs) = case solve n xs of
Nothing -> Nothing
Just ys -> Just (1:ys)
solve n (x:xs) = listToMaybe -- take first solution if it exists
. map (\ (m, Just ys) -> m:ys) -- put multiplier at front of list
. filter (isJust . snd) -- remove nonsolutions
. zip [1 ..] -- tuple in the multiplier
. map (\ m -> solve (n - m) xs) -- use each multiple
$ [x, x + x .. n] -- the multiples of x up to n
Here it is solving 11 with [1, 2] and 1 with [1, 2].

How to call a function in foreach with local variables as arguments?

I have a knapsack problem to solve in B-Prolog. I have to write something like:
knapsack(X, Indexes, Quantity, Weights, Values, Capacity)
X - array with number of ith item that is put in the bag
Indexes - [0, ..., NumOfItems-1]
Quantity - array with number of available ith items
Weights - array with weight of each item on ith position (only 1 item)
Value - array with value of each item (only 1 item)
Capacity - limit for bag capacity
The task must be solved using a predicate:
get([X|_], 0, X).
get([_|X], I, Y) :- I>0, I1 is I-1, get(X, I1, Y).
which returns the element on ith index, considering they can start at 0. Then Y has the value of that element.
Also, we must maximize the item values. I tried to make it work not only for fixed number of items.
Since I'm just a beginer for Prolog, I had an idea, but it doesn't wort of course.
knapsack(X, Indexes, Quantity, Weights, Values, Capacity) :-
/*
Find the last index of items,
Calculate NumOfItems as last index+1,
Make an array X with NumOfItems elements,
Define domen for each item (ith element in X) as 0..NumOfThatItem
(meaning I can take zero or more up to the max number of that element that is avaliable)
*/
last(Indexes, Elem),
NumOfItems is Elem+1,
length(X, NumOfItems),
foreach(I in 1..NumOfItems, get(Quantity, I, K), X[I]::0..K),
/*
Set up the constraint that sum of item weights must not be bigger than bag capacity
*/
sum([X[I]*T : I in 1..NumOfItems], get(Weights, I, T)) #=< Capacity,
/*
Maximize the values of items in the bag, and find all possible combinations for it
*/
labeling([maximize( sum([X[I]*V : I in 1..NumOfItems, get(Values, I, V)]))], X),
/*
This is the part of a task, to write out the Profit we made by taking those items,
and the overall weight that we have put in the bag.
*/
Profit is sum([X[I]*V : I in 1..NumOfItems, get(Values, I, V)]),
Weight is sum([X[I]*T : I in 1..NumOfItems, get(Weights, I, T)]),
nl,
write('Profit: '), write(Profit), nl,
write('Weight: '), write(Weight), nl
.
I am using B-Prolog Version 8.1, it can be downloaded on this link(<- click)
You can copy my code and place it in the BProlog folder on the location where you chose to install it.
When you open/start bp aplication:
cl('path_to_my_code.pro').
Exaple I have for this problem is the following:
knapsack(X, [0,1,2,3], [1,1,1,4], [50,10,5,1], [1000,2000,100,1], 63).
And that should give us:
Profit: 3003
Weight: 63
X = [1,1,0,3]
I get the following:
***illegal_local_variables(get([1,1,1,4], _f8, _fc))
I concluded that he doesn't recognize I as a number.
If you have any book or article or whatever related to this please share.
How should this be done? Please help...
Thank you for your time
At this point since you get the error you should test get/3 predicate to see if this working properly. The problem is in the part:
I>0, I1 is I-1, get(X, I1, Y).
Since you call get with I as a variable, I>0 yields instantiation error, instead you can write:
get([X|_], 0, X).
get([_|X], I, Y) :- get(X, I1, Y), I is I1+1, I>0.

Prolog inserting multiple elements into list

I want to implement a predicate (vecLine2BitLine) which does the following:
get two lists and a number the first list is the length of blocks (the elements of the blocks are '$') and the second list contains the indexes that these blocks should be placed at meaning:
vecLine2BitLine([1,2,1],[2,5,9],12,BitLine).
BitLine=[' ','$',' ',' ','$','$',' ',' ','$',' ',' ',' '].
explanation:a block of length 1 is at index 2
and a block of length 2 is at index 5 and so on..
insert_at_mul : inserts an element N times (it works perfectly,dupli and my_flatten were implemented previously so i used them)
Ive been trying to activate insert_at_mul N times when N is the length of the list X and Y
in the predicate vecLine2BitLine.
dupli(L1,N,L2) :- dupli(L1,N,L2,N).
dupli([],_,[],_).
dupli([_|Xs],N,Ys,0) :- dupli(Xs,N,Ys,N).
dupli([X|Xs],N,[X|Ys],K) :- K > 0, K1 is K - 1, dupli([X|Xs],N,Ys,K1).
my_flatten(X,[X]) :- \+ is_list(X).
my_flatten([],[]).
my_flatten([X|Xs],Zs) :- my_flatten(X,Y), my_flatten(Xs,Ys), append(Y,Ys,Zs).
insert_at_mul(L,X,K,R,N):-dupli([X],N,XX) , insert_at(L,XX,K,L1) , my_flatten(L1,R).
get_num_spaces(L,N,X):-sum(L,S), X is N-S.
generate_spaces(N,L,X):- insert_at_mul(L,'',1,X,N).
vecLine2BitLineAux([],[],_,_,_).
vecLine2BitLineAux([X|Tail1],[Y|Tail2],N,L,Lnew):- insert_at_mul(L,'*',Y,Lnew,X) ,vecLine2BitLineAux(Tail1,Tail2,N,Lnew,R). // problem here!!!
vecLine2BitLine(X,Y,N,L):- get_num_spaces(X,N,Z) , generate_spaces(Z,[],ZZ) , vecLine2BitLineAux(X,Y,N,ZZ,L).
now the problem is that in the function vecLine2BitLine i cant activate insert_at_mul N times(thats what i tried to do in this code, but failed).
how can I fix vecLine2BitLine for it to work properly as in returning the correct output by actually activating the predicate insert_at_mul N times??
THANKS!
added :
vecLine2BitLine : input parameters : (L1,L2,N,Result)
N: after activating the predicate Result will be N in length.
L1: L1 is a list of numbers each number indicates the length of a block, a block is comprised of a Sequence of '$'.
L2: L2 is a list of numbers the numbers are indices for where the blocks in L1 should be placed.
example:
vecLine2BitLine([3,2],[1,5],9,BitLine).
we can look at the input better as tuples :
vecLine2BitLine[(3,1),(2,5)],9,BitLine).
(3,1) : there is a sequence of '' 3 times at index 1
(2,5) : there is a sequence of '' 2 times at index 5
in our example 9 is the length of BitLine at the end and we have to insert into the
list BitLine 3+2 of the "special chars" '*' but we have 9-(3+2) places left in the list
so we add '' in those places and then we get:
BitLine=['$','$','$','','$','$','','','',''].
This is kind of a nice problem because you can use the arguments as loop counters. The K argument gets you to the proper index. Let's just traverse the list and find a particular index as an example. Notice the base case is that you're at the right element, and the inductive case is prior to the right element.
traverse(1, [X|_], X).
traverse(N, [_|Xs], X) :- N > 0, N0 is N-1, traverse(N0, Xs, X).
We're going to apply that pattern to insert_at/4 to get to the right location in the list. Now let's write a repeat/3 predicate that repeats X N times in a new list L. This time the base case is when we've added all the repetitions we care to, and the inductive case is that we'll add another instance.
repeat(1, X, [X]).
repeat(N, X, [X|Xs]) :- N > 0, N0 is N-1, repeat(N0, X, Xs).
You can see the similarity of structure between these two. Try to combine them into a single predicate. Since this is homework, I'll stop here. You're inches from the goal.

Prolog Counter Problem

I am trying to write a procedure order(List,Result) that has a List as input and returns a list Result of ordered pairs such that:
the first element of the ordered pair is the position of the pair in the list, and
the second element of the ordered pair is the element from List n the corresponding position.
Example:
if List = [a,b,c,d], the procedure order(List,Result) outputs the list:
Result = [(1,a), (2,b),(3,c),(4,d)].
I am struggling with the counter for the position of the pair in the list. I have made attempts such as:
increment(Accum,Total):-
Total is Accum + 1.
order([],[]).
order([Head|Tail],Result):-
order(Tail, NewTail),
NewCount is Count + 1,
increment(NewCount,Count),
Result = [(Count,Head)|NewTail].
Please help anyone?
The two clauses: NewCount is Count + 1 and increment(NewCount,Count) basically have the same meaning. You didn't make clear that Count is an input variable and it has a base case of 1, so Prolog didn't know where to start unifying values for it. For example, you should use Count as an input argument as follows (it doesn't change much if compared with your version):
order([],[], _).
order([Head|Tail],[(Count,Head)|NewTail], Count):-
NewCount is Count + 1,
order(Tail, NewTail, NewCount).
order(List, Result ):- order(List, Result, 1).
If you're OK with using findall/3 then this is probably the simplest solution:
order(List, Result) :-
findall(Index-Elem, nth1(Index, List, Elem), Result).
Note that here the key-value pairs are represented using the term -/2, which is how pairs are usually represented in Prolog, e.g. this is what keysort/2 expects.
order(List,Result) :-
findall((N,E),(
append(L0,[E|_],List),
length([_|L0],N)),
Result).

Passing results in prolog

I'm trying to make a function that has a list of lists, it multiplies the sum of the inner list with the outer list.
So far i can sum a list, i've made a function sumlist([1..n],X) that will return X = (result). But i cannot get another function to usefully work with that function, i've tried both is and = to no avail.
Is this what you mean?
prodsumlist([], 1).
prodsumlist([Head | Tail], Result) :-
sumlist(Head, Sum_Of_Head),
prodsumlist(Tail, ProdSum_Of_Tail),
Result is Sum_Of_Head * ProdSum_Of_Tail.
where sumlist/2 is a SWI-Prolog built-in.
Usage example:
?- prodsumlist([[1, 2], [3], [-4]], Result).
Result = -36.
The part "it multiplies the sum of the inner list with the outer list" isn't really clear, but I believe you mean that, given a list [L1,...,Ln] of lists of numbers, you want to calculate S1*..*Sn where Si is the sum of the elements in Li (for each i).
I assume the existence of plus and mult with their obvious meaning (e.g. plus(N,M,R) holds precisely when R is equal to N+M). First we need predicate sum such that sum(L,S) holds if, and only if, S is the sum of the elements of L. If L is empty, S obviously must be 0:
sum([],0).
If L is not empty but of the form [N|L2], then we have that S must be N plus the sum S2 of the elements in L2. In other words, we must have both sum(L2,S2) (to get S2 to be the sum of the elements of L2) and plus(N,S2,S). That is:
sum([N|L2],S) :- sum(L2,S2), plus(N,S2,S).
In the same way you can figure out the predicate p you are looking for. We want that p(L,R) holds if, and only if, R is the product of S1 through Sn where L=[L1,...,Ln] and sum(Li,Si) for all i. If L is empty, R must be 1:
p([],1).
If L is not empty but of the form [LL|L2], then we have that R must be the product of 'S', the sum of the elements of LL, and 'P', the product of the sums of the lists in L2. For S we have already have sum(LL,S), so this gives us the following.
p([LL|L2],R) :- sum(LL,S), p(L2,P), mult(S,P,R).
One thing I would like to add is that it is probably not such a good idea to see these predicates as functions you might be used to from imperative or functional programming. It is not the case that sumlist([1,..,n],X) returns X = (result); (result) is a value for X such that sumlist([1,...,n],X) is true. This requires a somewhat different mindset. Instead of thinking "How can I calculate X such that p(X) holds?" you must think "When does P(X) hold?" and use the answer ("Well, if q(X) or r(X)!") to make the clauses (p(X) :- q(X) and p(X) :- r(X)).
Here is a rewrite of Kaarel's answer (that's the intention anyway!) but tail-recursive.
prodsumlist(List, Result) :-
xprodsumlist(List,1,Result).
xprodsumlist([],R,R).
xprodsumlist([Head|Rest],Sofar,Result) :-
sumlist(Head, Sum_Of_Head),
NewSofar is Sofar * Sum_Of_Head,
xprodsumlist(Rest, NewSofar, Result).

Resources