Creating Duplicate Elements in an Array using Higher-Order Functions - d

New to D Language here. I'm trying to use higher-order functions (i.e. fold!, reduce!, filter!, map!) to create duplicates of array elements. I'm declaring my generic function as pure and trying to accomplish this task as a one line function. The closest I've come so far is
auto dupList(T)(T[] list) pure { (return map!(a => a.repeat(2)); }
but this gives me the following output
[[1,1],[2,2]]
instead of what I'm actually wanting
[1, 1, 2, 2]
I'm calling the function like so
writeln(dupList(nums));
Instead of using map, I've been trying to use reduce in its place but when I switch out map for reduce I get the following errors:
Error instantiated from here: `staticMap!(ReduceSeedType, __lambda2)` C:\D\dmd2\src\phobos\std\algorithm\iteration.d 3287
Error: template `D_Programs.duplist!int.duplist.__lambda2` cannot deduce function from argument types `!()(int, int)`, candidates are: C:\D\dmd2\src\phobos\std\algorithm\iteration.d 3696
Error: template instance `D_Programs.duplist!int.duplist.F!(__lambda2)` error instantiating C:\D\dmd2\src\phobos\std\meta.d 803
Error instantiated from here: `reduce!(int[])` D_Programs.d (refers to dupList)
Error `D_Programs.duplist!int.duplist.__lambda2` D_Programs.d (refers to dupList)
Error instantiated from here: `duplist!int` D_Programs.d (refers to where I'm calling from)
Any help/advice on understanding at least the top three errors and where I'm going wrong with my function would be appreciated.

map essentially replaces each element with the result of calling the passed function on that element. Since your function returns an array of two ints, the result will be an array of arrays, each element holding two ints.
Armed with this knowledge, we can use std.algorith.iteration.joiner:
auto dupList(T)(T[] list) pure { return list.map!(a => a.repeat(2)).joiner; }
As you note, it should also be possible to use reduce, but it's a bit more complicated:
auto dupList(T)(T[] list) pure { return reduce!((a,b) => a~b~b)((T[]).init, list); }
The reasons it's more complicated are:
1) reduce's function takes two arguments - the result of reducing thus far, and the next element.
2) reduce assumes the first element of the passed array is the starting point for reduction, unless a seed value is passed. Since the first element is a T, not a T[], we will need to pass a seed value. [] won't do, since it's typed as void[], so we will need to create an empty T[]. This can be done either with new T[0], or as above, (T[]).init.
Hope this helps - if there are any more questions, please ask! :)

I am assuming you meant to call map!(a => a.repeat(2))(list) or list.map!(a=>a.repeat(2)) (both are the same) since if you don't pass the actual list to the function, it isn't ever actually being called!
Anyway, neither map nor reduce will do what you want on their own. Map transforms individual elements, but can neither add nor remove elements. Reduce (and btw fold, they are basically the same) runs through the array and... well, reduces it down to just one element, like a sum function turning the array 1,2,3 into the single element, 6. Since you want to add elements, you are going to need something else outside.
But first, a sidestep: your call to reduce is failing to compile because it is being passed incorrect arguments (or something, tbh the error messages are really bad and hard to read without having the code they directly refer to open too, but it definitely refers to a lambda). Passing it your dupList won't work because dupList takes an array, but reduce works with just two elements at a time, for example, sum(a, b).
Anyway, back to the main point, the closest you can get is perhaps running another function outside map to flatten the resulting array, or in other words, join them together. There's a function for that: http://dpldocs.info/experimental-docs/std.algorithm.iteration.joiner.2.html
Suggesting a possible answer:
return list .map!(a => a.repeat(2)) .joiner;
BTW: one line functions are grossly overrated. You are often better off writing it on multiple lines, even if as a single statement, if nothing else but so you can get unique line numbers on the error messages. I would prefer to write this out probably something like this:
return
list
.map!(a => a.repeat(2))
.joiner
;
so each line represents a single step of the process. The exact formatting, of course, is up to you, but I like this more stretched out approach for (slightly) nicer error messages and an easier view when editing to add comments or more stuff before, after, in the middle, whatever.

Related

Numba Creating a tuple from a list

I have a very simple problem I can't solve.
I'm using Numba and Cuda.
I have a list T=[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0] and I want a tuple with the elements of the list, like this:
C=(1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0).
In Python I would code C=tuple(T), but I can't with Numba.
I tried these solutions but none of them work because you can't modify the type of a variable inside a loop with Numba.
Important My list has a length which is a multiple of 3 and I use this knowledge for my algorithms.
Code
First algorithm, recursively, it works by giving the algorithm L=[(1.0,),(2.0,),(3.0,),(4.0,),(5.0,),...,(9.0,)]
#njit
def list2tuple(L):
n=len(L)
if n == 1:
return L[0]
else:
C=[]
for i in range(0,n-2,3):
c=L[i]+L[i+1]+L[i+2]
C.append(c)
return list2tuple(C)
Problem: It enters an infinite loop and I must stop the kernel. It works in basic Python.
algorithm 2: it works by giving T=[1.0,2.0,3.0,...,9.0]
#njit
def list2tuple2(T):
L=[]
for i in range(len(T)):
a=(T[i],)
L.append(a)
for k in range(len(T)//3-1):
n=len(L)
C=[]
for j in range(0,n-2,3):
c=L[j]+L[j+1]+L[j+2]
C.append(c)
L=C
return L[0]
Problem When C=[(1.0,2.0,3.0),(4.0,5.0,6.0),(7.0,8.0,9.0)], you can't say L=C because L = [(1.0,),(2.0,),(3.0,),....(9.0,)] is List(Unituple(float64x1)) and can't be unified with List(Unituple(float64x3)).
I can't find a solution for this problem.
Tuples and list are very different in Numba: a list is an unbounded sequence of items of the same type while a tuple is a fixed-length sequence of items of possibly different type. As a result, the type of a list of 2 element can be defined as List[ItemType] while a tuple of 2 items can be Tuple[ItemType1, ItemType2] (where ItemType1 and ItemType2 may be the same). A list of 3 items still have the same type (List[ItemType]). However, a tuple of 3 element is a completely different type: Tuple[ItemType1, ItemType2, ItemType3]. Numba defines a UniTuple type to easily create a N-ary tuple where each item is of the same type, but this is only for convenience. Internally, Numba (and more specifically the JIT compiler: LLVM-Lite) needs to iterates over all the types and generate specific functions for each tuple type.
As a result, creating a recursive function that works on growing tuples is not possible because Numba cannot generate all the possible tuple type so to be able to just compile all the functions (one by tuple type). Indeed, the maximum length of the tuple is only known at runtime.
More generally, you cannot generate a N-ary tuple where N is variable in a Numba function. However, you can instead to generate and compile a function for a specific N. If N is very small (e.g. <15), this is fine. Otherwise, it is really a bad idea to write/generate such a function. Indeed, for the JIT, this is equivalent to generate a function with N independent parameters and when N is big, the compilation time can quickly become huge and actually be much slower than the actual computation (many compiler algorithms have theoretically a pretty big complexity, for example the register allocation which is known to be NP-complete although heuristics are relatively fast in most practical cases). Not to mention the required memory to generate such a function can also be huge.

Sort function from standard library gives an error using an iterator

I am relatively new to C++ language and trying to implement sort function from algorithm library defined in standard namespace and use std::sort directly.
The common structure to sort a vector using sort is given using iterator and comparison function.
Consider vector v as {4,3,5,9} and after sorting it will look like {9,5,4,3}.
For an instance
std::sort(v.begin(),v.end(),a>b)
So, I wanted to use this method to sort an list of nodes based on heuristic value for my A* search algorithm.Heuristic is basically addition of 2 attributes of Node object and I the sorting operation has to be done vector of this nodes and I want to use
open_list.begin() and open_list.end() as my iterators
to use my compare function as a third argument for std::sort() function here is actual implementation:
std::sort(open_list.begin(),open_list.end(),open_list.begin()->g_value + open_list.begin()->h_value > open_list.end()->g_value + open_list.end()->h_value );
Here, I basically am adding h and g values which are attributes of object Node and
open_list is a vector of pointers to the nodes. I felt my implementation was right but it throws me a weird error which looks like this:
/home/piyushkumar/CppND-Route-Planning-Project/src/route_planner.cpp:65:93: error: request for member ‘h_value’ in ‘((RoutePlanner)this)->RoutePlanner::open_list.std::vector::begin().__gnu_cxx::__normal_iterator >::operator->()’, which is of pointer type ‘RouteModel::Node*’ (maybe you meant to use ‘->’ ?)
std::sort(open_list.begin(),open_list.end(),open_list.begin()->g_value + open_list.begin()->h_value > open_list.end()->g_value + open_list.end()->h_value );
Some clarification regarding the error:
RouteModel is an class and Node inherits from that class. Why this simple comparison function as a 3rd argument fails and says that you should use -> which I have already used to retrieve values of g_value and h_value from Node object.
Any help and leads will be appreciated.
Ok let's sort things out one by one.
First about your error message. Your vector stores pointers and keep in mind that a->b is equivalent to (*a).b, so open_list.begin()->h_value equals to open_list.front().h_value, and a pointer clearly doesn't have member variable. To refer to the member variable, you need to write (*open_list.begin())->h_value. Furthermore, dereferencing .end() gives you undefined behaviour immediately. To access the last element of std::vector, use .back() instead of *(you_vector.end()). (Remember to check the vector is not empty beforehand! Otherwise you will step into undefined behaviour again :) )
Secondly your idea about how to use std::sort is wrong. To sort a range of elements by a "standard" you chose, the first two parameters of sort provide the information about the range, and the third parameter is your "standard", so it must be a "callable", and it takes two parameters and tell std::sort whether the first parameter should be sorted before the second. As a result, to sort v in descending order, you need to call std::sort in the following way:
std::sort(v.begin(), v.end(), [](int a,int b)->bool{ return a > b;});
Here, the third parameter is a lambda expression, if you don't know what the hell it is, google helps you. (FYI callable may not necessarily be a lambda expression, it may also be a function or a functor (a.k.a. function object) but I personally think lambda is the clearest one here.)
I will not give you the statement needed for sorting your open_list, you can use it to check whether you have figured out how the things work or not. Enjoy learning.
Ok, so much not right here.
The third parameter to std::sort is a "callable" (think like a function pointer), which std::sort calls to compare two elements in the sequence. It needs to take two elements of the sequence (usually by const & and return a bool.
Your example std::sort(v.begin(),v.end(),a>b) will not work, because a>b is not callable.
Your "real" code suffers from the same problem.
std::sort(open_list.begin(),
open_list.end(),
open_list.begin()->g_value + open_list.begin()->h_value >
open_list.end()->g_value + open_list.end()->h_value );
That big expression is not callable, and that's why the compiler is complaining.
Also, FWIW, open_list.end() is an iterator to the "one past the end" position in the sequence, and dereferencing it (as you do in open_list.end()->g_value) is undefined behavior, since there's no element there.
See cppreference for more info.

Sol2 unable to iterate over vector

I'm attempting to give a list of integers to a Lua script, and iterate over them.
The error I'm getting is:
test.lua:12: bad argument #1 to 'pairs' (table expected, got userdata)
stack traceback:
[C]: in function 'pairs'
test.lua:12: in main chunk
The C++ code being used:
#include <sol.hpp>
struct Test {
std::vector<int> a;
};
int main(void) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<Test>("test",
"a", &Test::a);
lua.script_file("test.lua", [](lua_State* L, sol::protected_function_result pfr) {
sol::error err = pfr;
std::cout << err.what() << std::endl;
return pfr;
});
}
The Lua script:
t = test.new()
for i in pairs(t.a) do
print(i)
end
SO I know this is an old question, but I came across this problem myself when first learning how to do this so I thought I'd add this answer for anyone coming across this now.
The problem isn't with your C++ code, it's with your Lua code. Lua uses colons ( : ) instead of full stops ( . ) for member calls, so it should look like this:
t = test:new()
for k,v in pairs(t.a) do
print(v)
end
Emphasis on member calls, mind you. Properties are still accessed with full stops. If you have a user type CObject with the function ExFnc, you could call it on object ExampleObj either of the two following ways:
ExampleObj:ExFnc()
or
CObject.ExFnc(ExampleObj)
sol (at least the version I used, 3.0.2) provides a whole assortment of container mappings already included that just work right out of the box. You can find details for them here: sol 3.0.2 containers documentation
It lists automatic compatibility with the following types:
std::vector
std::deque
std::list
std::forward_list
std::array
std::set
std::multi_set
std::map
std::multi_map
std::unordered_set
std::unordered_multiset
std::unordered_map
std::unordered_multimap
Keep in mind though that NAMESPACES in sol are tables, you have to use full stops for those.
pairs is a Lua function that only takes a single variable of type table as input. t is of type userdata, hence the error.
https://www.lua.org/manual/5.3/manual.html#pdf-pairs
You have two options here:
implement a version of pairs that can handle your userdata type
copy all elements into a table befor you feed that into pairs
Also ask yourself if it makes any sense to use pairs on a vector. A numeric for loop would feel much more natural. I'd even prefer ipairs over pairs

Remove duplicates algorithm

I'm trying to write an algorithm to remove duplicates from a vector<struct xxxx*>.
struct xxxx{
int value; // This is just to make you understand
xxxx* one;
xxxx* two;
}
As you see my struct it's like a tree but the pointers are not in order. The pointers can point to any(actually not any but most) of the others. And the vector doesn't contain the structs but pointers, so I couldn't use the std algorithms to help me neither.
I'm trying to delete duplicates with exactly same value and the same two pointers, but in the same time if I have two similar structs (Let's say A and B) and C.one or C.two points to B. Then I need to change it to A and viceversa.
In other words: if A == B then remove B and change C.one to point A.
I think I can write the brute-force, so if there's no better algorithm I'll write it by myself.
Yesterday, I tried to explain the reasonable approach to a very similar problem to a coworker who had used an N squared solution to an N log N problem.
First create a helper struct, that is basically a wrapper around an xxxx* with a comparison operator checking the contents (not the pointer value) and probably with some other utility functions. This wrapper struct isn't strictly needed vs. just using xxxx*, but from experience, I think it makes the task cleaner.
Create a std::set of those helper structs, into which you will only insert unique elements, and likely another set into which you will insert recursively unresolved elements.
Loop through the original vector and at each position recurse through its children. If you hit a child already in the unique set, that is a final value for that child pointer. If you hit a child that matches a unique element without being the one it matches, then fix the pointer that got you there. If there is also the possibility of null pointers that should bottom the recursion, and if loops are possible you need to detect them (with that recursively unresolved set) and some decision about what to do with a loop. At some point you hit resolved unique elements and add that to the unique set.
The performance and maybe even soundness of the idea depends on the depth and complexity of the loops and what you want to do with loops. There are some messy cases where a loop would map onto another loop, but detecting that could be very tricky. If your phase "like a tree" meant "no loops" then the recursion bottoms cleanly and efficiently without the extra complexity of explicitly managing the recursively unresolved elements.
Obviously I left out some of the grunt work detail around detecting unique / non-unique as you back out of the recursion and around detecting "already did it during an earlier recursion" as you hit an item in the main loop above the recursion. But all those details should be pretty obvious as you write the relevant parts of the code.
Edit: To understand how few node visits there are despite nesting a recursion inside a sequential loop, think from the point of view of the pointers. We follow each pointer at most once (some duplicates are pre detected without following their pointers). For N nodes, there are N top level pointers (if I understood your description correctly) and significantly less than 2N internal pointers (the more tree-like it is, the closer it will be to N-1 internal pointers, rather than 2N). So each node is visited on average less than 3 times and a minority of those visits require both the pre lookup and the post recursion lookup, and each lookup is log U where U is the number of unique items found up to that point. So we can trivially see a bound of 6 N log N.

How to add element to existing list without creating new variable in erlang?

I have a list contains some elements and now with the help of lists:foreach I am fetching some more records and I want to append each value to my existing list elements without creating new variable as doing in other languages with help of array.
Here is my sample code which I am getting:
exception error: no match of right hand side value [6,7,1].
Sample Code:
listappend() ->
A = [1,2,3,4,5],
B = [6,7],
lists:foreach(fun (ListA) ->
B = lists:append(B, [ListA])
end, A),
B.
I want output like,
B = [6,7,1,2,3,4,5].
First of all, this feature already exists, so you won't need to implement it yourself. In fact, the list can take two lists as arguments:
1> lists:append([1,2,3,4,5], [6,7]).
[1,2,3,4,5,6,7]
Which is actually implemented as:
2> [1,2,3,4,5] ++ [6,7].
[1,2,3,4,5,6,7]
Please bear in mind that the ++ operator will copy the left operand, so this operation can easily lead to quadratic complexity. Said that, you probably want to construct your lists using the "cons" operator (eventually reversing the list at the end of the computation):
3> [1|[2,3,4,5,6,7]].
[1,2,3,4,5,6,7]
In any case, you can have two arguments in your function, which are the two lists to append, instead of defining them in the body of the function. This way, the values of A and B will change every time you call the my_append/2 function.
my_append(A, B) ->
YOUR_CODE_GOES_HERE
As a note and regarding the actual error you're getting, this is due to the following line:
B = lists:append(B, [ListA])
During each iteration, you're binding a new value to the variable B, which is already bound to the value [6,7].
Variables in Erlang are immutable. That means you cannot assign a new value to a variable once it has been bound, and this is why you get the 'no match' error. The old value does simply not match the new value you are trying to assign to the variable. Instead, you can create a new list using e.g lists:append based on the old one. You should probably start by looking at recursion and how you can use it to manipulate lists.