Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Michaël Benesty
    @pommedeterresautee
    Can you please provide me with some guidelines? A doc (even basic) using a custom lib with a custom preset?
    Samuel Audet
    @saudet
    Michaël Benesty
    @pommedeterresautee
    Thanks but the doc is for Java with Maven. I am wondering if I can find the workflow when I use SBT?
    How am I supposed to call the Build() function?
    stuff like that
    The point is that the error I have doesn't happen when I manually compile the lib or when I use it in JNA. Therefore I think I screw up the workflow in javacpp...
    Samuel Audet
    @saudet
    It doesn't have anything to do with Scala, for that error we need to tell JavaCPP to ignore ANNOY_NODE_ATTRIBUTE
    Something like this should work:
    infoMap.put(new Info("ANNOY_NODE_ATTRIBUTE").cppTypes().annotations())
    Lloyd
    @lloydmeta

    Sadly, I won't be of much help in this discussion as I'm fairly inexperienced at writing custom presets.

    One thing I will say though is that it might be easier to use the Maven flow (as used in the official JavaCPP presets) to write and publish your presets first, and then bring them in as dependencies in a Scala project later.

    Michaël Benesty
    @pommedeterresautee
    @saudet I understand that the error is generated by the compiler but is is linked in some way to the JNI generated code (the C++ code is working when used alone) and I am not sure to understand what is done by the plugin and what is done by JavaCpp directly...
    From what I read, JavaCpp provides much better perf than JNA and if the plugin works as I imagine (write some simple preset, call build and done), this project would deserve a good documentation to be used by as much user as possible. What is really missing is the documentation of the workflow when you are using SBT plugin, right now I am generating the Java file from the Preset and then move it to the correct folder, then recompile. Sure it is not ok, but it seems this bad method should work.
    @lloydmeta I thought the same but wanted to go as far as possible without touching to Maven that I hate a lot :-)
    Samuel Audet
    @saudet
    Are you saying that using the following line you still get the same exact error?
    infoMap.put(new Info("ANNOY_NODE_ATTRIBUTE").cppTypes().annotations())
    Michaël Benesty
    @pommedeterresautee
    not tried yet. I am not home and I have not the code at work
    What I am saying is compiling the main header from the C++ project works but compiling the JNI generated related file raise an error when the compiler work on the main header from the C++ project. I am not C++ expert but the generated file seems to break something. Therefore I was wondering if the generated code was correctly compiled, and this raised the question of how to correctly use the plugin. Hope it is more clear :-)
    Lloyd
    @lloydmeta

    So to be clear, the sbt-javacpp and sbt-javacv plugins are for projects that use JavaCPP and Presets

    Building JavaCPP or writing a JavaCPP preset is a different workflow that requires a bunch of other stuff (see the JavaCPP Preset stuff in the Maven build for details, but it includes for instance writing a build script).

    Michaël Benesty
    @pommedeterresautee
    @saudet the code you provided fixed the compilation issue, thanks.
    Michaël Benesty
    @pommedeterresautee

    I did some test, and it seems most of the function are working, the only thing remaining is this code:

    void getNnsByItem(AnnoyIndexInterface<int,float> *ptr, int item, int n,
                      int search_k, int *result, float *distances) {
      vector<int> resultV;
      vector<float> distancesV;
      ptr->get_nns_by_item(item, n, search_k, &resultV, &distancesV);
      std::copy(resultV.begin(), resultV.end(), result);
      std::copy(distancesV.begin(), distancesV.end(), distances);
    }

    Basically result and distancesare two float[] I send from Java full of 0s. And they are supposed to be rewritten by the CPP part with the generated result. When I call this function it is not rewritten, like nothing happen. Because all the other functions are working I think there is something to change in the preset. The very same function works in JNA (called in the very same way). Have you any idea how I can fix the preset?

    Second question, Annoy is the standard in machine learning to make near neighboor vector search (looking for a similar vector in a very large vector database), I think it would be a great thing to share this preset directly in the repository of JavaCpp, right now I am not using anything other than Build and the preset, is it mandatory to have this build script show in the Wiki? (https://github.com/bytedeco/javacpp-presets/wiki/Create-New-Presets#the-cppbuildsh-file) Is it just about compiling? Is it possible I do it from Java as I am doing right now (with Build)?
    Michaël Benesty
    @pommedeterresautee

    So to be clear, the sbt-javacpp and sbt-javacv plugins are for projects that use JavaCPP and Presets
    Building JavaCPP or writing a JavaCPP preset is a different workflow that requires a bunch of other stuff (see the JavaCPP Preset stuff in the Maven build for details, but it includes for instance writing a build script).

    Yep I think I misunderstood what the plugin is doing. Thanks for highlighting this point

    Samuel Audet
    @saudet
    If you are mapping int* and float* using IntPointer and FloatPointer, you'll need to call get() on them to get the output.
    Sure, contributions are welcome, please send a pull request!
    I'm not sure what you mean by "Build". Are you saying you are building this from an IDE? If so, yes please use a script instead.
    Michaël Benesty
    @pommedeterresautee

    Where should I call get() ?

    Currently the C++ code looks like that (modified since previous message):

      void get_nns_by_item(S item, size_t n, size_t search_k, vector<S>* result, vector<T>* distances) {
        std::cout << "size d av " << distances->size() << "\n"; // av -> avant in French means previous
        const Node* m = _get(item);
        _get_all_nns(m->v, n, search_k, result, distances);
        std::cout << "size d ap " << distances->size() << "\n"; // ap -> après in French means after
      }

    The function is called from Scala through the code generated by the preset.

    val r3b = Array[Int]()
    val distances3 = Array[Float]()
    annoy3.get_nns_by_item(elementToTest, 100, -1, r3b, distances3)

    Parameters result and distances are 2 arrays, that I init empty in Scala.

    When the function is called, it prints in the console:

    size d av 0
    size d ap 100

    So the work is done.

    When I check the content of the arrays in Scala they are both empty, for distances:

    println(distances3.toSeq)

    it prints:

    WrappedArray()
    Regarding the compilation, the function Builder is used like here: https://github.com/bytedeco/sbt-javacpp/blob/master/src/sbt-test/sbt-javacpp/simple/src/test/java/javacpp/VectorTest.java#L16
    I am not using at all the IDE feature for the compilation (just using SBT)
    There are 2 calls to Builder, one applied to the preset and it generates the Java code, and one on the Java code, it generates JNI + compile the C++ code
    Michaël Benesty
    @pommedeterresautee
    To call get(), is there a way to do it with the preset without touching the original C++ code? The idea is to keep the C++ code not modified so the preset can be called on new version of Annoy library (required if the preset is shared in Javacpp).
    Samuel Audet
    @saudet
    You're providing arrays of length 0, we can't change the size of arrays. You're going to need to provide non-zero-length arrays if you're expecting anything in return.
    Michaël Benesty
    @pommedeterresautee

    You're providing arrays of length 0, we can't change the size of arrays. You're going to need to provide non-zero-length arrays if you're expecting anything in return.

    When I did so, the size of the array was the original size + 100 (because I was retrieving 100 items, which doesn't make sense if the size of the array can't change). Moreover, how does it works for get()?

    Samuel Audet
    @saudet
    get() is for when you use Pointer, but you're not using Pointer, so don't worry about it
    Michaël Benesty
    @pommedeterresautee
    vector<S>* result, vector<T>* distances are pointers isn't it ?
    (sorry my CPP is really bad)
    Samuel Audet
    @saudet
    Those are vectors, you'll need to use Pointer if you need them to return the size
    Michaël Benesty
    @pommedeterresautee
    ok, so the solution should be to just init my arrays in Scala with values to reach the correct size, nothing else to do, right?
    If yes I retry tonight...
    Samuel Audet
    @saudet
    If you know the size of arrays you need, yes that would work
    Michaël Benesty
    @pommedeterresautee

    When I init the java Array with 100 values (100 is the size of the result I expect), in CPP, when I print the size of the vector after retrieving the result, it is 200.
    When I keep the java Array empty, in CPP, when I print the size of the vector after retrieving the result, it is 100.

    Finally I made the function work by modifying the original source code:

    void get_nns_by_item(S item, size_t n, size_t search_k, vector<S>* result, vector<T>* distances) {
        vector<S> resultV;
        vector<T> distancesV;
        const Node* m = _get(item);
        _get_all_nns(m->v, n, search_k, &resultV, &distancesV);
        distances->swap(distancesV);
        result->swap(resultV);
      }

    As a reminder original source code is there: https://github.com/spotify/annoy/blob/master/src/annoylib.h#L435

    As you can see, I just copy the retrieved vector in the Java Array.
    All unit tests pass now. However the solution is ugly and we can't share the preset in this state.
    Is there some test I can do to help you understand?
    Can I force in some way Javacpp to override the function with this code? (the function is inside a structure)

    Michaël Benesty
    @pommedeterresautee

    Instead of calling swap(), this seems to work:

    *distances = distancesV;
    *result = resultV;

    I am under the feeling there is something simple to do in the preset.
    Right now it looks like that:

    @Properties(target="org.bytedeco.javacpp.annoy", value={@Platform(include={
            "/mnt/workspace/justice-data/source_code/src/main/cpp/annoyjavacpp.cpp", // very light instance creator
            "/mnt/workspace/justice-data/source_code/src/main/cpp/annoylib.h",
            "/mnt/workspace/justice-data/source_code/src/main/cpp/kissrandom.h"
    },
            link="z@.1")
    })
    public class annoy_preset implements InfoMapper {
        public void map(InfoMap infoMap) {
            infoMap
                    .put(new Info("AnnoyIndexInterface<int,float>").pointerTypes("AnnoyIndexInterface"))
                    .put(new Info("AnnoyIndex<int,float,Euclidean,Kiss64Random>").pointerTypes("AnnoyIndexE").base("AnnoyIndexInterface"))
                    .put(new Info("AnnoyIndex<int,float,Angular,Kiss64Random>").pointerTypes("AnnoyIndexA").base("AnnoyIndexInterface"))
                    .put(new Info("ANNOY_NODE_ATTRIBUTE").cppTypes().annotations())
            ;
        }
    }
    Samuel Audet
    @saudet
    Ok, so it sounds like you need to use Pointer instead of arrays, so try that.
    Michaël Benesty
    @pommedeterresautee
    I have no idea how to express that in the preset? (to be clear I don't really understand what I am doing, is there a way to have the same effect just playing with the preset? Or to override the function somehow and do my stuffed in the overiden version?)
    Annoy is supposed to be used in performant sensitive context, and adding a copy seems stupid and not necessary. So may be there is something I can do in the preset to directly provide somthing which would work without the copy?
    Michaël Benesty
    @pommedeterresautee

    May be interesting, the function which is called inside the one I am working on: https://github.com/spotify/annoy/blob/master/src/annoylib.h#L547

      void _get_all_nns(const T* v, size_t n, size_t search_k, vector<S>* result, vector<T>* distances) {
       ... // no call to result and distances
       size_t m = nns_dist.size();
        size_t p = n < m ? n : m; // Return this many items
        std::partial_sort(nns_dist.begin(), nns_dist.begin() + p, nns_dist.end());
        for (size_t i = 0; i < p; i++) {
          if (distances)
            distances->push_back(D::normalized_distance(nns_dist[i].first));
          result->push_back(nns_dist[i].second);
        }
      }

    If I understand correctly calling push_back explains why when I directly provide a 100 array I finish in CPP with a 200 array, and for some reason, when I get it back in Java I lose the added elements.
    Here size_t n is the number of elements I am expecting.

    Samuel Audet
    @saudet
    If yon want best performance, you'll need to create an instance of the std::vector template. There are many examples of that in the presets
    Michaël Benesty
    @pommedeterresautee

    Right now, for my own project, I have what I need. The issue is more about how to modify preset to share it in JavaCPP-presets.
    For that purpose I need to keep the lib like it is (otherwise it would require to apply the same modification to any update in the future which is not a good solution).
    I have played with the template of std::vector but I am not sure to see how I am supposed to leverage it in Annoy.

    Anyway, I was thinking to all of that, it seems to me the issue I have is only related to the call to push_back() and is not about sending a pointer and references.

    • As said before, when I just call the function with a 100 dimensions Java Array init with -1 for each dimension of the vector for instance, I get a 200 dimensions CPP. The reason of that is because new values are put at the end of the existing vector which is a copy/ref to the Java array. When it goes back to java / scala, it gets back only the 100 first value because it was the initial size of the java Array.
    • the current solution (using another vector then copy the values) works because the new vector is created empty, so push_back()starts at the position 0, when it s finished the copy put the values in the java array starting at position 0.

    Therefore the natural solution would be to inform the preset that the array may change of size. Clearly in Java/Scala, changing the size of an array makes no sense, but to me C++ is like dark magic, so may be there is a way to perform such a thing?
    Another workaround would be to make preset wrap the original function automatically and adding the new vector stuff like I did by modifying the original source code.
    A third solution would be to apply a patch automatically to the original source code of Annoy (the ugliest solution I think).

    What do you think?

    Samuel Audet
    @saudet
    No, no, we just need to create a wrapper for the instance of std::vector. To have a more productive conversation, could you send a pull request with what you have now? It would help
    Michaël Benesty
    @pommedeterresautee
    Yes you are right, I do it tonight when I will be home.
    Michaël Benesty
    @pommedeterresautee
    bytedeco/javacpp-presets#399 I have posted in the text description of the PR my Scala code. If required I can translate the Scala code in Java (just got home late but can do it tomorrow night).
    To use with original Annoy code, will work for most functions but get_nns_by_item and get_nns_by_vector (both have the same issue for the same reason).
    Samuel Audet
    @saudet
    Thanks! Will take a look later
    Hanns Holger Rutz
    @Sciss
    Hi there. Trying to catch up with the tech - what's the way to get live video camera capture going on linux (both i386 and arm would be great)? Is this the fly-capture library? can I use sbt-javacpp to write a scala app that grabs camera images - which would be the dependency I need?
    basically I need to grab frames from a USB web cam and get hold of a pixel matrix
    Samuel Audet
    @saudet
    JavaCV is pretty much it. There's some sample code here: https://github.com/bytedeco/javacv#sample-usage
    We can use sbt with sbt-javacv to use it from Scala, sure.