Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

WIP: Alternate model management system. #2875

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ subdirs(
ml
toolkits
visualization
model_server)
model_server
model_server_v2)


if(TC_BUILD_PYTHON)
Expand Down
8 changes: 7 additions & 1 deletion src/model_server/lib/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <core/data/flexible_type/flexible_type.hpp>
#include <core/storage/sframe_data/dataframe.hpp>
#include <core/storage/serialization/serialization_includes.hpp>
#include <model_server/lib/variant.hpp>

namespace turi {
class model_base;
Expand Down Expand Up @@ -308,6 +307,13 @@ template <typename T>
inline variant_type to_variant(const T& f) {
return variant_converter<typename std::decay<T>::type>().set(f);
}

/** Overload for the case when we're trying to wrap a void return
* type in a template.
*/
inline variant_type to_variant() {
return variant_type();
}
} // namespace turi

namespace turi {
Expand Down
17 changes: 17 additions & 0 deletions src/model_server_v2/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
make_library( model_server_v2
SOURCES
model_server.cpp
model_base.cpp
REQUIRES
unity_shared)


make_executable(demo
SOURCES demo.cpp
REQUIRES model_server_v2 unity_shared)






106 changes: 106 additions & 0 deletions src/model_server_v2/demo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include <string>
#include <turi_common.h>
#include <model_server_v2/model_base.hpp>
#include <model_server_v2/registration.hpp>

using namespace turi;
using namespace turi::v2;

/** Demo model.
*
*/
class demo_model : public turi::v2::model_base {

public:

/** The name of the model.
*
*/
const char* name() const { return "demo_model"; }

/** Sets up the options and the registration.
*
* The registration is done in the constructor, without the use of macros.
*/
demo_model() {
register_method("add", &demo_model::add, "x", "y");
register_method("concat_strings", &demo_model::append_strings, "s1", "s2");

// Defaults are specified inline
register_method("increment", &demo_model::increment, "x", Parameter("delta", 1));
}

/** Add two numbers.
*
* Const is fine.
*/
size_t add(size_t x, size_t y) const {
return x + y;
}

/** Append two strings with a +
*/
std::string append_strings(const std::string& s1, const std::string& s2) const
{
return s1 + "+" + s2;
}

/** Incerment a value.
*/
size_t increment(size_t x, size_t delta) const {
return x + delta;
}

};

/** Registration for a model is just a single macro in the header.
*
* This automatically loads and registers the model when the library is loaded.
* This registration is trivially cheap.
*/
REGISTER_MODEL(demo_model);


void hello_world(const std::string& greeting) {
std::cout << "Hello, world!! " << greeting << std::endl;
}

/** Registration for a function is just a single macro in a source file or header.
*
* This automatically loads and registers the function when the library is loaded.
*/
REGISTER_FUNCTION(hello_world, "greeting");



int main(int argc, char** argv) {


auto dm = model_server().create_model("demo_model");

std::string name = variant_get_value<std::string>(dm->call_method("name"));

std::cout << "Demoing model = " << name << std::endl;

size_t result = variant_get_value<size_t>(dm->call_method("add", 5, 9));

std::cout << "5 + 9 = " << result << std::endl;

std::string s_res = variant_get_value<std::string>(dm->call_method("concat_strings", "A", "B"));

std::cout << "Concat A, +, B: " << s_res << std::endl;

// Delta default is 1
size_t inc_value = variant_get_value<size_t>(dm->call_method("increment", 5));

std::cout << "Incremented 5: " << inc_value << std::endl;


// Call the registered function.
std::cout << "Calling hello_world." << std::endl;
model_server().call_function("hello_world", "This works!");


return 0;

}
113 changes: 113 additions & 0 deletions src/model_server_v2/method_parameters.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* Copyright © 2019 Apple Inc. All rights reserved.
*
* Use of this source code is governed by a BSD-3-clause license that can
* be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
*/
#ifndef TURI_METHOD_PARAMETERS_HPP_
#define TURI_METHOD_PARAMETERS_HPP_

#include <turi_common.h>
#include <model_server/lib/variant.hpp>
#include <string>
#include <array>

namespace turi {
namespace v2 {


/** Struct to hold information about the user specified parameter of a method.
*
* Includes information about a possible default value.
*/
struct Parameter {

Parameter() {}

// Allow implicit cast from string here..
Parameter(const std::string& n) : name(n) {}
Parameter(std::string&& n) : name(std::move(n)) {}

// Specify parameter with a default value
Parameter(const std::string& n, const variant_type& v)
: name(n), has_default(true), default_value(v)
{}

Parameter(std::string&& n, variant_type&& v)
: name(std::move(n)), has_default(true), default_value(std::move(v))
{}


// TODO: expand this out into a proper container class.


// Name
std::string name;

// Optional default value
bool has_default = false;
variant_type default_value;
};



template <typename... FuncParams>
void validate_parameter_list(const std::vector<Parameter>& params) {

// Validates that the parameter list works with the given types of
// the function.
if(sizeof...(FuncParams) != params.size()) {
throw std::invalid_argument("Mismatch in number of specified parameters.");
}

// TODO: validate uniqueness of names.
// TODO: validate defaults can be cast to proper types.
}


////////////////////////////////////////////////////////////////////////////////

// How the arguments are bundled up and packaged.
struct argument_pack {
std::vector<variant_type> ordered_arguments;
variant_map_type named_arguments;
};

/** Method for resolving incoming arguments to a method.
*
*/
template <int n>
void resolve_method_arguments(std::array<const variant_type*, n>& arg_v,
const std::vector<Parameter>& parameter_list,
const argument_pack& args) {

size_t n_ordered = args.ordered_arguments.size();
for(size_t i = 0; i < n_ordered; ++i) {
arg_v[i] = &args.ordered_arguments[i];
}

// TODO: check if more ordered arguments given than are
// possible here.
size_t used_counter = n_ordered;
for(size_t i = n_ordered; i < n; ++i) {
auto it = args.named_arguments.find(parameter_list[i].name);
if(it == args.named_arguments.end()) {
if(parameter_list[i].has_default) {
arg_v[i] = &(parameter_list[i].default_value);
} else {
// TODO: intelligent error message.
throw std::string("Missing argument.");
}
} else {
arg_v[i] = &(it->second);
++used_counter;
}
}

// TODO: check that all the arguments have been used up. If not,
// generate a good error message.
}

}
}

#endif
Loading