Skip to content

Use a callable template param in DmpCeff #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
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
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ set(STA_SOURCE
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc
dcalc/DmpDelayCalc.cc
dcalc/FindRoot.cc
dcalc/GraphDelayCalc.cc
dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc
Expand Down
20 changes: 12 additions & 8 deletions dcalc/DmpCeff.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,14 @@ gateModelRd(const LibertyCell *cell,
double c1,
const Pvt *pvt,
bool pocv_enabled);
template <typename Eval>
static void
newtonRaphson(const int max_iter,
double x[],
const int n,
const double x_tol,
// eval(state) is called to fill fvec and fjac.
function<void ()> eval,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the original slow-ness be because this is passed by value instead of const & ? I guess it depends on how much is captured with the call.

Maybe it helps to un-stall this PR if changing the signature to const function<void()> &eval could improve performance and don't require a callable template parameter.

const Eval &eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
Expand Down Expand Up @@ -494,9 +495,9 @@ DmpAlg::findVoCrossing(double vth,
double t_lower,
double t_upper)
{
FindRootFunc vo_func = [&] (double t,
double &y,
double &dy) {
const auto vo_func = [&] (double t,
double &y,
double &dy) {
double vo, vo_dt;
Vo(t, vo, vo_dt);
y = vo - vth;
Expand Down Expand Up @@ -612,9 +613,9 @@ DmpAlg::findVlCrossing(double vth,
double t_lower,
double t_upper)
{
FindRootFunc vl_func = [&] (double t,
double &y,
double &dy) {
const auto vl_func = [&] (double t,
double &y,
double &dy) {
double vl, vl_dt;
Vl(t, vl, vl_dt);
y = vl - vth;
Expand Down Expand Up @@ -1278,19 +1279,22 @@ DmpZeroC2::voCrossingUpperBound()
// x_tol is percentage that all changes in x must be less than (1.0 = 100%).
// Eval(state) is called to fill fvec and fjac (returns false if fails).
// Return error msg on failure.
// Eval should be callable like void(void)
template <typename Eval>
static void
newtonRaphson(const int max_iter,
double x[],
const int size,
const double x_tol,
function<void ()> eval,
const Eval &eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
int *index,
double *p,
double *scale)
{
static_assert(std::is_invocable_v<Eval>, "Must be a callable with no arguments");
for (int k = 0; k < max_iter; k++) {
eval();
for (int i = 0; i < size; i++)
Expand Down
106 changes: 0 additions & 106 deletions dcalc/FindRoot.cc

This file was deleted.

80 changes: 71 additions & 9 deletions dcalc/FindRoot.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,95 @@

#pragma once

#include <functional>
#include <algorithm> // abs

namespace sta {

typedef const std::function<void (double x,
// Return values.
double &y,
double &dy)> FindRootFunc;
using std::abs;

// FindRootFunc should be callable like void(double, double&, double&)
template <typename FindRootFunc>
double
findRoot(FindRootFunc func,
findRoot(const FindRootFunc &func,
double x1,
double x2,
double x_tol,
int max_iter,
// Return value.
bool &fail);
bool &fail)
{
double y1, y2, dy1;
func(x1, y1, dy1);
func(x2, y2, dy1);
return findRoot(func, x1, y1, x2, y2, x_tol, max_iter, fail);
}

// FindRootFunc should be callable like void(double, double&, double&)
template <typename FindRootFunc>
double
findRoot(FindRootFunc func,
findRoot(const FindRootFunc &func,
double x1,
double y1,
double x2,
double y2,
double x_tol,
int max_iter,
// Return value.
bool &fail);
bool &fail)
{
if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0)) {
// Initial bounds do not surround a root.
fail = true;
return 0.0;
}

if (y1 == 0.0) {
fail = false;
return x1;
}

if (y2 == 0.0) {
fail = false;
return x2;
}

if (y1 > 0.0)
// Swap x1/x2 so func(x1) < 0.
std::swap(x1, x2);
double root = (x1 + x2) * 0.5;
double dx_prev = abs(x2 - x1);
double dx = dx_prev;
double y, dy;
func(root, y, dy);
for (int iter = 0; iter < max_iter; iter++) {
// Newton/raphson out of range.
if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0)
// Not decreasing fast enough.
|| (abs(2.0 * y) > abs(dx_prev * dy))) {
// Bisect x1/x2 interval.
dx_prev = dx;
dx = (x2 - x1) * 0.5;
root = x1 + dx;
}
else {
dx_prev = dx;
dx = y / dy;
root -= dx;
}
if (abs(dx) <= x_tol * abs(root)) {
// Converged.
fail = false;
return root;
}

func(root, y, dy);
if (y < 0.0)
x1 = root;
else
x2 = root;
}
fail = true;
return root;
}

} // namespace