Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
O
ogs
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Mojtaba Abdolkhani
ogs
Commits
b3298dbf
Commit
b3298dbf
authored
8 years ago
by
Christoph Lehmann
Browse files
Options
Downloads
Patches
Plain Diff
[NL] added named function caller
parent
1cd5e30e
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
NumLib/NamedFunctionCaller.cpp
+300
-0
300 additions, 0 deletions
NumLib/NamedFunctionCaller.cpp
NumLib/NamedFunctionCaller.h
+133
-0
133 additions, 0 deletions
NumLib/NamedFunctionCaller.h
with
433 additions
and
0 deletions
NumLib/NamedFunctionCaller.cpp
0 → 100644
+
300
−
0
View file @
b3298dbf
/**
* \copyright
* Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#include
"NamedFunctionCaller.h"
#include
<algorithm>
#include
<list>
#include
"BaseLib/uniqueInsert.h"
#include
"BaseLib/Error.h"
bool
hasTopologicalOrdering
(
std
::
vector
<
std
::
vector
<
int
>>
const
&
dependencies
)
{
std
::
vector
<
unsigned
>
dep_counts
(
dependencies
.
size
());
// init dependency counts
for
(
std
::
size_t
fct_idx
=
0
;
fct_idx
<
dependencies
.
size
();
++
fct_idx
)
{
for
(
int
dep
:
dependencies
[
fct_idx
])
{
if
(
dep
>=
0
)
++
dep_counts
[
dep
];
}
}
auto
num_dependent
=
dep_counts
.
size
();
std
::
list
<
std
::
size_t
>
q
;
// init work queue
for
(
std
::
size_t
fct_idx
=
0
;
fct_idx
<
dep_counts
.
size
();
++
fct_idx
)
{
if
(
dep_counts
[
fct_idx
]
==
0
)
{
q
.
push_back
(
fct_idx
);
--
num_dependent
;
}
}
while
(
!
q
.
empty
())
{
auto
const
fct_idx
=
q
.
front
();
q
.
pop_front
();
for
(
int
dep
:
dependencies
[
fct_idx
])
{
if
(
dep
<
0
)
continue
;
if
(
--
dep_counts
[
dep
]
==
0
)
{
q
.
push_back
(
dep
);
--
num_dependent
;
}
}
}
return
num_dependent
==
0
;
}
enum
class
TraversePosition
{
StartNode
,
BetweenChildren
,
EndNode
};
template
<
typename
Callback
>
void
traverse
(
std
::
vector
<
std
::
vector
<
int
>>
const
&
map_sink_source
,
int
sink_fct
,
Callback
&&
callback
)
{
assert
(
sink_fct
<
static_cast
<
int
>
(
map_sink_source
.
size
()));
callback
(
sink_fct
,
TraversePosition
::
StartNode
);
if
(
sink_fct
<
0
)
return
;
auto
const
&
si_so
=
map_sink_source
[
sink_fct
];
int
const
num_args
=
si_so
.
size
();
for
(
int
sink_arg
=
0
;
sink_arg
!=
num_args
;
++
sink_arg
)
{
if
(
sink_arg
!=
0
)
callback
(
sink_fct
,
TraversePosition
::
BetweenChildren
);
traverse
(
map_sink_source
,
si_so
[
sink_arg
],
callback
);
}
callback
(
sink_fct
,
TraversePosition
::
EndNode
);
}
namespace
NumLib
{
NamedFunctionCaller
::
NamedFunctionCaller
(
std
::
initializer_list
<
std
::
string
>
unbound_arguments
)
:
_uninitialized
(
-
1
-
unbound_arguments
.
size
())
{
int
idx
=
-
1
;
for
(
auto
arg
:
unbound_arguments
)
{
BaseLib
::
insertIfKeyUniqueElseError
(
_map_name_idx
,
arg
,
idx
,
"The name of the unbound argument is not unique."
);
--
idx
;
}
}
void
NamedFunctionCaller
::
addNamedFunction
(
NamedFunction
&&
fct
)
{
DBUG
(
"Adding named function `%s'"
,
fct
.
getName
().
c_str
());
BaseLib
::
insertIfKeyUniqueElseError
(
_map_name_idx
,
fct
.
getName
(),
_named_functions
.
size
(),
"The name of the function is not unique."
);
_map_sink_source
.
emplace_back
(
fct
.
getArgumentInfo
().
size
(),
_uninitialized
);
_named_functions
.
push_back
(
std
::
move
(
fct
));
}
void
NamedFunctionCaller
::
plug
(
const
std
::
string
&
sink_fct
,
const
std
::
string
&
sink_arg
,
const
std
::
string
&
source
)
{
_deferred_plugs
.
push_back
({
sink_fct
,
sink_arg
,
source
});
}
void
NamedFunctionCaller
::
applyPlugs
()
{
while
(
!
_deferred_plugs
.
empty
())
{
auto
const
&
plug
=
_deferred_plugs
.
back
();
auto
const
&
sink_fct
=
plug
.
sink_fct
;
auto
const
&
sink_arg
=
plug
.
sink_arg
;
auto
const
&
source
=
plug
.
source
;
auto
const
source_it
=
_map_name_idx
.
find
(
source
);
if
(
source_it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"A function with the name `%s' has not been found."
,
source
.
c_str
());
}
auto
const
source_idx
=
source_it
->
second
;
auto
const
sink_it
=
_map_name_idx
.
find
(
sink_fct
);
if
(
sink_it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"A function with the name `%s' has not been found."
,
sink_fct
.
c_str
());
}
auto
const
sink_fct_idx
=
sink_it
->
second
;
auto
const
&
sink_args
=
_named_functions
[
sink_it
->
second
].
getArgumentInfo
();
auto
const
sink_arg_it
=
std
::
find
(
sink_args
.
begin
(),
sink_args
.
end
(),
sink_arg
);
if
(
sink_arg_it
==
sink_args
.
end
())
{
OGS_FATAL
(
"An argument with the name `%s' has not been found for the "
"function `%s'."
,
sink_arg
.
c_str
(),
sink_fct
.
c_str
());
}
std
::
size_t
sink_arg_idx
=
std
::
distance
(
sink_args
.
begin
(),
sink_arg_it
);
auto
&
sis_sos
=
_map_sink_source
[
sink_fct_idx
];
if
(
sis_sos
[
sink_arg_idx
]
!=
_uninitialized
)
{
OGS_FATAL
(
"A dependency for `%s'.`%s' has already been introduced."
,
sink_fct
.
c_str
(),
sink_arg
.
c_str
());
}
sis_sos
[
sink_arg_idx
]
=
source_idx
;
if
(
!
hasTopologicalOrdering
(
_map_sink_source
))
{
OGS_FATAL
(
"The call graph being plugged together must be an acyclic "
"graph. The added dependency for `%s'.`%s' introduces a cycle "
"into the graph."
,
sink_fct
.
c_str
(),
sink_arg
.
c_str
());
}
_deferred_plugs
.
pop_back
();
}
}
double
NamedFunctionCaller
::
call
(
const
std
::
string
&
function_name
,
const
std
::
vector
<
double
>&
unbound_arguments
)
const
{
assert
(
unbound_arguments
.
size
()
==
getNumberOfUnboundArguments
());
auto
it
=
_map_name_idx
.
find
(
function_name
);
if
(
it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"A function with the name `%s' has not been found."
,
function_name
.
c_str
());
}
return
call
(
it
->
second
,
unbound_arguments
);
}
double
NamedFunctionCaller
::
call
(
std
::
size_t
function_idx
,
const
std
::
vector
<
double
>&
unbound_arguments
)
const
{
assert
(
_deferred_plugs
.
empty
()
&&
"You must call applyPlugs() before this method!"
);
DBUG
(
"Preparing call of fct #%lu %s()"
,
function_idx
,
_named_functions
[
function_idx
].
getName
().
c_str
());
auto
const
&
sis_sos
=
_map_sink_source
[
function_idx
];
assert
(
sis_sos
.
size
()
==
_named_functions
[
function_idx
].
getArgumentInfo
().
size
());
std
::
vector
<
double
>
fct_args
(
sis_sos
.
size
());
for
(
std
::
size_t
sink
=
0
;
sink
<
sis_sos
.
size
();
++
sink
)
{
auto
const
source
=
sis_sos
[
sink
];
if
(
source
>=
0
)
{
fct_args
[
sink
]
=
call
(
source
,
unbound_arguments
);
DBUG
(
"setting %luth argument to %g"
,
sink
,
fct_args
[
sink
]);
}
else
{
assert
(
source
!=
_uninitialized
);
fct_args
[
sink
]
=
unbound_arguments
[
-
source
-
1
];
DBUG
(
"setting %luth argument to %g"
,
sink
,
fct_args
[
sink
]);
}
}
DBUG
(
"Finished preparing call of fct #%lu %s()"
,
function_idx
,
_named_functions
[
function_idx
].
getName
().
c_str
());
return
_named_functions
[
function_idx
].
call
(
fct_args
);
}
std
::
string
NamedFunctionCaller
::
getCallExpression
(
std
::
string
const
&
function_name
)
const
{
auto
const
fct_it
=
_map_name_idx
.
find
(
function_name
);
if
(
fct_it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"A function with the name `%s' has not been found."
,
function_name
.
c_str
());
}
std
::
string
expr
;
auto
callback
=
[
&
](
int
fct_idx
,
TraversePosition
pos
)
{
switch
(
pos
)
{
case
TraversePosition
::
StartNode
:
{
if
(
fct_idx
<
0
)
{
auto
it
=
std
::
find_if
(
_map_name_idx
.
begin
(),
_map_name_idx
.
end
(),
[
fct_idx
](
std
::
pair
<
std
::
string
,
int
>
const
&
e
)
{
return
e
.
second
==
fct_idx
;
});
if
(
it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"The function index %i has not been found."
,
fct_idx
);
}
expr
+=
it
->
first
;
}
else
{
expr
+=
_named_functions
[
fct_idx
].
getName
()
+
"("
;
}
break
;
}
case
TraversePosition
::
BetweenChildren
:
expr
+=
", "
;
break
;
case
TraversePosition
::
EndNode
:
expr
+=
")"
;
}
};
traverse
(
_map_sink_source
,
fct_it
->
second
,
callback
);
DBUG
(
"expression: %s"
,
expr
.
c_str
());
return
expr
;
}
SpecialFunctionCaller
NamedFunctionCaller
::
getSpecialFunction
(
const
std
::
string
&
function_name
)
{
auto
const
fct_it
=
_map_name_idx
.
find
(
function_name
);
if
(
fct_it
==
_map_name_idx
.
end
())
{
OGS_FATAL
(
"A function with the name `%s' has not been found."
,
function_name
.
c_str
());
}
return
SpecialFunctionCaller
(
fct_it
->
second
,
*
this
);
}
std
::
size_t
NamedFunctionCaller
::
getNumberOfUnboundArguments
()
const
{
return
-
_uninitialized
-
1
;
}
SpecialFunctionCaller
::
SpecialFunctionCaller
(
const
std
::
size_t
function_idx
,
const
NamedFunctionCaller
&
caller
)
:
_function_idx
(
function_idx
),
_caller
(
caller
)
{
}
double
SpecialFunctionCaller
::
call
(
const
std
::
vector
<
double
>&
unbound_arguments
)
const
{
return
_caller
.
call
(
_function_idx
,
unbound_arguments
);
}
std
::
size_t
SpecialFunctionCaller
::
getNumberOfUnboundArguments
()
const
{
return
_caller
.
getNumberOfUnboundArguments
();
}
}
// namespace NumLib
This diff is collapsed.
Click to expand it.
NumLib/NamedFunctionCaller.h
0 → 100644
+
133
−
0
View file @
b3298dbf
/**
* \copyright
* Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#ifndef NUMLIB_NAMEDFUNCTIONCALLER_H
#define NUMLIB_NAMEDFUNCTIONCALLER_H
#include
<map>
#include
<vector>
#include
"NamedFunction.h"
namespace
NumLib
{
class
SpecialFunctionCaller
;
//! Builds expression trees of named functions dynamically at runtime.
class
NamedFunctionCaller
final
{
public:
//! Constructs an instance whose unbound arguments have the given names.
explicit
NamedFunctionCaller
(
std
::
initializer_list
<
std
::
string
>
unbound_arguments
);
//! Adds the given named function
void
addNamedFunction
(
NamedFunction
&&
fct
);
std
::
vector
<
NamedFunction
>
const
&
getNamedFunctions
()
const
{
return
_named_functions
;
}
//! Declares that the argument with name \c sink_arg of the function \c
//! sink_fct is being computed by the function \c source.
//!
//! The functions involved need not already be known to the
//! NamedFunctionCaller.
void
plug
(
std
::
string
const
&
sink_fct
,
std
::
string
const
&
sink_arg
,
std
::
string
const
&
source
);
//! Actually plug all the plugs previously declared.
//!
//! \pre All functions involved must have been added.
void
applyPlugs
();
//! Calls the function with the given name with the given unbound arguments.
//!
//! \pre applyPlugs() must have been called before.
double
call
(
std
::
string
const
&
function_name
,
std
::
vector
<
double
>
const
&
unbound_arguments
)
const
;
//! Creates a function caller that is able to call the function with the
//! given name.
SpecialFunctionCaller
getSpecialFunction
(
std
::
string
const
&
function_name
);
//! Returns a string representing the expression graph of the given
//! function.
//!
//! \pre applyPlugs() must have been called before.
std
::
string
getCallExpression
(
std
::
string
const
&
function_name
)
const
;
//! Returns the number of unbound arguments.
std
::
size_t
getNumberOfUnboundArguments
()
const
;
private
:
//! Calls the function with the given index with the given unbound
//! arguments.
double
call
(
std
::
size_t
function_idx
,
std
::
vector
<
double
>
const
&
unbound_arguments
)
const
;
//! Maps function names to indices.
//! Negative indices refer to unbound arguments.
std
::
map
<
std
::
string
,
int
>
_map_name_idx
;
//! Contains all named functions.
std
::
vector
<
NamedFunction
>
_named_functions
;
//! The expression graph.
//! Contains for each named function (outer vector) a vector which maps each
//! function argument to the source function index that computes this
//! argument.
std
::
vector
<
std
::
vector
<
int
>>
_map_sink_source
;
//! Magic number used to mark function arguments in \c _map_sink_source
//! whose source functions have not yet been set up.
const
int
_uninitialized
;
struct
SinkSource
{
std
::
string
const
sink_fct
;
std
::
string
const
sink_arg
;
std
::
string
const
source
;
};
//! Saves plugs declared by plug().
std
::
vector
<
SinkSource
>
_deferred_plugs
;
friend
class
SpecialFunctionCaller
;
};
//! A function caller that can call one specific function.
//!
//! \todo Use this class to provide some optimizations of the expression
//! evaluation.
class
SpecialFunctionCaller
final
{
public:
//! Constructs a new instance.
SpecialFunctionCaller
(
std
::
size_t
const
function_idx
,
NamedFunctionCaller
const
&
caller
);
//! Call the function set up with the given unbound arguments.
double
call
(
std
::
vector
<
double
>
const
&
unbound_arguments
)
const
;
//! Returns the number of unbound arguments.
std
::
size_t
getNumberOfUnboundArguments
()
const
;
private:
//! Index of the referenced function.
std
::
size_t
const
_function_idx
;
//! The named function caller used for the evaluation.
NamedFunctionCaller
const
&
_caller
;
};
}
// namespace NumLib
#endif // NUMLIB_NAMEDFUNCTIONCALLER_H
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment