import torch
+
+import torch
-
-
import molgrid
+
+import molgrid
-
-
from openbabel import pybel
+
+from openbabel import pybel
-
-
# create simple molecule
-m = pybel.readstring('smi','C')
+
+# create simple molecule
+m = pybel.readstring('smi','C')
m.addh()
-
-
# atom typing based on atomic number and valence, with a constant radius of 1.5
-def mytyper(atom):
- if hasattr(atom, 'GetValence'):
+
+# atom typing based on atomic number and valence, with a constant radius of 1.5
+def mytyper(atom):
+ if hasattr(atom, 'GetValence'):
return ([atom.GetAtomicNum(),atom.GetValence()], 1.5)
else:
return ([atom.GetAtomicNum(),atom.GetExplicitDegree()], 1.5)
-
-
# create the typer; the explicit names may be omitted, in which case numerical names
+
+# create the typer; the explicit names may be omitted, in which case numerical names
# will be automatically created
-t = molgrid.PythonCallbackVectorTyper(mytyper, 2, ["anum","valence"])
+t = molgrid.PythonCallbackVectorTyper(mytyper, 2, ["anum","valence"])
-
-
# get types for our simple molecule using our typer
+
+# get types for our simple molecule using our typer
types = [t.get_atom_type_vector(a.OBAtom) for a in m.atoms]
-
-
import torch
-import molgrid
-from molgrid.openbabel import pybel as pybel
+
+import torch
+import molgrid
+from molgrid.openbabel import pybel as pybel
-
-
sdf = '''lig.pdb
+
+sdf = '''lig.pdb
28 31 0 0 0 0 0 0 0 0999 V2000
@@ -14067,181 +7896,138 @@
> <minimizedRMSD>
0.64667
-$$$$'''
+$$$$'''
-
-
Create a CoordinateSet from a pybel molecule and use that to grid.
-mol = pybel.readstring('sdf',sdf)
+
+mol = pybel.readstring('sdf',sdf)
c = molgrid.CoordinateSet(mol)
-
-
gmaker = molgrid.GridMaker()
+
+gmaker = molgrid.GridMaker()
dims = gmaker.grid_dimensions(molgrid.defaultGninaLigandTyper.num_types())
gridtensor = torch.zeros(dims,dtype=torch.float32)
-
-
gmaker.forward(c.center(),c,gridtensor)
+
+gmaker.forward(c.center(),c,gridtensor)
-
-
import matplotlib.pyplot as plt
+
+import matplotlib.pyplot as plt
plt.matshow(gridtensor[0,24,:,:])
-
-
<matplotlib.image.AxesImage at 0x7f165b1b2070>
plt.matshow(gridtensor[1,24,:,:])
+
+plt.matshow(gridtensor[1,24,:,:])
-
-
<matplotlib.image.AxesImage at 0x7f165b09f1c0>
import molgrid
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.optim as optim
-from torch.nn import init
-import os
-import matplotlib.pyplot as plt
+
+import molgrid
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.optim as optim
+from torch.nn import init
+import os
+import matplotlib.pyplot as plt
-
-
# set some constants
+
+# set some constants
batch_size = 50
-datadir = os.getcwd() +'/data'
-fname = datadir+"/small.types"
+datadir = os.getcwd() +'/data'
+fname = datadir+"/small.types"
molgrid.set_random_seed(0)
torch.manual_seed(0)
np.random.seed(0)
-
-
# define network architecture
-class Net(nn.Module):
- def __init__(self, dims):
+
+# define network architecture
+class Net(nn.Module):
+ def __init__(self, dims):
super(Net, self).__init__()
self.pool0 = nn.MaxPool3d(2)
self.conv1 = nn.Conv3d(dims[0], 32, kernel_size=3, padding=1)
@@ -14038,7 +7867,7 @@
self.last_layer_size = dims[1]//8 * dims[2]//8 * dims[3]//8 * 128
self.fc1 = nn.Linear(self.last_layer_size, 2)
- def forward(self, x):
+ def forward(self, x):
x = self.pool0(x)
x = F.relu(self.conv1(x))
x = self.pool1(x)
@@ -14049,92 +7878,83 @@
x = self.fc1(x)
return x
-
-
# define weight initialization
-def weights_init(m):
+
+# define weight initialization
+def weights_init(m):
if isinstance(m, nn.Conv3d) or isinstance(m, nn.Linear):
init.xavier_uniform_(m.weight.data)
-
-
# use the libmolgrid ExampleProvider to obtain shuffled, balanced, and stratified batches from a file
-e = molgrid.ExampleProvider(data_root=datadir+"/structs",balanced=True,shuffle=True)
+
+# use the libmolgrid ExampleProvider to obtain shuffled, balanced, and stratified batches from a file
+e = molgrid.ExampleProvider(data_root=datadir+"/structs",balanced=True,shuffle=True)
e.populate(fname)
-
-
# initialize libmolgrid GridMaker
+
+# initialize libmolgrid GridMaker
gmaker = molgrid.GridMaker()
dims = gmaker.grid_dimensions(e.num_types())
tensor_shape = (batch_size,)+dims
-
-
# initialize Net on GPU
-model = Net(dims).to('cuda')
+
+# initialize Net on GPU
+model = Net(dims).to('cuda')
model.apply(weights_init)
-
-
Net( (pool0): MaxPool3d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv1): Conv3d(28, 32, kernel_size=(3, 3, 3), stride=(1, 1, 1), padding=(1, 1, 1)) @@ -14145,51 +7965,49 @@ (fc1): Linear(in_features=27648, out_features=2, bias=True) )
# construct optimizer
+
+# construct optimizer
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
-
-
# construct input tensors
-input_tensor = torch.zeros(tensor_shape, dtype=torch.float32, device='cuda')
+
+# construct input tensors
+input_tensor = torch.zeros(tensor_shape, dtype=torch.float32, device='cuda')
float_labels = torch.zeros(batch_size, dtype=torch.float32)
-
-
# train for 500 iterations
+
+# train for 500 iterations
losses = []
for iteration in range(500):
# load data
@@ -14199,7 +8017,7 @@
# the user may also use libmolgrid Transforms directly in python
gmaker.forward(batch, input_tensor, 0, random_rotation=False)
batch.extract_label(0, float_labels)
- labels = float_labels.long().to('cuda')
+ labels = float_labels.long().to('cuda')
optimizer.zero_grad()
output = model(input_tensor)
@@ -14208,102 +8026,74 @@
optimizer.step()
losses.append(float(loss))
-
-
%matplotlib inline
+
+%matplotlib inline
-
-
plt.plot(losses)
+
+plt.plot(losses)
-
-
[<matplotlib.lines.Line2D at 0x7f1197dbcc88>]
+
+
-
-
import molgrid
-import numpy as np
-import tensorflow as tf
-import tensorflow.keras as keras
-import keras.layers
-import os
-import matplotlib.pyplot as plt
+
+import molgrid
+import numpy as np
+import tensorflow as tf
+import tensorflow.keras as keras
+import keras.layers
+import os
+import matplotlib.pyplot as plt
-
-
Using TensorFlow backend.
molgrid.set_random_seed(0)
+
+molgrid.set_random_seed(0)
np.random.seed(0)
batch_size = 50
-datadir = os.getcwd() +'/../data'
-fname = datadir+"/small.types"
+datadir = os.getcwd() +'/../data'
+fname = datadir+"/small.types"
-
-
def create_model(dims):
- """ Creates a 3D CNN by defining and applying layers simultaneously. """
+
+def create_model(dims):
+ """ Creates a 3D CNN by defining and applying layers simultaneously. """
input_layer = keras.layers.Input(shape=dims)
- pool0 = keras.layers.MaxPooling3D(data_format="channels_first")(input_layer)
- conv1 = keras.layers.Conv3D(filters=32, kernel_size=3, data_format="channels_first", activation="relu")(pool0)
- pool1 = keras.layers.MaxPooling3D(data_format="channels_first")(conv1)
- conv2 = keras.layers.Conv3D(filters=64, kernel_size=3, data_format="channels_first", activation="relu")(pool1)
- pool2 = keras.layers.MaxPooling3D(data_format="channels_first")(conv2)
- conv3 = keras.layers.Conv3D(filters=128, kernel_size=3, data_format="channels_first", activation="relu")(pool2)
+ pool0 = keras.layers.MaxPooling3D(data_format="channels_first")(input_layer)
+ conv1 = keras.layers.Conv3D(filters=32, kernel_size=3, data_format="channels_first", activation="relu")(pool0)
+ pool1 = keras.layers.MaxPooling3D(data_format="channels_first")(conv1)
+ conv2 = keras.layers.Conv3D(filters=64, kernel_size=3, data_format="channels_first", activation="relu")(pool1)
+ pool2 = keras.layers.MaxPooling3D(data_format="channels_first")(conv2)
+ conv3 = keras.layers.Conv3D(filters=128, kernel_size=3, data_format="channels_first", activation="relu")(pool2)
- flatten = keras.layers.Flatten(data_format="channels_first")(conv3)
+ flatten = keras.layers.Flatten(data_format="channels_first")(conv3)
- fc1 = keras.layers.Dense(2,activation='softmax')(flatten)
+ fc1 = keras.layers.Dense(2,activation='softmax')(flatten)
# Define and return model
model = keras.models.Model(inputs=input_layer, outputs=fc1)
- model.compile(optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9), loss="sparse_categorical_crossentropy")
+ model.compile(optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9), loss="sparse_categorical_crossentropy")
return model
-
-
e = molgrid.ExampleProvider(data_root=datadir+"/structs",balanced=True,shuffle=True)
+
+e = molgrid.ExampleProvider(data_root=datadir+"/structs",balanced=True,shuffle=True)
e.populate(fname)
-
-
gmaker = molgrid.GridMaker()
+
+gmaker = molgrid.GridMaker()
dims = gmaker.grid_dimensions(e.num_types())
tensor_shape = (batch_size,)+dims
model = create_model(dims)
-
-
labels = molgrid.MGrid1f(batch_size)
+
+labels = molgrid.MGrid1f(batch_size)
input_tensor = molgrid.MGrid5f(*tensor_shape)
-
-
losses = []
+
+losses = []
# train for 500 iterations
for iteration in range(500):
# load data
@@ -14132,102 +7953,74 @@
loss = model.train_on_batch(input_tensor.tonumpy(), labels.tonumpy())
losses.append(float(loss))
-
-
%matplotlib inline
+
+%matplotlib inline
-
-
plt.plot(losses)
+
+plt.plot(losses)
-
-
[<matplotlib.lines.Line2D at 0x7f28f06bf9e8>]
+
+
-
-
Cartesian Reduction Example¶
Here we show that a simple convolutional neural network (CNN) can learn to convert between a voxelized grid representation of atomic densities to Cartesian coordinats for a toy one-atom system.
+import molgrid
-
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.optim as optim
-import matplotlib.pyplot as plt
-import seaborn as sns
-import os
+
+import molgrid
+
+import numpy as np
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.optim as optim
+import matplotlib.pyplot as plt
+import seaborn as sns
+import os
-
-
n_types = 1
+
+n_types = 1
n_atoms = 1
radii = np.ones((n_types))*2.5 #fixed radius of 2.5A
-
-
We define a CNN with three layers of convolution/max pooling followed by fully connected layers to generate coordinates and types (which are irrelevant to this toy example).
-class CNN(nn.Module):
+
+class CNN(nn.Module):
- def __init__(self, gmaker, n_types, n_latent, type_radii, n_atoms=80):
+ def __init__(self, gmaker, n_types, n_latent, type_radii, n_atoms=80):
super(CNN, self).__init__()
self.n_atoms = n_atoms
@@ -14056,12 +7895,12 @@ Cartesian Reduction Exampleself.c2grid = molgrid.Coords2Grid(gmaker, center=(0,0,0))
- def to(self, device):
+ def to(self, device):
ret = super(CNN, self).to(device)
self.device = device
return ret
- def forward(self, input, temp=0.0):
+ def forward(self, input, temp=0.0):
batch_size = input.shape[0]
@@ -14081,141 +7920,140 @@ Cartesian Reduction Examplereturn coords, types, grid_gen
-
-
An out-of-box loss is necessary to penalize generated coordinates that do not fit within the grid.
-def out_of_box_loss(c, max_val):
- '''hingey loss at box boundaries'''
+
+def out_of_box_loss(c, max_val):
+ '''hingey loss at box boundaries'''
return (0.1*F.relu(abs(c)-max_val)).sum()
-
-
def weight_init(m):
+
+def weight_init(m):
if isinstance(m, nn.Conv3d) or isinstance(m, nn.Linear):
nn.init.xavier_uniform_(m.weight.data)
-
-
gmaker = molgrid.GridMaker(resolution=0.5, dimension=23.5, radius_type_indexed=True)
+
+gmaker = molgrid.GridMaker(resolution=0.5, dimension=23.5, radius_type_indexed=True)
dims = gmaker.grid_dimensions(1)
-grid_true = torch.empty(batch_size, *dims, dtype=torch.float32, device='cuda')
-type_count_true = torch.empty(batch_size, n_types, dtype=torch.float32, device='cuda')
+grid_true = torch.empty(batch_size, *dims, dtype=torch.float32, device='cuda')
+type_count_true = torch.empty(batch_size, n_types, dtype=torch.float32, device='cuda')
-origtypes = torch.ones(batch_size,n_atoms,1,device='cuda')
+origtypes = torch.ones(batch_size,n_atoms,1,device='cuda')
#size radii for batches
-batch_radii = torch.tensor(np.tile(radii, (batch_size, 1)), dtype=torch.float32, device='cuda')
+batch_radii = torch.tensor(np.tile(radii, (batch_size, 1)), dtype=torch.float32, device='cuda')
-
-
#create model
-model = CNN(gmaker, type_radii=batch_radii, n_types=1, n_latent=100, n_atoms=n_atoms).to('cuda')
+
+#create model
+model = CNN(gmaker, type_radii=batch_radii, n_types=1, n_latent=100, n_atoms=n_atoms).to('cuda')
model.apply(weight_init)
optimizer = optim.Adam(model.parameters(), lr=.0005)
-
-
grid_true.shape
+
+grid_true.shape
-
-
torch.Size([10, 1, 48, 48, 48])
We compute starting losses (from random initialization) to get a sense of the magnitude of the loss of a random prediction.
-# compute starting losses for normalization purposes
-origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*10-5
+
+# compute starting losses for normalization purposes
+origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*10-5
with torch.no_grad():
for i in range(batch_size):
@@ -14226,133 +8064,116 @@ Cartesian Reduction Exampleoob_loss = out_of_box_loss(coords, max_val=11.5)
start_type_loss = F.mse_loss(type_count_true, types.sum(dim=1))
-
-
start_type_loss
+
+start_type_loss
-
-
tensor(1., device='cuda:0')+
tensor(1., device='cuda:0')
start_grid_loss
+
+start_grid_loss
-
-
tensor(0.0015, device='cuda:0')+
tensor(0.0015, device='cuda:0')
#setup plotting
-def get_ylim(vals):
+
+#setup plotting
+def get_ylim(vals):
min_val = 0 #min(vals)
max_val = max(vals)
val_range = max_val - min_val
return min_val - 0.1*val_range, max_val + 0.1*val_range
-import seaborn as sns
-sns.set_style('white')
-sns.set_context('notebook')
-sns.set_palette('bright')
-from IPython import display
+import seaborn as sns
+sns.set_style('white')
+sns.set_context('notebook')
+sns.set_palette('bright')
+from IPython import display
grid_losses = []
oob_losses = []
-
-
We train by randomly generating coordinates of atoms, where each x,y,z coordinate ranges from -8 to 8.
-fig = plt.figure(figsize=(10,4))
+
+fig = plt.figure(figsize=(10,4))
ax = plt.gca()
-ax.plot(grid_losses, label='grid loss')
-ax.plot(oob_losses, label='oob loss')
+ax.plot(grid_losses, label='grid loss')
+ax.plot(oob_losses, label='oob loss')
ax.legend(loc=1)
-ax.set_xlabel('iteration')
+ax.set_xlabel('iteration')
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=400, gamma=0.1)
@@ -14361,7 +8182,7 @@ Cartesian Reduction Exampletry:
optimizer.zero_grad()
#sample coordinates from -8 to 8
- origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*16-8
+ origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*16-8
for i in range(batch_size):
gmaker.forward((0,0,0), origcoords[i], origtypes[i], batch_radii[i], grid_true[i])
@@ -14391,178 +8212,151 @@ Cartesian Reduction Exampledisplay.clear_output(wait=True)
except KeyboardInterrupt:
- print('interrupted')
+ print('interrupted')
break
-
-
with torch.no_grad(): #mean squared error on coordinates
+
+with torch.no_grad(): #mean squared error on coordinates
print(F.mse_loss(coords,origcoords))
-
-
tensor(0.0920, device='cuda:0') + ++tensor(0.0920, device='cuda:0')
true = origcoords.detach().cpu().numpy().reshape(10,3)
+
+true = origcoords.detach().cpu().numpy().reshape(10,3)
pred = coords.detach().cpu().numpy().reshape(10,3)
-
-
%matplotlib inline
-from mpl_toolkits.mplot3d import Axes3D
+
+%matplotlib inline
+from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
-ax = fig.add_subplot(111, projection='3d')
-ax.scatter(pred[:,0],pred[:,1],pred[:,2],label='pred')
-ax.scatter(true[:,0],true[:,1],true[:,2],label='true')
+ax = fig.add_subplot(111, projection='3d')
+ax.scatter(pred[:,0],pred[:,1],pred[:,2],label='pred')
+ax.scatter(true[:,0],true[:,1],true[:,2],label='true')
plt.legend();
-
-
Because the atomic gradient is "short sighted" - it can only "see" areas of the grid that overlap the atom, we can train faster by warming up the model with generated coordinates that span a smaller range initially (and are closer to the near-zero coordinates generated from random weights).
-grid_losses = []
+
+grid_losses = []
oob_losses = []
#recreate model
-model = CNN(gmaker, type_radii=batch_radii, n_types=1, n_latent=100, n_atoms=n_atoms).to('cuda')
+model = CNN(gmaker, type_radii=batch_radii, n_types=1, n_latent=100, n_atoms=n_atoms).to('cuda')
model.apply(weight_init)
optimizer = optim.Adam(model.parameters(), lr=.0005)
-
-
#size radii for batches
-batch_radii = torch.tensor(np.tile(radii, (batch_size, 1)), dtype=torch.float32, device='cuda')
+
+#size radii for batches
+batch_radii = torch.tensor(np.tile(radii, (batch_size, 1)), dtype=torch.float32, device='cuda')
fig = plt.figure(figsize=(10,4))
ax = plt.gca()
-ax.plot(grid_losses, label='grid loss')
-ax.plot(oob_losses, label='oob loss')
+ax.plot(grid_losses, label='grid loss')
+ax.plot(oob_losses, label='oob loss')
ax.legend(loc=1)
-ax.set_xlabel('iteration')
+ax.set_xlabel('iteration')
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=400, gamma=0.1)
@@ -14570,7 +8364,7 @@ Cartesian Reduction Examplefor iter in range(100):
try:
optimizer.zero_grad()
- origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*2*maxcoord-maxcoord
+ origcoords = torch.rand(batch_size,n_atoms,3,device='cuda')*2*maxcoord-maxcoord
for i in range(batch_size):
gmaker.forward((0,0,0), origcoords[i], origtypes[i], batch_radii[i], grid_true[i])
@@ -14601,151 +8395,116 @@ Cartesian Reduction Exampledisplay.clear_output(wait=True)
except KeyboardInterrupt:
- print('interrupted')
+ print('interrupted')
break
-
-
with torch.no_grad(): #mean squared error on coordinates
+
+with torch.no_grad(): #mean squared error on coordinates
print(F.mse_loss(coords,origcoords))
-
-
tensor(0.0066, device='cuda:0') + ++tensor(0.0066, device='cuda:0')
true = origcoords.detach().cpu().numpy().reshape(10,3)
+
+true = origcoords.detach().cpu().numpy().reshape(10,3)
pred = coords.detach().cpu().numpy().reshape(10,3)
fig = plt.figure()
-ax = fig.add_subplot(111, projection='3d')
-ax.scatter(pred[:,0],pred[:,1],pred[:,2],label='pred')
-ax.scatter(true[:,0],true[:,1],true[:,2],label='true')
+ax = fig.add_subplot(111, projection='3d')
+ax.scatter(pred[:,0],pred[:,1],pred[:,2],label='pred')
+ax.scatter(true[:,0],true[:,1],true[:,2],label='true')
plt.legend();
-
-
We achieve coordinate accuracy more than an order of magnitude better than the grid resolution (0.5A).
-
+
+
-
-
' + _('Hide Search Matches') + '
') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, + }; - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)), + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); }, - initOnKeyListeners: function() { - $(document).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box, textarea, dropdown or button - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey - && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS + && !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) + return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); } break; - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); } break; } } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } }); - } + }, }; // quick alias for translations -_ = Documentation.gettext; +const _ = Documentation.gettext; -$(document).ready(function() { - Documentation.init(); -}); +_ready(Documentation.init); diff --git a/docs/cpp/_static/documentation_options.js b/docs/cpp/_static/documentation_options.js index 2fa8c97f..7e4c114f 100644 --- a/docs/cpp/_static/documentation_options.js +++ b/docs/cpp/_static/documentation_options.js @@ -1,12 +1,13 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), +const DOCUMENTATION_OPTIONS = { VERSION: '', - LANGUAGE: 'None', + LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', FILE_SUFFIX: '.html', LINK_SUFFIX: '.html', HAS_SOURCE: true, SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, }; \ No newline at end of file diff --git a/docs/cpp/_static/english-stemmer.js b/docs/cpp/_static/english-stemmer.js new file mode 100644 index 00000000..056760ee --- /dev/null +++ b/docs/cpp/_static/english-stemmer.js @@ -0,0 +1,1066 @@ +// Generated from english.sbl by Snowball 3.0.1 - https://snowballstem.org/ + +/**@constructor*/ +var EnglishStemmer = function() { + var base = new BaseStemmer(); + + /** @const */ var a_0 = [ + ["arsen", -1, -1], + ["commun", -1, -1], + ["emerg", -1, -1], + ["gener", -1, -1], + ["later", -1, -1], + ["organ", -1, -1], + ["past", -1, -1], + ["univers", -1, -1] + ]; + + /** @const */ var a_1 = [ + ["'", -1, 1], + ["'s'", 0, 1], + ["'s", -1, 1] + ]; + + /** @const */ var a_2 = [ + ["ied", -1, 2], + ["s", -1, 3], + ["ies", 1, 2], + ["sses", 1, 1], + ["ss", 1, -1], + ["us", 1, -1] + ]; + + /** @const */ var a_3 = [ + ["succ", -1, 1], + ["proc", -1, 1], + ["exc", -1, 1] + ]; + + /** @const */ var a_4 = [ + ["even", -1, 2], + ["cann", -1, 2], + ["inn", -1, 2], + ["earr", -1, 2], + ["herr", -1, 2], + ["out", -1, 2], + ["y", -1, 1] + ]; + + /** @const */ var a_5 = [ + ["", -1, -1], + ["ed", 0, 2], + ["eed", 1, 1], + ["ing", 0, 3], + ["edly", 0, 2], + ["eedly", 4, 1], + ["ingly", 0, 2] + ]; + + /** @const */ var a_6 = [ + ["", -1, 3], + ["bb", 0, 2], + ["dd", 0, 2], + ["ff", 0, 2], + ["gg", 0, 2], + ["bl", 0, 1], + ["mm", 0, 2], + ["nn", 0, 2], + ["pp", 0, 2], + ["rr", 0, 2], + ["at", 0, 1], + ["tt", 0, 2], + ["iz", 0, 1] + ]; + + /** @const */ var a_7 = [ + ["anci", -1, 3], + ["enci", -1, 2], + ["ogi", -1, 14], + ["li", -1, 16], + ["bli", 3, 12], + ["abli", 4, 4], + ["alli", 3, 8], + ["fulli", 3, 9], + ["lessli", 3, 15], + ["ousli", 3, 10], + ["entli", 3, 5], + ["aliti", -1, 8], + ["biliti", -1, 12], + ["iviti", -1, 11], + ["tional", -1, 1], + ["ational", 14, 7], + ["alism", -1, 8], + ["ation", -1, 7], + ["ization", 17, 6], + ["izer", -1, 6], + ["ator", -1, 7], + ["iveness", -1, 11], + ["fulness", -1, 9], + ["ousness", -1, 10], + ["ogist", -1, 13] + ]; + + /** @const */ var a_8 = [ + ["icate", -1, 4], + ["ative", -1, 6], + ["alize", -1, 3], + ["iciti", -1, 4], + ["ical", -1, 4], + ["tional", -1, 1], + ["ational", 5, 2], + ["ful", -1, 5], + ["ness", -1, 5] + ]; + + /** @const */ var a_9 = [ + ["ic", -1, 1], + ["ance", -1, 1], + ["ence", -1, 1], + ["able", -1, 1], + ["ible", -1, 1], + ["ate", -1, 1], + ["ive", -1, 1], + ["ize", -1, 1], + ["iti", -1, 1], + ["al", -1, 1], + ["ism", -1, 1], + ["ion", -1, 2], + ["er", -1, 1], + ["ous", -1, 1], + ["ant", -1, 1], + ["ent", -1, 1], + ["ment", 15, 1], + ["ement", 16, 1] + ]; + + /** @const */ var a_10 = [ + ["e", -1, 1], + ["l", -1, 2] + ]; + + /** @const */ var a_11 = [ + ["andes", -1, -1], + ["atlas", -1, -1], + ["bias", -1, -1], + ["cosmos", -1, -1], + ["early", -1, 5], + ["gently", -1, 3], + ["howe", -1, -1], + ["idly", -1, 2], + ["news", -1, -1], + ["only", -1, 6], + ["singly", -1, 7], + ["skies", -1, 1], + ["sky", -1, -1], + ["ugly", -1, 4] + ]; + + /** @const */ var /** Array-
+
- Languages + ${languages + .map( + (translation) => ` +
- + ${translation.language.code} + + `, + ) + .join("\n")} +
-
+
- Versions + ${config.versions.active + .map( + (version) => ` +
- + ${version.slug} + + `, + ) + .join("\n")} +
-
+
- Downloads + ${Object.entries(config.versions.current.downloads) + .map( + ([name, url]) => ` +
- + ${downloadsNameDisplay[name]} + + `, + ) + .join("\n")} +
-
+
- On Read the Docs +
- + Project Home + +
- + Builds + +
- + Downloads + +
-
+
- Search +
- + + +
+ + Hosted by Read the Docs + +
' + _('Searching') + '
').appendTo(this.out); - this.dots = $('').appendTo(this.title); - this.status = $('').appendTo(this.out); - this.output = $('
' + + '' + + _("Hide Search Matches") + + "
", + ), + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms"); + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) + return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) + return; + if ( + DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + && event.key === "Escape" + ) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/docs/cpp/genindex.html b/docs/cpp/genindex.html index a5fb1ac7..c7d01eb1 100644 --- a/docs/cpp/genindex.html +++ b/docs/cpp/genindex.html @@ -1,19 +1,20 @@ + + - +