<commit_before>/**
 * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author <NAME> <<EMAIL>>
 */

import { Box3D } from '../../geometry';
import { Vec3, Mat4, Tensor } from '../../linear-algebra';
import { RuntimeContext } from 'mol-task';
import { PositionData, DensityData } from '../common';
import { OrderedSet } from 'mol-data/int';
import { GaussianDensityProps, getDelta } from '../gaussian-density';

export async function GaussianDensityCPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number,  props: GaussianDensityProps): Promise<DensityData> {
    const { resolution, radiusOffset, smoothness } = props

    const { indices, x, y, z } = position
    const n = OrderedSet.size(indices)
    const radii = new Float32Array(n)

    let maxRadius = 0
    for (let i = 0; i < n; ++i) {
        const r = radius(OrderedSet.getAt(indices, i)) + radiusOffset
        if (maxRadius < r) maxRadius = r
        radii[i] = r

        if (i % 100000 === 0 && ctx.shouldUpdate) {
            await ctx.update({ message: 'calculating max radius', current: i, max: n })
        }
    }

    const pad = maxRadius * 2 + resolution
    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad))
    const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
    const min = expandedBox.min

    const delta = getDelta(Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad)), resolution)
    const dim = Vec3.zero()
    Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
    // console.log('grid dim cpu', dim)

    const space = Tensor.Space(dim, [0, 1, 2], Float32Array)
    const data = space.create()
    const field = Tensor.create(space, data)

    const idData = space.create()
    const idField = Tensor.create(space, idData)

    const densData = space.create()

    const v = Vec3()
    const c = Vec3()

    const alpha = smoothness

    const _r2 = maxRadius * 2
    const _radius2 = Vec3.create(_r2, _r2, _r2)
    Vec3.mul(_radius2, _radius2, delta)
    const updateChunk = Math.ceil(1000000 / (_radius2[0] * _radius2[1] * _radius2[2]))

    const beg = Vec3()
    const end = Vec3()
    const rad2 = Vec3()

    const gridPad = 1 / Math.max(...delta)

    const invDelta = Vec3.inverse(Vec3(), delta)
    const [ invDeltaX, invDeltaY, invDeltaZ ] = invDelta

    let dx: number, dy: number, dz: number
    let dxySq: number
    let dSq: number

    // console.time('gaussian density cpu')
    for (let i = 0; i < n; ++i) {
        const j = OrderedSet.getAt(indices, i)

        Vec3.set(v, x[j], y[j], z[j])
        Vec3.sub(v, v, min)
        const [ vx, vy, vz ] = v

        Vec3.mul(c, v, delta)

        const rad = radii[i]
        const rSq = rad * rad
        const rSqInv = 1 / rSq

        const r2 = radiusOffset + rad * 2 + gridPad
        const r2sq = r2 * r2
        Vec3.set(rad2, r2, r2, r2)
        Vec3.mul(rad2, rad2, delta)

        const [ begX, begY, begZ ] = Vec3.floor(beg, Vec3.sub(beg, c, rad2))
        const [ endX, endY, endZ ] = Vec3.ceil(end, Vec3.add(end, c, rad2))

        for (let xi = begX; xi < endX; ++xi) {
            dx = xi * invDeltaX - vx
            for (let yi = begY; yi < endY; ++yi) {
                dy = yi * invDeltaY - vy
                dxySq = dx * dx + dy * dy
                for (let zi = begZ; zi < endZ; ++zi) {
                    dz = zi * invDeltaZ - vz
                    dSq = dxySq + dz * dz
                    if (dSq <= r2sq) {
                        const dens = Math.exp(-alpha * (dSq * rSqInv))
                        space.add(data, xi, yi, zi, dens)
                        if (dens > space.get(densData, xi, yi, zi)) {
                            space.set(densData, xi, yi, zi, dens)
                            space.set(idData, xi, yi, zi, i)
                        }
                    }
                }
            }
        }

        if (i % updateChunk === 0 && ctx.shouldUpdate) {
            await ctx.update({ message: 'filling density grid', current: i, max: n })
        }
    }
    // console.timeEnd('gaussian density cpu')

    const transform = Mat4.identity()
    Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))
    Mat4.setTranslation(transform, expandedBox.min)

    return { field, idField, transform }
}<commit_msg>optimized gaussian density cpu more<commit_after>/**
 * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author <NAME> <<EMAIL>>
 */

import { Box3D } from '../../geometry';
import { Vec3, Mat4, Tensor } from '../../linear-algebra';
import { RuntimeContext } from 'mol-task';
import { PositionData, DensityData } from '../common';
import { OrderedSet } from 'mol-data/int';
import { GaussianDensityProps, getDelta } from '../gaussian-density';

export async function GaussianDensityCPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number,  props: GaussianDensityProps): Promise<DensityData> {
    const { resolution, radiusOffset, smoothness } = props

    const { indices, x, y, z } = position
    const n = OrderedSet.size(indices)
    const radii = new Float32Array(n)

    let maxRadius = 0
    for (let i = 0; i < n; ++i) {
        const r = radius(OrderedSet.getAt(indices, i)) + radiusOffset
        if (maxRadius < r) maxRadius = r
        radii[i] = r

        if (i % 100000 === 0 && ctx.shouldUpdate) {
            await ctx.update({ message: 'calculating max radius', current: i, max: n })
        }
    }

    const pad = maxRadius * 2 + resolution
    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad))
    const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
    const min = expandedBox.min

    const delta = getDelta(Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad)), resolution)
    const dim = Vec3.zero()
    Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
    // console.log('grid dim cpu', dim)

    const space = Tensor.Space(dim, [0, 1, 2], Float32Array)
    const data = space.create()
    const field = Tensor.create(space, data)

    const idData = space.create()
    const idField = Tensor.create(space, idData)

    const iu = dim[2], iv = dim[1], iuv = iu * iv

    const densData = space.create()

    const v = Vec3()
    const c = Vec3()

    const alpha = smoothness

    const _r2 = maxRadius * 2
    const _radius2 = Vec3.create(_r2, _r2, _r2)
    Vec3.mul(_radius2, _radius2, delta)
    const updateChunk = Math.ceil(1000000 / (_radius2[0] * _radius2[1] * _radius2[2]))

    const beg = Vec3()
    const end = Vec3()
    const rad2 = Vec3()

    const gridPad = 1 / Math.max(...delta)

    const invDelta = Vec3.inverse(Vec3(), delta)
    const [ invDeltaX, invDeltaY, invDeltaZ ] = invDelta

    console.time('gaussian density cpu')
    for (let i = 0; i < n; ++i) {
        const j = OrderedSet.getAt(indices, i)

        Vec3.set(v, x[j], y[j], z[j])
        Vec3.sub(v, v, min)
        const [ vx, vy, vz ] = v

        Vec3.mul(c, v, delta)

        const rad = radii[i]
        const rSq = rad * rad
        const rSqInv = 1 / rSq

        const r2 = radiusOffset + rad * 2 + gridPad
        const r2sq = r2 * r2
        Vec3.set(rad2, r2, r2, r2)
        Vec3.mul(rad2, rad2, delta)

        const [ begX, begY, begZ ] = Vec3.floor(beg, Vec3.sub(beg, c, rad2))
        const [ endX, endY, endZ ] = Vec3.ceil(end, Vec3.add(end, c, rad2))

        for (let xi = begX; xi < endX; ++xi) {
            const dx = xi * invDeltaX - vx
            const xIdx = xi * iuv
            for (let yi = begY; yi < endY; ++yi) {
                const dy = yi * invDeltaY - vy
                const dxySq = dx * dx + dy * dy
                const xyIdx = yi * iu + xIdx
                for (let zi = begZ; zi < endZ; ++zi) {
                    const dz = zi * invDeltaZ - vz
                    const dSq = dxySq + dz * dz
                    if (dSq <= r2sq) {
                        const dens = Math.exp(-alpha * (dSq * rSqInv))
                        const idx = zi + xyIdx
                        data[idx] += dens
                        if (dens > densData[idx]) {
                            densData[idx] = dens
                            idData[idx] = i
                        }
                    }
                }
            }
        }

        if (i % updateChunk === 0 && ctx.shouldUpdate) {
            await ctx.update({ message: 'filling density grid', current: i, max: n })
        }
    }
    console.timeEnd('gaussian density cpu')

    const transform = Mat4.identity()
    Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))
    Mat4.setTranslation(transform, expandedBox.min)

    return { field, idField, transform }
}
{'fraction_non_alphanumeric': 0.13268902785673678, 'fraction_numerical': 0.02274019329164298, 'mean_word_length': 2.05204718945177, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7311740', 'n_tokens_mistral': 3039, 'n_tokens_neox': 2883, 'n_words': 837}