Skip to content

Commit

Permalink
Merge pull request #42 from siftech/develop
Browse files Browse the repository at this point in the history
v1.8.0
  • Loading branch information
danbryce authored Jan 29, 2024
2 parents c503c8e + c64f541 commit d909110
Show file tree
Hide file tree
Showing 116 changed files with 19,670 additions and 667 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,7 @@ gmon.out
unsat.core
.gitignore
core.dimacs
notebooks/saved-results/out
**/*.bbl
**/*.blg
**/*.out
450 changes: 292 additions & 158 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Version information."""

# The following line *must* be the last in the module, exactly as formatted:
__version__ = "1.5.2"
__version__ = "1.8.0"
2 changes: 1 addition & 1 deletion auxiliary_packages/funman_demo/src/funman_demo/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Version information."""

# The following line *must* be the last in the module, exactly as formatted:
__version__ = "1.7.0"
__version__ = "1.8.0"
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
ParameterSynthesisScenario,
ParameterSynthesisScenarioResult,
)
from funman.search import ResultCombinedHandler
from funman.utils.handlers import ResultCombinedHandler


from ..plot import plot_parameter_space

Expand Down
102 changes: 102 additions & 0 deletions auxiliary_packages/funman_demo/src/funman_demo/example/pde.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import logging
import os
from typing import List, Optional

import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from IPython.display import HTML
from sklearn import preprocessing

from funman.server.query import FunmanResults


def animate_heat_map(my_df, frames):
fig = plt.figure()

vmin = my_df.min().min()
vmax = my_df.max().max()
# ax = sns.heatmap(data, vmin=0, vmax=1)
# fig, ax = plt.subplots()
# sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest", ax=ax)

def init():
# plt.clf()
fig.clear()
data = my_df.loc[0, :]
ax = sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest")
ax.set_xlabel(data.columns[0][0])
ax.set_ylabel(data.index.name)
ax.set_title(data.columns[0][0])

def animate(i):
# plt.clf()
fig.clear()
data = my_df.loc[i, :]
# ax.set_data(data)
ax = sns.heatmap(data, vmin=vmin, vmax=vmax, cmap="crest")
ax.set_xlabel(data.columns[0][0])
ax.set_ylabel(data.index.name)
ax.set_title(f"{data.columns[0][0]}: time = {i}")

anim = animation.FuncAnimation(
fig,
animate,
interval=1000,
frames=frames,
init_func=init,
)

return anim


def plot_spatial_timeseries(
results: FunmanResults,
variables: Optional[List[str]] = None,
outdir=None,
fps=1,
):
logging.getLogger("matplotlib.animation").setLevel(logging.ERROR)
logging.getLogger("matplotlib.colorbar").setLevel(logging.ERROR)

df = results.dataframe(points=[results.parameter_space.true_points()[-1]])
steps = len(df)
parameters = results.model._parameter_names()
vars = results.model._state_var_names()
to_drop = (
parameters
+ ["id", "label"]
+ [v for v in vars if variables is not None and v not in variables]
)
df = df.drop(columns=to_drop)

# x = df.values #returns a numpy array
# min_max_scaler = preprocessing.MinMaxScaler()
# standard_scaler = preprocessing.StandardScaler()
# x_scaled = min_max_scaler.fit_transform(x)
# # x_scaled = standard_scaler.fit_transform(x)
# df = pd.DataFrame(x_scaled, columns =df.columns)

df.columns = df.columns.str.split("_", expand=True)
df = df.stack([1])
df.index = df.index.set_names(["time"] + [df.columns[0][0]])

anim_h = animate_heat_map(df, steps)
if outdir:
anim_h.save(
os.path.join(outdir, "h.gif"),
writer=animation.PillowWriter(fps=fps),
)
hh = HTML(anim_h.to_jshtml())
dh = df.unstack().diff().fillna(0).stack([1]).rename(columns={"h": "dh"})
anim_dh = animate_heat_map(dh, steps)
if outdir:
anim_dh.save(
os.path.join(outdir, "dh.gif"),
writer=animation.PillowWriter(fps=fps),
)
hdh = HTML(anim_dh.to_jshtml())

return hh, hdh, anim_h, anim_dh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def __init__(
alpha=0.2,
plot_points=False,
parameters=None,
dpi=100,
):
if isinstance(parameter_space, ParameterSpace):
self.ps = parameter_space
Expand Down Expand Up @@ -55,20 +56,30 @@ def __init__(
Line2D([0], [0], color="g", lw=4, alpha=alpha),
Line2D([0], [0], color="r", lw=4, alpha=alpha),
]
self.dpi = dpi

def computeBounds(self, interval: Interval = Interval(lb=-2000, ub=2000)):
box = Box(bounds={p: interval for p in self.parameters})
return box

def initialize_figure(self):
def map_param_idx_to_plot_loc(self, i, j, plot_diagonal):
if plot_diagonal:
return i, j
elif i == 0 or j == self.dim - 1:
return None, None
else:
return i - 1, j

def initialize_figure(self, plot_diagonal):
if self.dim == 0:
return

dim_to_plot = self.dim if plot_diagonal else self.dim - 1
fig, axs = plt.subplots(
self.dim,
self.dim,
dim_to_plot,
dim_to_plot,
squeeze=False,
dpi=600,
dpi=self.dpi,
figsize=(10, 10),
)
self.fig = fig
Expand All @@ -89,43 +100,74 @@ def initialize_figure(self):

self.fig.tight_layout(pad=3.0)
self.data = [[None] * self.dim] * self.dim

for i in range(self.dim):
for j in range(self.dim):
if j > i:
axs[i, j].axis("off")
i_coord, j_coord = self.map_param_idx_to_plot_loc(
i, j, plot_diagonal
)
if i_coord is None or j_coord is None:
continue

if j_coord > i_coord:
axs[i_coord, j_coord].axis("off")
else:
(self.data[i][j],) = self.axs[i, j].plot([], [])
axs[i, j].set_xlabel(f"{self.parameters[i]}")
axs[i, j].set_ylabel(f"{self.parameters[j]}")
(self.data[i][j],) = self.axs[i_coord, j_coord].plot(
[], []
)
axs[i_coord, j_coord].set_xlabel(f"{self.parameters[i]}")
axs[i_coord, j_coord].set_ylabel(f"{self.parameters[j]}")
self.fig.suptitle(self.title)
plt.legend(self.custom_lines, ["true", "false"])

def plot(self, show=False):
self.initialize_figure()
def plot(self, show=False, plot_diagonal=False):
self.initialize_figure(plot_diagonal)
t = "true"
f = "false"
for b in self.ps.false_boxes:
self.plotNDBox(b, self.color_map[f])
self.plotNDBox(b, self.color_map[f], plot_diagonal=plot_diagonal)
for b in self.ps.true_boxes:
self.plotNDBox(b, self.color_map[t])
self.plotNDBox(b, self.color_map[t], plot_diagonal=plot_diagonal)
if self.plot_points:
for p in self.ps.false_points():
self.plot_add_point(p, self.color_map[f], self.shape_map[f])
self.plot_add_point(
p,
self.color_map[f],
self.shape_map[f],
plot_diagonal=plot_diagonal,
)
true_points = self.ps.true_points()
for p in true_points:
self.plot_add_point(p, self.color_map[t], self.shape_map[t])
self.plot_add_point(
p,
self.color_map[t],
self.shape_map[t],
plot_diagonal=plot_diagonal,
)
if show:
plt.show(block=False)

def plot_add_point(self, point: Point, color="r", shape="x", alpha=0.9):
def plot_add_point(
self,
point: Point,
color="r",
shape="x",
alpha=0.9,
plot_diagonal=False,
):
for i in range(self.dim):
for j in range(self.dim):
if i < j:
i_coord, j_coord = self.map_param_idx_to_plot_loc(
i, j, plot_diagonal
)
if i_coord is None or j_coord is None:
continue
if j_coord > i_coord:
continue
yval = (
point.values[self.parameters[j]] if self.dim > 1 else 0.0
)
self.axs[i, j].scatter(
self.axs[i_coord, j_coord].scatter(
point.values[self.parameters[i]],
yval,
color=color,
Expand All @@ -136,17 +178,23 @@ def plot_add_point(self, point: Point, color="r", shape="x", alpha=0.9):
# self.fig.canvas.draw()
# self.fig.canvas.flush_events()

def plotNDBox(self, box, color="g", alpha=0.2):
def plotNDBox(self, box, color="g", alpha=0.2, plot_diagonal=False):
for i in range(self.dim):
for j in range(self.dim):
if i < j:
i_coord, j_coord = self.map_param_idx_to_plot_loc(
i, j, plot_diagonal
)
if i_coord is None or j_coord is None:
continue
if j_coord > i_coord:
continue

x_limits = box.bounds[self.parameters[i]]
y_limits = box.bounds[self.parameters[j]]

if i == j:
# Plot a line segment
self.axs[i, j].plot(
self.axs[i_coord, j_coord].plot(
[x_limits.lb, x_limits.ub],
[x_limits.lb, x_limits.ub],
color=color,
Expand All @@ -162,7 +210,7 @@ def plotNDBox(self, box, color="g", alpha=0.2):
x = np.linspace(
float(x_limits.lb), float(x_limits.ub), 1000
)
self.axs[i, j].fill_between(
self.axs[i_coord, j_coord].fill_between(
x,
y_limits.lb,
y_limits.ub,
Expand Down
37 changes: 36 additions & 1 deletion auxiliary_packages/funman_demo/src/funman_demo/plot.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import json
import logging
from typing import Dict

import matplotlib.pyplot as plt
from IPython.display import clear_output
from matplotlib.lines import Line2D

from funman import Box, Point
from funman import Box, Parameter, Point
from funman.representation.parameter_space import ParameterSpace

l = logging.getLogger(__file__)
Expand Down Expand Up @@ -65,3 +66,37 @@ def plot_cached_search(search_path, alpha: float = 0.2):
ParameterSpace(true_boxes, false_boxes, true_points, false_points),
alpha=alpha,
)


def summarize_results(variables, results, ylabel="Height"):
points = results.points()
boxes = results.parameter_space.boxes()

l.info("*" * 80)
l.info("*" * 80)
l.info("* Analysis Summary ")
l.info("*" * 80)
l.info(
f"{len(points)} Points (+:{len(results.parameter_space.true_points())}, -:{len(results.parameter_space.false_points())}), {len(boxes)} Boxes (+:{len(results.parameter_space.true_boxes)}, -:{len(results.parameter_space.false_boxes)})"
)
if points and len(points) > 0:
point: Point = points[-1]
parameters: Dict[Parameter, float] = results.point_parameters(point)
results.plot(
variables=variables,
label_marker={"true": ",", "false": ","},
xlabel="Time",
ylabel=ylabel,
legend=variables,
label_color={"true": "g", "false": "r"},
)
parameter_values = {p: point.values[p.name] for p in parameters}
l.info(f"Parameters = {parameter_values}")
l.info(parameters)
l.info(results.dataframe([point]))
else:
# if there are no points, then we have a box that we found without needing points
l.info(f"Found box with no points")
box = boxes[0]
l.info(json.dumps(box.explain(), indent=4))
l.info("*" * 80)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Version information."""

# The following line *must* be the last in the module, exactly as formatted:
__version__ = "1.7.0"
__version__ = "1.8.0"
Loading

0 comments on commit d909110

Please sign in to comment.