Making model accessible with GenericDistribution
This commit is contained in:
parent
626b4f65c3
commit
beda0b61ed
|
@ -26,19 +26,18 @@ let _lastElement = (a: array('a)) =>
|
|||
|
||||
let probabilityBeforeDomainMax = (t: t) => _lastElement(t.distribution.ys);
|
||||
|
||||
let domainMaxX = (t: t) => t.domainMaxX;
|
||||
let domainMaxX = (t: t) => t.domainMaxX /* CdfLibrary.Distribution.findX(yPoint, t.distribution)*/;
|
||||
|
||||
let probabilityDistribution = (t: t) =>
|
||||
t.distribution |> CdfLibrary.Distribution.toPdf;
|
||||
// let probabilityDistribution = (t: t) =>
|
||||
// t.distribution |> CdfLibrary.Distribution.toPdf;
|
||||
|
||||
let probability = (t: t, xPoint: float) =>
|
||||
CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t));
|
||||
// let probability = (t: t, xPoint: float) =>
|
||||
// CdfLibrary.Distribution.findY(xPoint, probabilityDistribution(t));
|
||||
|
||||
let probabilityInverse = (t: t, yPoint: float) =>
|
||||
CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t));
|
||||
// let probabilityInverse = (t: t, yPoint: float) =>
|
||||
// CdfLibrary.Distribution.findX(yPoint, probabilityDistribution(t));
|
||||
|
||||
let cumulativeProbability = (t: t, xPoint: float) =>
|
||||
CdfLibrary.Distribution.findY(xPoint, t.distribution);
|
||||
// let cumulativeProbability = (t: t, xPoint: float) =>
|
||||
// CdfLibrary.Distribution.findY(xPoint, t.distribution);
|
||||
|
||||
let cumulativeProbabilityInverse = (t: t, yPoint: float) =>
|
||||
CdfLibrary.Distribution.findX(yPoint, t.distribution);
|
||||
// let cumulativeProbabilityInverse = (t: t, yPoint: float) =>
|
|
@ -27,21 +27,20 @@ let probabilityBeforeDomainMax = (t: t) =>
|
|||
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf);
|
||||
|
||||
let domainMaxX = (t: t) =>
|
||||
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf);
|
||||
LimitedDomainCdf.probabilityBeforeDomainMax(t.limitedDomainCdf) /* |> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)))*/;
|
||||
|
||||
let probability = (t: t, m: MomentRe.Moment.t) => {
|
||||
RelativeTimePoint.toXValue(t.timeVector, Time(m))
|
||||
|> LimitedDomainCdf.probability(t.limitedDomainCdf);
|
||||
};
|
||||
// let probability = (t: t, m: MomentRe.Moment.t) => {
|
||||
// RelativeTimePoint.toXValue(t.timeVector, Time(m))
|
||||
// |> LimitedDomainCdf.probability(t.limitedDomainCdf);
|
||||
// };
|
||||
|
||||
let probabilityInverse = (t: t, y: float) =>
|
||||
LimitedDomainCdf.probabilityInverse(t.limitedDomainCdf, y)
|
||||
|> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)));
|
||||
// let probabilityInverse = (t: t, y: float) =>
|
||||
// LimitedDomainCdf.probabilityInverse(t.limitedDomainCdf, y)
|
||||
// |> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)));
|
||||
|
||||
let cumulativeProbability = (t: t, m: MomentRe.Moment.t) =>
|
||||
RelativeTimePoint.toXValue(t.timeVector, Time(m))
|
||||
|> LimitedDomainCdf.cumulativeProbability(t.limitedDomainCdf);
|
||||
// let cumulativeProbability = (t: t, m: MomentRe.Moment.t) =>
|
||||
// RelativeTimePoint.toXValue(t.timeVector, Time(m))
|
||||
// |> LimitedDomainCdf.cumulativeProbability(t.limitedDomainCdf);
|
||||
|
||||
let cumulativeProbabilityInverse = (t: t, y: float) =>
|
||||
LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y)
|
||||
|> (r => RelativeTimePoint.toTime(t.timeVector, XValue(r)));
|
||||
// let cumulativeProbabilityInverse = (t: t, y: float) =>
|
||||
// LimitedDomainCdf.cumulativeProbabilityInverse(t.limitedDomainCdf, y)
|
|
@ -48,89 +48,4 @@ type genericDistribution = {
|
|||
probabilityType,
|
||||
domain,
|
||||
unit: distributionUnit,
|
||||
};
|
||||
|
||||
module Shape = {
|
||||
module Continuous = {
|
||||
let fromArrays = (xs, ys): continuousShape => {xs, ys};
|
||||
};
|
||||
|
||||
module Discrete = {
|
||||
let fromArrays = (xs, ys): continuousShape => {xs, ys};
|
||||
};
|
||||
|
||||
module Mixed = {
|
||||
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
|
||||
continuous,
|
||||
discrete,
|
||||
discreteProbabilityMassFraction,
|
||||
};
|
||||
|
||||
module Builder = {
|
||||
type assumption =
|
||||
| ADDS_TO_1
|
||||
| ADDS_TO_CORRECT_PROBABILITY;
|
||||
type assumptions = {
|
||||
continuous: assumption,
|
||||
discrete: assumption,
|
||||
discreteProbabilityMass: option(float),
|
||||
};
|
||||
let build = (~continuous, ~discrete, ~assumptions) =>
|
||||
switch (assumptions) {
|
||||
| {
|
||||
continuous: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discrete: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discreteProbabilityMass: Some(r),
|
||||
} =>
|
||||
// TODO: Fix this, it's wrong :(
|
||||
Some(
|
||||
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
|
||||
)
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: Some(r),
|
||||
} =>
|
||||
Some(
|
||||
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
|
||||
)
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: None,
|
||||
} =>
|
||||
None
|
||||
| {
|
||||
continuous: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: None,
|
||||
} =>
|
||||
None
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discreteProbabilityMass: None,
|
||||
} =>
|
||||
None
|
||||
| _ => None
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
module GenericDistribution = {
|
||||
let make =
|
||||
(
|
||||
~generationSource,
|
||||
~probabilityType=Pdf,
|
||||
~domain=Complete,
|
||||
~unit=Unspecified,
|
||||
(),
|
||||
)
|
||||
: genericDistribution => {
|
||||
generationSource,
|
||||
probabilityType,
|
||||
domain,
|
||||
unit,
|
||||
};
|
||||
};
|
34
src/lib/GenericDistribution.re
Normal file
34
src/lib/GenericDistribution.re
Normal file
|
@ -0,0 +1,34 @@
|
|||
open DistributionTypes;
|
||||
let make =
|
||||
(
|
||||
~generationSource,
|
||||
~probabilityType=Pdf,
|
||||
~domain=Complete,
|
||||
~unit=Unspecified,
|
||||
(),
|
||||
)
|
||||
: genericDistribution => {
|
||||
generationSource,
|
||||
probabilityType,
|
||||
domain,
|
||||
unit,
|
||||
};
|
||||
|
||||
let renderIfNeeded =
|
||||
(~sampleCount=1000, t: genericDistribution): option(genericDistribution) => {
|
||||
switch (t.generationSource) {
|
||||
| GuesstimatorString(s) =>
|
||||
let shape = Guesstimator.stringToMixedShape(~string=s, ~sampleCount, ());
|
||||
shape
|
||||
|> E.O.fmap((shape: DistributionTypes.mixedShape) =>
|
||||
make(
|
||||
~generationSource=Shape(Mixed(shape)),
|
||||
~probabilityType=Cdf,
|
||||
~domain=t.domain,
|
||||
~unit=t.unit,
|
||||
(),
|
||||
)
|
||||
);
|
||||
| Shape(_) => Some(t)
|
||||
};
|
||||
};
|
|
@ -15,6 +15,7 @@ module Value = {
|
|||
| FloatPoint(float)
|
||||
| Probability(float)
|
||||
| Conditional(conditional)
|
||||
| GenericDistribution(DistributionTypes.genericDistribution)
|
||||
| TimeLimitedDomainCdf(TimeLimitedDomainCdf.t)
|
||||
| TimeLimitedDomainCdfLazy(
|
||||
(string => Types.ContinuousDistribution.t) => TimeLimitedDomainCdf.t,
|
||||
|
@ -31,6 +32,7 @@ module Value = {
|
|||
}
|
||||
| SelectSingle(r) => r
|
||||
| FloatCdf(r) => r
|
||||
| GenericDistribution(_) => ""
|
||||
| TimeLimitedDomainCdf(_) => ""
|
||||
| TimeLimitedDomainCdfLazy(_) => ""
|
||||
| Probability(r) => (r *. 100. |> Js.Float.toFixed) ++ "%"
|
||||
|
@ -55,41 +57,29 @@ module Value = {
|
|||
| SelectSingle(r) => r |> ReasonReact.string
|
||||
| ConditionalArray(r) => "Array" |> ReasonReact.string
|
||||
| Conditional(r) => r.name |> ReasonReact.string
|
||||
| TimeLimitedDomainCdfLazy(r) => <div />
|
||||
// let timeLimited = r(CdfLibrary.Distribution.fromString(_, 1000));
|
||||
// let cdf = timeLimited.limitedDomainCdf.distribution;
|
||||
// <>
|
||||
// <Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
|
||||
// <Chart
|
||||
// height=100
|
||||
// data={
|
||||
// cdf
|
||||
// |> CdfLibrary.Distribution.toPdf
|
||||
// |> Types.ContinuousDistribution.toJs
|
||||
// }
|
||||
// />
|
||||
// {FloatCdf.logNormal(50., 20.) |> ReasonReact.string}
|
||||
// </>;
|
||||
| GenericDistribution(r) =>
|
||||
let newDistribution =
|
||||
GenericDistribution.renderIfNeeded(~sampleCount=1000, r);
|
||||
switch (newDistribution) {
|
||||
| Some({generationSource: Shape(Mixed({continuous: n}))}) =>
|
||||
<div>
|
||||
<Chart height=100 data={n |> Shape.Continuous.toJs} />
|
||||
<Chart
|
||||
height=100
|
||||
data={n |> Shape.Continuous.toCdf |> Shape.Continuous.toJs}
|
||||
/>
|
||||
</div>
|
||||
| None => "Something went wrong" |> ReasonReact.string
|
||||
| _ => <div />
|
||||
};
|
||||
| TimeLimitedDomainCdfLazy(_) => <div />
|
||||
| TimeLimitedDomainCdf(r) =>
|
||||
let cdf: Types.ContinuousDistribution.t =
|
||||
r.limitedDomainCdf.distribution;
|
||||
<>
|
||||
<Chart height=100 data={cdf |> Types.ContinuousDistribution.toJs} />
|
||||
</>;
|
||||
| FloatCdf(r) => <div />
|
||||
// let cdf: Types.MixedDistribution.t =
|
||||
// CdfLibrary.Distribution.fromString(r, 2000);
|
||||
// <>
|
||||
// <Chart
|
||||
// height=100
|
||||
// data={
|
||||
// cdf
|
||||
// |> CdfLibrary.Distribution.toPdf
|
||||
// |> Types.ContinuousDistribution.toJs
|
||||
// }
|
||||
// />
|
||||
// {r |> ReasonReact.string}
|
||||
// </>;
|
||||
| FloatCdf(_) => <div />
|
||||
| Probability(r) =>
|
||||
(r *. 100. |> Js.Float.toFixed) ++ "%" |> ReasonReact.string
|
||||
| DateTime(r) => r |> MomentRe.Moment.defaultFormat |> ReasonReact.string
|
||||
|
|
108
src/lib/Shape.re
Normal file
108
src/lib/Shape.re
Normal file
|
@ -0,0 +1,108 @@
|
|||
open DistributionTypes;
|
||||
|
||||
module Continuous = {
|
||||
let fromArrays = (xs, ys): continuousShape => {xs, ys};
|
||||
let toJs = (t: continuousShape) => {
|
||||
{"xs": t.xs, "ys": t.ys};
|
||||
};
|
||||
let toPdf = CdfLibrary.Distribution.toPdf;
|
||||
let toCdf = CdfLibrary.Distribution.toCdf;
|
||||
let findX = CdfLibrary.Distribution.findX;
|
||||
let findY = CdfLibrary.Distribution.findY;
|
||||
};
|
||||
|
||||
module Discrete = {
|
||||
type t = discreteShape;
|
||||
let fromArrays = (xs, ys): discreteShape => {xs, ys};
|
||||
let _lastElement = (a: array('a)) =>
|
||||
switch (Belt.Array.size(a)) {
|
||||
| 0 => None
|
||||
| n => Belt.Array.get(a, n)
|
||||
};
|
||||
|
||||
let derivative = (p: t) => {
|
||||
let (xs, ys) =
|
||||
Belt.Array.zip(p.xs, p.ys)
|
||||
->Belt.Array.reduce([||], (items, (x, y)) =>
|
||||
switch (_lastElement(items)) {
|
||||
| Some((_, yLast)) => [|(x, y -. yLast)|]
|
||||
| None => [|(x, y)|]
|
||||
}
|
||||
)
|
||||
|> Belt.Array.unzip;
|
||||
fromArrays(xs, ys);
|
||||
};
|
||||
|
||||
let integral = (p: t) => {
|
||||
let (xs, ys) =
|
||||
Belt.Array.zip(p.xs, p.ys)
|
||||
->Belt.Array.reduce([||], (items, (x, y)) =>
|
||||
switch (_lastElement(items)) {
|
||||
| Some((_, yLast)) => [|(x, y +. yLast)|]
|
||||
| None => [|(x, y)|]
|
||||
}
|
||||
)
|
||||
|> Belt.Array.unzip;
|
||||
fromArrays(xs, ys);
|
||||
};
|
||||
};
|
||||
|
||||
module Mixed = {
|
||||
let make = (~continuous, ~discrete, ~discreteProbabilityMassFraction) => {
|
||||
continuous,
|
||||
discrete,
|
||||
discreteProbabilityMassFraction,
|
||||
};
|
||||
|
||||
module Builder = {
|
||||
type assumption =
|
||||
| ADDS_TO_1
|
||||
| ADDS_TO_CORRECT_PROBABILITY;
|
||||
type assumptions = {
|
||||
continuous: assumption,
|
||||
discrete: assumption,
|
||||
discreteProbabilityMass: option(float),
|
||||
};
|
||||
let build = (~continuous, ~discrete, ~assumptions) =>
|
||||
switch (assumptions) {
|
||||
| {
|
||||
continuous: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discrete: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discreteProbabilityMass: Some(r),
|
||||
} =>
|
||||
// TODO: Fix this, it's wrong :(
|
||||
Some(
|
||||
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
|
||||
)
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: Some(r),
|
||||
} =>
|
||||
Some(
|
||||
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
|
||||
)
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: None,
|
||||
} =>
|
||||
None
|
||||
| {
|
||||
continuous: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discrete: ADDS_TO_1,
|
||||
discreteProbabilityMass: None,
|
||||
} =>
|
||||
None
|
||||
| {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discreteProbabilityMass: Some(r),
|
||||
} =>
|
||||
Some(
|
||||
make(~continuous, ~discrete, ~discreteProbabilityMassFraction=r),
|
||||
)
|
||||
| _ => None
|
||||
};
|
||||
};
|
||||
};
|
|
@ -113,14 +113,22 @@ module Model = {
|
|||
switch (output) {
|
||||
| DONATIONS
|
||||
| PAYOUTS =>
|
||||
Prop.Value.FloatCdf(
|
||||
let difference =
|
||||
calculateDifference(
|
||||
currentValue(group, output),
|
||||
dateTime,
|
||||
currentDateTime,
|
||||
yearlyMeanGrowthRateIfNotClosed(group),
|
||||
),
|
||||
)
|
||||
);
|
||||
let genericDistribution =
|
||||
GenericDistribution.make(
|
||||
~generationSource=GuesstimatorString(difference),
|
||||
~probabilityType=Cdf,
|
||||
~domain=Complete,
|
||||
~unit=Unspecified,
|
||||
(),
|
||||
);
|
||||
Prop.Value.GenericDistribution(genericDistribution);
|
||||
| CHANCE_OF_EXISTENCE =>
|
||||
let lazyDistribution = r =>
|
||||
TimeLimitedDomainCdf.make(
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
module Model = {
|
||||
let make = (currentDateTime: MomentRe.Moment.t) => {
|
||||
let lazyDistribution = r =>
|
||||
TimeLimitedDomainCdf.make(
|
||||
~timeVector={zero: currentDateTime, unit: `years},
|
||||
~distribution=r(FloatCdf.logNormal(20., 3.)),
|
||||
~probabilityAtMaxX=0.7,
|
||||
~maxX=`x(200.),
|
||||
let genericDistribution =
|
||||
GenericDistribution.make(
|
||||
~generationSource=GuesstimatorString(FloatCdf.logNormal(20., 3.)),
|
||||
~probabilityType=Cdf,
|
||||
~domain=RightLimited({xPoint: 200., excludingProbabilityMass: 0.3}),
|
||||
~unit=Time({zero: currentDateTime, unit: `years}),
|
||||
(),
|
||||
);
|
||||
Prop.Value.TimeLimitedDomainCdfLazy(lazyDistribution);
|
||||
Prop.Value.GenericDistribution(genericDistribution);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -5,15 +5,15 @@ module JS = {
|
|||
ys: array(float),
|
||||
};
|
||||
|
||||
let distToJs = (d: Types.ContinuousDistribution.t) =>
|
||||
let distToJs = (d: DistributionTypes.continuousShape) =>
|
||||
distJs(~xs=d.xs, ~ys=d.ys);
|
||||
|
||||
let jsToDist = (d: distJs): Types.ContinuousDistribution.t => {
|
||||
let jsToDist = (d: distJs): DistributionTypes.continuousShape => {
|
||||
xs: xsGet(d),
|
||||
ys: ysGet(d),
|
||||
};
|
||||
|
||||
let doAsDist = (f, d: Types.ContinuousDistribution.t) =>
|
||||
let doAsDist = (f, d: DistributionTypes.continuousShape) =>
|
||||
d |> distToJs |> f |> jsToDist;
|
||||
|
||||
[@bs.module "./CdfLibrary.js"]
|
||||
|
@ -34,40 +34,6 @@ module JS = {
|
|||
[@bs.module "./CdfLibrary.js"]
|
||||
external differentialEntropy: (int, distJs) => distJs =
|
||||
"differentialEntropy";
|
||||
|
||||
[@bs.module "./CdfLibrary.js"]
|
||||
external scoreNonMarketCdfCdf: (int, distJs, distJs, float) => distJs =
|
||||
"scoreNonMarketCdfCdf";
|
||||
|
||||
module Guesstimator = {
|
||||
[@bs.deriving abstract]
|
||||
type discrete = {
|
||||
xs: array(float),
|
||||
ys: array(float),
|
||||
};
|
||||
|
||||
let jsToDistDiscrete = (d: discrete): Types.DiscreteDistribution.t => {
|
||||
xs: xsGet(d),
|
||||
ys: ysGet(d),
|
||||
};
|
||||
|
||||
[@bs.deriving abstract]
|
||||
type combined = {
|
||||
continuous: distJs,
|
||||
discrete,
|
||||
};
|
||||
|
||||
let toContinous = (r: combined) => continuousGet(r) |> jsToDist;
|
||||
let toDiscrete = (r: combined): Types.DiscreteDistribution.t =>
|
||||
discreteGet(r) |> jsToDistDiscrete;
|
||||
let toMixed = (r: combined): Types.MixedDistribution.t => {
|
||||
discrete: toDiscrete(r),
|
||||
continuous: toContinous(r),
|
||||
};
|
||||
|
||||
[@bs.module "./GuesstimatorLibrary.js"]
|
||||
external toGuesstimator: (string, int) => combined = "run";
|
||||
};
|
||||
};
|
||||
|
||||
module Distribution = {
|
||||
|
@ -75,9 +41,6 @@ module Distribution = {
|
|||
let toCdf = dist => dist |> JS.doAsDist(JS.cdfToPdf);
|
||||
let findX = (y, dist) => dist |> JS.distToJs |> JS.findX(y);
|
||||
let findY = (x, dist) => dist |> JS.distToJs |> JS.findY(x);
|
||||
let fromString = (str: string, sampleCount: int) =>
|
||||
JS.Guesstimator.toGuesstimator(str, sampleCount)
|
||||
|> JS.Guesstimator.toMixed;
|
||||
let integral = dist => dist |> JS.distToJs |> JS.integral;
|
||||
let differentialEntropy = (maxCalculationLength, dist) =>
|
||||
dist
|
||||
|
|
42
src/utility/Guesstimator.re
Normal file
42
src/utility/Guesstimator.re
Normal file
|
@ -0,0 +1,42 @@
|
|||
module Internals = {
|
||||
[@bs.deriving abstract]
|
||||
type discrete = {
|
||||
xs: array(float),
|
||||
ys: array(float),
|
||||
};
|
||||
|
||||
let jsToDistDiscrete = (d: discrete): DistributionTypes.discreteShape => {
|
||||
xs: xsGet(d),
|
||||
ys: ysGet(d),
|
||||
};
|
||||
|
||||
[@bs.deriving abstract]
|
||||
type combined = {
|
||||
continuous: CdfLibrary.JS.distJs,
|
||||
discrete,
|
||||
};
|
||||
|
||||
let toContinous = (r: combined): DistributionTypes.continuousShape =>
|
||||
continuousGet(r) |> CdfLibrary.JS.jsToDist;
|
||||
let toDiscrete = (r: combined): DistributionTypes.discreteShape =>
|
||||
discreteGet(r) |> jsToDistDiscrete;
|
||||
|
||||
[@bs.module "./GuesstimatorLibrary.js"]
|
||||
external toCombinedFormat: (string, int) => combined = "run";
|
||||
|
||||
let toMixedShape = (r: combined): option(DistributionTypes.mixedShape) => {
|
||||
let assumptions: Shape.Mixed.Builder.assumptions = {
|
||||
continuous: ADDS_TO_1,
|
||||
discrete: ADDS_TO_CORRECT_PROBABILITY,
|
||||
discreteProbabilityMass: Some(0.3),
|
||||
};
|
||||
Shape.Mixed.Builder.build(
|
||||
~continuous=toContinous(r),
|
||||
~discrete=toDiscrete(r),
|
||||
~assumptions,
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
let stringToMixedShape = (~string, ~sampleCount=1000, ()) =>
|
||||
Internals.toCombinedFormat(string, sampleCount) |> Internals.toMixedShape;
|
Loading…
Reference in New Issue
Block a user