Using binomal distribution with Spark to calculate an expected value and a variance ("number of times getting a six when throwing a dice three times") - apache-spark

I'm training myself to resolve classical statistics exercices with Spark and it's MLib module when needed, in order to face any situation later.
Spark is dedicated to calculation on matrices, but let's say that I have a side calculation to do in my program, at a time, and that I would like to resolve it with Spark, without adding others APIs.
The calculation is simple : learn the expected value and the variance
of having a six on a dice, when you throw it three times.
Currently, I resolve it by the help of the Apache maths API and a bit of Spark :
/** Among imports : */
import org.apache.commons.math3.distribution.*;
/**
* E8.5 : On lance trois dés. Probabilité d'un six obtenu ?
* Suit une loi binomiale B(3, 1/6)
* Par calcul : F(0) = 125/216, F(1) = 125/216 + 75/216, F(2) = (125 + 75 + 15)/216,
* F(3) = (125 + 75 + 15 + 1)/216 = 1
*/
#Test
#DisplayName("On lance trois dés. Probabilité d'un six obtenu ?. Caractéristiques de la loi B(3, 1/6)")
public void troisDésDonnentUnSix() {
int n = 3; // Nombre de lancés de dés.
double v[] = {0, 1, 2, 3}; // Valeurs possibles de la variable aléatoire.
double f[] = new double[n+1]; // Fréquences cumulées.
double p[] = new double[n+1]; // Probabilités.
// Calculer les probabilités et les fréquences.
BinomialDistribution loiBinomale = new BinomialDistribution(n, 1.0/6.0);
for(int i=0; i <= n; i++) {
p[i] = loiBinomale.probability(i);
f[i] = loiBinomale.cumulativeProbability(i);
}
LOGGER.info("P(x) = {}", p);
LOGGER.info("F(x) = {}", f);
Dataset<Row> ds = fromDouble(v, p);
LOGGER.info("E(X) = {}, V(X) = {}", esperance(ds), variance(ds));
}
where fromDouble(v, p) method creates a Dataset from a list of random variable values (column x) and their associated frequencies (column Px) :
/**
* Renvoyer un Dataset depuis une série de valeurs entières à probabilités.
* #param valeurs Valeurs.
* #param probabilites Probabilités.
* #return Dataset avec une colonne x, entière, contenant les valeurs<br>
* et une colonne Px, décimale, contenant les probabilités.
*/
protected Dataset<Row> fromDouble(double[] valeurs, double[] probabilites) {
StructType schema = new StructType()
.add("x", DoubleType, false)
.add("Px", DoubleType, false);
List<Row> rows = new ArrayList<>();
for(int index=0; index < valeurs.length; index ++) {
rows.add(RowFactory.create(valeurs[index], probabilites[index]));
}
return this.session.createDataFrame(rows, schema);
}
And esperance (= expected value) and variance methods called are doing these calculations :
/**
* Calculer l'espérance sur un Dataset avec valeurs et probabilités.
* #param ds Dataset avec colonnes : <br>
* x : valeur<br>
* Px : fréquence<br>
* #return espérance.
*/
protected double esperance(Dataset<Row> ds) {
return ds.agg(sum(col("x").multiply(col("Px")))).first().getDouble(0);
}
/**
* Calculer la variance sur un Dataset avec valeurs et probabilités.
* #param ds Dataset avec colonnes : <br>
* x : valeur<br>
* Px : fréquence<br>
* #return espérance.
*/
protected double variance(Dataset<Row> ds) {
Column variation = col("x").minus(esperance(ds));
Column variationCarre = variation.multiply(variation);
Column termeCalculVariance = col("Px").multiply(variationCarre);
return ds.agg(sum(termeCalculVariance)).first().getDouble(0);
}
LOGGER output :
P(x) = [0.5787037037037037, 0.34722222222222215, 0.06944444444444445, 0.0046296296296296285]
F(x) = [0.5787037037037035, 0.9259259259259259, 0.9953703703703703, 1.0]
E(X) = 0.49999999999999994, V(X) = 0.41666666666666663
It works (? I have caculatd by hand "E(X) = 53/108", and it finds 54/108 = 0.5..., I might be wrong), but it's not perfect.
Is there a more elegant way to solve this problem using Spark (and Spark-MLib, if needed) ?

Related

hi all . i am trying to run the bym2 model . at this stage, i have a problem.are you help me?

library(“rstan”)
library(“rstudioapi”)
library(“parallel”)
library(“brms”)
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectgores())
library(pkgbuild) # load packAge
find_rtools() # should be TRUE, assuming you have Rtools 3.5
#fit model icar.stan to NYC census tracts neighborhood map
install.packages(‘tidyverse’, dependencies = TRUE)
install.packages(‘rstanarm’, dependencies = TRUE)
library(rstan);
library(tidyverse)
library(rstanarm)
"data {
int<lower=0> N;
int<lower=0> N_edges;
int<lower=1, upper=N> node1[N_edges]; // node1[i] adjacent to node2[i]
int<lower=1, upper=N> node2[N_edges]; // and node1[i] < node2[i]
int<lower=0> y[N]; // count outcomes
vector<lower=0>[N] E; // exposure
int<lower=1> K; // num covariates
matrix[N, K] x; // design matrix
real<lower=0> scaling_factor; // scales the variance of the spatial effects
}
transformed data {
vector[N] log_E = log(E);
}
parameters {
real beta0; // intercept
vector[K] betas; // covariates
real<lower=0> sigma; // overall standard deviation
real<lower=0, upper=1> rho; // proportion unstructured vs. spatially structured variance
vector[N] theta; // heterogeneous effects
vector[N] phi; // spatial effects
}
transformed parameters {
vector[N] convolved_re;
// variance of each component should be approximately equal to 1
convolved_re = sqrt(1 - rho) * theta + sqrt(rho / scaling_factor) * phi;
}
model {
y ~ poisson_log(log_E + beta0 + x * betas + convolved_re * sigma); // co-variates
// This is the prior for phi! (up to proportionality)
target += -0.5 * dot_self(phi[node1] - phi[node2]);
beta0 ~ normal(0.0, 1.0);
betas ~ normal(0.0, 1.0);
theta ~ normal(0.0, 1.0);
sigma ~ normal(0, 1.0);
rho ~ beta(0.5, 0.5);
// soft sum-to-zero constraint on phi)
sum(phi) ~ normal(0, 0.001 * N); // equivalent to mean(phi) ~ normal(0,0.001)
}
generated quantities {
real logit_rho = log(rho / (1.0 - rho));
vector[N] eta = log_E + beta0 + x * betas + convolved_re * sigma; // co-variates
vector[N] mu = exp(eta);
}"
options(mc.cores = parallel::detectCores())
library(INLA)
source(“mungecardata4stan.R”)
source(“iran_data.R”)
y = data$y;
E = data$E;
K = 1;
x = 0.1 * data$x;
nbs = mungeCARdata4stan(data$adj, data$num);
N = nbs$N;
node1 = nbs$node1;
node2 = nbs$node2;
N_edges = nbs$N_edges;
adj.matrix = sparseMatrix(i=nbs$node1,j=nbs$node2,x=1,symmetric=TRUE)
Q= Diagonal(nbs$N, rowSums(adj.matrix)) - adj.matrix
Q_pert = Q + Diagonal(nbs$N) * max(diag(Q)) * sqrt(.Machine$double.eps)
Q_inv = inla.qinv(Q_pert, constr=list(A = matrix(1,1,nbs$N),e=0))
scaling_factor = exp(mean(log(diag(Q_inv))))
scot_stanfit = stan(“bym2_predictor_plus_offset.stan”, data=list(N,N_edges,node1,node2,y,x,E,scaling_factor), warmup=5000, iter=6000);
Error in new_CppObject_xp(fields$.module, fields$.pointer, …) : **
** Exception: variable does not exist; processing stage=data initialization; variable name=N; base type=int (in ‘string’, line 3, column 2 to column 17)
In addition: Warning message:
In readLines(file, warn = TRUE) :
** incomplete final line found on ‘C:\Users\Uaer\Downloads\bym2_predictor_plus_offset.stan’
failed to create the sampler;** sampling not done
in my opinion , in source(“mungecardata4stan.R”) you should type the address of mungecardata4stan.R that is placed in your pc. and also for source(“iran_data.R”). like this: source("C:/Users/me/Desktop/iran_data.R").

Chunk SMS into SMSes of size 30 characters

The problem statement is as follows -
There is a text messaging service.It provides with an API to send SMSes to a user,
but they can be at most 30 characters long.
Also it doesn't guarantee the order in which the messages will be received.
You have to build a function which splits the text in chunks so that it can
be sent in multiple messages. Each chunk has to be :
- upto 30 characters long
- no word should be split in the middle
- each chunk has to have its order suffixed in the form of '(k/n)'
e.g. "this is the first chunk (1/2)", "this is the second chunk (2/2)"
- if the text provided to the function is within 30 characters limit,
no ordering should be suffixed
Input/Output Format
Each test case consists of a single line of words. Words are space
separated. Any other character other than space is considered part of
the word. For each test case, output the minimum number of chunks C
required to fit the entire SMS.
Restrictions
1 <=C<= 99; Input will be such that C remain in this mentioned limit
if your algorithm is optimal. No word will have a length that does
not fit in a single chunk (even after considering the suffix).
Sample Input:
The best lies are always mixed with a little truth
There is no creature on earth half so terrifying as a truly just man!!!!!
You know nothing, Jon Snow
Sample Output
3
3
1
Explanation:
In first case, we will have to split as below
The best lies are always (1/3)
mixed with a little (2/3)
truth (3/3)
First line is fully utilised with 30 characters in it.
Second line has 25 characters but if we try to fit last word in this line,
it becomes 31 characters. 'mixed with a little truth (2/2)
Hence we must split into 3 parts as above.
My approach -> was more around finding the approximate number of chunks first and then expanding on it but that didn't work. I was wondering is it even possible to first calculate how many chunks will be required mathematically or do we actually have to build chunks and see but then how do we build chunks without knowing 'n' of 'k/n'?
You have to know n to be able to know how many words can be put in each chunk because that depends on n.
Even if n is expressed in base 99 so that it only takes one character, you still need to examine the length of every word individually.
I have a suspicion that the optimal distribution of words between chunks is not the simple method of putting words (and spaces) into lines until the next item won't fit: it could be better to make some smaller chunks somewhere earlier to enable better packing later. However, this is not the cutting stock problem because the order must be preserved.
By the simple method, I mean packing the words in assuming there are less than ten chunks, and if not then start again based on there being less than 100 chunks, for example in VB.NET:
Imports System.Text
Imports System.Text.RegularExpressions
Module Module1
Function NumberLength(n As Integer) As Integer
Return If(n < 10, 1, 2)
End Function
Sub Main()
Dim msg = "Escobazos tu dios pisan amor sus el las grupos se y no de los pulso mudas muerte mi inocentes vilo los las bajaba viciosa tierra de amor horizonte la se deja de tierra heridas ni los la es los recodos horizonte diminutas la de es nube talco hombrecillo de piel los se escobazos nadadora de bajo consume las se con ni las en por que donde tierra es sillas el de de que latido viva lo a grupos torre escaleras desnudo dolor me a la la quedo que sepultura signos criaturas de desnudo subía la húmedo desnuda latido nube quedo de la el nadadora el cielo dolor arroyo escobazos quedo donde de amor venas el viva poniendo desangradas torre que resonancia los fría ansioso el de subía el tierra todo se ansioso manteles por amor amor con de el quemadas resonancia con mujer el y que luna los bajaba quedo los yo a alegrísima de ilesa huido el mi que los se bajo la hombrecillo luna en de vilo es de el aire despenada que latido aire para sus horizonte todo muelles heridas viva hule tierra para huido de las a los llenando los que por húmedo tránsito tierra la la aire olvidando recodos de de la ligeros los término por luna bajaba tierra llenando del al que bajo de que de a pupila mueven que grupos se tránsito los ciudades de de nino mármol vuelve lenguas se los pisotean la vengo con faraón tránsito ballenas la se los tierra del escaleras de tierra nunca lenta se musgos que desgarrados la de desgarrados la imperturbable la resonancia y duro subía tierra me mi de talco escaleras el duro los desangradas sus buscando desangradas de pies algodón golondrina por que las no larga con diana que el en imperturbable de los luna al la huevos muertos las los las larga para borrachos de el aire los la bajo tierra fría talco los los comida en llanura en en los todo que en olvidando es de el de tu la de los muerte los las de que húmedo llenando de los pasan los hombrecillo se duro lenta ballenas ninos hule la con a la tierra por gustada es y se tierra amor las recientes manteles tierra de para signos el es un diana es del dios es imperturbable de consume de muelles luna para al nube tierra bajo apariencia encuentro es diminutas"
Dim nPart = 1
Dim nPartsTotal = 1 'assume 9 or less parts
Dim nPartsTotalLength = 1
Dim maxPartLength = 30
If msg.Length <= maxPartLength Then
Console.WriteLine("1")
Console.ReadLine()
Exit Sub
End If
Dim words = Regex.Split(msg, "( )")
Dim suffixLength = 5 ' up to 9 parts
Dim pos = 0
Dim nWord = 0
Dim thisPart As New StringBuilder
Dim partText As New List(Of String)
While nWord < words.Count()
suffixLength = 3 + NumberLength(nPart) + nPartsTotalLength
If pos + suffixLength + words(nWord).Length <= maxPartLength Then
pos += words(nWord).Length
nWord += 1
thisPart.Append(words(nWord - 1))
Else
partText.Add(thisPart.ToString())
pos = 0
nPart += 1
nPartsTotal += 1
thisPart.Clear()
If nPartsTotal > 9 AndAlso nPartsTotalLength = 1 Then
' start again knowing that there are more than 9 parts required
nPartsTotalLength = 2
nPart = 1
nPartsTotal = 1
nWord = 0
partText.Clear()
End If
End If
End While
If thisPart.Length > 0 Then
partText.Add(thisPart.ToString())
End If
Console.WriteLine(nPartsTotal)
Console.WriteLine(New String("|"c, maxPartLength)) ' show max length
For i = 1 To partText.Count()
Console.WriteLine($"{partText(i - 1)}({i}/{nPartsTotal})")
Next
Console.ReadLine()
End Sub
End Module
That happens to generate 99 chunks. The question doesn't ask for the output of the actual chunks - that part of the example code is there to have a look in case it is obvious where a different alogorithm could do better.
It was rather simpler. I started with trying to find the number of chunks first and that is where it went wrong. Andrew's solution is correct.
I am attaching my code in JavaScript(just for reference)
function splitSMSIn10Chunks(string){
let parts = string.split(' ');
let suffix = '(x/y)';
let chunks = 0;
let currentChunk = '';
for(let i=0;i<parts.length;i++){
if((currentChunk.length+1+parts[i].length+suffix.length)<=30){
currentChunk = currentChunk + parts[i] + " ";
}else{
currentChunk = currentChunk + suffix;
currentChunk = parts[i]+" " ;
chunks++;
}
if(i==parts.length-1){
//Last chunk
currentChunk = currentChunk + suffix;
chunks++;
}
if(chunks==10) return -1;
}
return chunks;
};
function splitSMSIn99Chunks(string){
let parts = string.split(' ');
let suffix = '(x/yy)';
let chunks = 0;
let currentChunk = '';
for(let i=0;i<parts.length;i++){
if((currentChunk.length+1+parts[i].length+suffix.length)<=30){
currentChunk = currentChunk + parts[i] + " ";
}else{
currentChunk = currentChunk + suffix;
currentChunk = parts[i]+" " ;
chunks++;
if(chunks==9){
suffix = '(xx/yy)';
}
}
if(i==parts.length-1){
//Last chunk
currentChunk = currentChunk + suffix;
chunks++;
console.log(currentChunk);
}
}
return chunks;
};
let sms = "The best lies are always mixed with a little truth The best lies are always mixed with a little truth The best lies are always mixed with a little truth The best lies are always mixed with a little truth";
let chunksRequired = splitSMSIn10Chunks(sms);
if(chunksRequired==-1){
console.log(splitSMSIn99Chunks(sms));
}else{
console.log(chunksRequired);
}
It can be done in 1 function also but to keep it simpler and easier to read, I have created two separate functions.

Convert specific string into int

I've read in multiple topics about this, but i cant get it.
I have this specific type of string format: 8Y4H20M.
I need to obtain in 3 differents variables
Year=8
Hours=4
Minutes=20
First i've done this, because the string can have spaces
var cadena = tiempo.ToUpper().Trim();
//Saco todos los espacios que haya en las cadenas
cadena = string.Join("", cadena.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
var cont = 0;
//int dia = 0, hora = 0, minutos = 0;
string[] numbers = Regex.Split(cadena, #"\D+");
foreach (string value in numbers)
{
if (!string.IsNullOrEmpty(value))
{
if (cont == 0)
{
minutos += (Convert.ToInt32(value))*480;
cont++;
}
else if (cont == 1)
{
minutos += (Convert.ToInt32(value))*60;
cont++;
}
else if (cont == 2)
{
minutos += (Convert.ToInt32(value));
cont++;
}
}
}
But for example. This doesnt work if the string is "8H7M" or if "19Y".I have to search for specific chars and put them in variables.
Thanks
I suggest using a small and easy to understand regex to collect matches details into a dictionary:
var result = Regex.Matches(s, #"(?<num>[0-9]+)\s*(?<unit>[mhy])", RegexOptions.IgnoreCase)
.Cast<Match>()
.ToDictionary(x => x.Groups["unit"].Value, m => m.Groups["num"].Value);
See the regex demo. The (?<num>[0-9]+)\s*(?<unit>[mhy]) matches:
(?<num>[0-9]+) - 1 or more (+) digits ([0-9]) and places the result into Group "num"
\s* - 0+ whitespace symbols
(?<unit>[mhy]) - 1 of 3 letters, in a case insensitive way (due to the flag used): m, h or y, put into Group "unit".
A simplified code demo:
string s = "8Y4H20M 8H7M 8 h 7 M 19 y 19Y";
MatchCollection result = Regex.Matches(s, #"(?<num>[0-9]+)\s*(?<unit>[mhy])", RegexOptions.IgnoreCase);
foreach (System.Text.RegularExpressions.Match m in result) {
Console.WriteLine("{0} / {1}", m.Groups["unit"].Value, m.Groups["num"].Value);
Output:
Y / 8
H / 4
M / 20
H / 8
M / 7
h / 8
M / 7
y / 19
Y / 19

How increment ++ really works and how to adapt it to exclude an invalidity?

The context:
As part of a class project, I created this code (Original Version). It works great, had almost full grade. As I was learning new materials, I challenge myself to rewrite the original code and to implement the new stuff in it. So basically what this new version (not much difference with the original - feel free to compare) does is:
you enter a letter c/C for circle, r/R for rectangle, and k/K for Square,
enter the desire measurement,
it accordingly calculates the perimeter and the surface,
as the user if he wants to continue,
repeat the process,
display (in same order) the following information when the user decides to stop:
total number of figures treated,
the larger surface,
the smaller circle perimeter,
total number of rectangle with length > 7.8,
total number of square treated,
the average length of the side of the square treated.
Notice in the execution below that 3 of the 4 characters enter are valid. So we get their surface and perimeter. However 'T' is an invalid character, but when the user decides not to continue it is still counted as part of the total figure and gives me 4 instead of 3:
Entrez le caractere correspondant a la figure geometrique (c,C,r,R,k,K): c
Veuillez entrer le rayon: 10
Le perimetre est de: 62.83
La surface est de: 314.16
Voulez-vous continuer ? (o/n) o
Entrez le caractere correspondant a la figure geometrique (c,C,r,R,k,K): t
Le caractere 'T' est invalide
Voulez-vous continuer ? (o/n) o
Entrez le caractere correspondant a la figure geometrique (c,C,r,R,k,K): k
Veuillez entrer le cote du carre: 5
Le perimetre est de: 20.00
La surface est de: 25.00
Voulez-vous continuer ? (o/n) o
Entrez le caractere correspondant a la figure geometrique (c,C,r,R,k,K): r
Veuillez entrer la longeur et largeur du rectangle: 10 5
Le perimetre est de: 30.00
La surface est de: 50.00
Voulez-vous continuer ? (o/n) n
Au total, on a traite 4 figure(s)
La surface la plus grande est: 314.16
Il y a 1 rectangle(s) dont la longueur depasse 7.80 metres
Le plus petit perimetre des cercles est: 62.83
Le nombre total de carre traitees : 1
Le cote moyen des carres traites est de: 5.00
Process returned 0 (0x0) execution time : 47.514 s
Press any key to continue.
Question:
How to adapt the increment (somFigure++) in a way that it only counts the valid characters enter by the user?
Source code:
int main() {
char figure,
reponse;
int valide,
nbCarre = 0,
somFigure = 0,
nbGrRec = 0;
float perimetre,
surface,
rayon,
longueur,
largeur,
cote,
somCarre = 0.0,
plusGrandeSurface = 0.0,
plusPetitPerimetreC = 5000.0;
const float PI = 3.14159,
GRAND_RECTANGLE = 7.8;
do
{
printf("Entrez le caractere correspondant a la figure geometrique (c,C,r,R,k,K): ");
fflush(stdin);
figure = toupper(getchar());
valide = (figure == 'C') || (figure == 'R') || (figure == 'K');
somFigure++;
switch (figure) {
case 'C': printf("Veuillez entrer le rayon: ");
scanf("%f", &rayon);
perimetre = 2 * PI * rayon;
surface = PI * rayon * rayon;
if (surface > plusGrandeSurface)
plusGrandeSurface = surface;
if (perimetre < plusPetitPerimetreC)
plusPetitPerimetreC = perimetre;
break;
case 'R': printf("Veuillez entrer la longeur et largeur du rectangle: ");
scanf("%f%f", &longueur, &largeur);
perimetre = 2 * (longueur + largeur);
surface = longueur * largeur;
if (longueur > GRAND_RECTANGLE)
nbGrRec++;
if (surface > plusGrandeSurface)
plusGrandeSurface = surface;
break;
case 'K': printf("Veuillez entrer le cote du carre: ");
scanf("%f", &cote);
perimetre = 4 * cote;
surface = cote * cote;
nbCarre++;
somCarre += cote;
if (surface > plusGrandeSurface)
plusGrandeSurface = surface;
break;
default: printf("Le caractere '%c' est invalide\n", figure);
} /* Fin du Switch */
if (valide)
printf("Le perimetre est de: %.2f\n", perimetre),
printf("La surface est de: %.2f\n", surface);
printf("\nVoulez-vous continuer ? (o/n) ");
fflush(stdin);
reponse = getchar();
fflush(stdin);
}while(toupper(reponse) == 'O'); /* Fin de la boucle do....while */
printf("\nAu total, on a traite %d figure(s)\n", somFigure);
printf("La surface la plus grande est: %.2f\n", plusGrandeSurface);
if (nbGrRec > 0)
{
printf("Il y a %d rectangle(s) dont la longueur depasse %.2f metres\n", nbGrRec, GRAND_RECTANGLE);
}
else
printf("Il y a aucun rectangle traite\n");
if (plusPetitPerimetreC != 5000.0)
{
printf("Le plus petit perimetre des cercles est: %.2f\n", plusPetitPerimetreC);
}
else
printf("Il y a aucun cercle traite\n");
// Fait un resumer des nombre de carrés traités si l'utilisateur decise de ne plus continuer
if (nbCarre > 0)
{
printf("Le nombre total de carre traitees : %d\n", nbCarre);
printf("Le cote moyen des carres traites est de: %.2f\n", somCarre / nbCarre);
}
else
printf("Il y a aucun carre traite\n");
return 0;
}
You can do this:
if (valide) {
somFigure++;
printf("Le perimetre est de: %.2f\n", perimetre),
printf("La surface est de: %.2f\n", surface);
}
Also note that the original code without the curly braces probably does not work as you expect. The first printfstatement will be executed only if valide is true but the second one will be executed in any case. It's a good practice to always use curly braces with if statements to avoid errors like this.

Unexpected result in color conversion from LAB to RGB

My goal is to create high-resolution images of color charts in LAB.
I'm a beginner in programming and I use Processing because that's the best I know to do it. However, it works only in RGB or HSB so I have to convert LAB to RGB in order to display it.
I used the formulas found on the web (LAB to XYZ and XYZ to RGB)
I included them in my code, then I use a "for" loop to determine the color for each pixel.
I saw a few topics on color conversion, but I'm kind of stuck as I don't know where my problem is coming from ....
So here it is: for a fixed value of L = 100, everything is working perfectly, I'm getting this image as expected :
https://drive.google.com/file/d/0ByjuuWpChE01X3otSFRQNFUyVjA/edit?usp=sharing
But when I try to make another image for a fixed value of a = 0, I get a horizontal line in the bottom, as if there was a problem with lower values of L ... here it is :
https://drive.google.com/file/d/0ByjuuWpChE01RzJWUVZnR2U3VW8/edit?usp=sharing
Here is my code, I hope it will be clear, ask me if you need anything, and thank you very much for your help.
// parameters for the code execution
void setup() {
noLoop();
size(10,10,P2D);
nuancier = createGraphics(taille,taille);
}
// final image file and size
PGraphics nuancier ;
int taille = 1000 ;
// Arrays for color values
float[] colorLAB = new float[3];
float[] colorXYZ = new float[3];
float[] colorRGB = new float[3];
// colors
float X;
float Y;
float Z;
float L;
float a;
float b;
float R;
float G;
float B;
// pixels
int x ;
int y ;
// function to convert Lab to XYZ
float[] LABtoXYZ() {
L = colorLAB[0];
a = colorLAB[1];
b = colorLAB[2];
float ntY = ( L + 16 ) / 116 ;
float ntX = a / 500 + ntY ;
float ntZ = ntY - b / 200 ;
if ( (pow(ntY,3)) > 0.008856 ) {
ntY = (pow(ntY,3)) ;
} else { ntY = ( ntY - 16 / 116 ) / 7.787 ; }
if ( (pow(ntX,3)) > 0.008856 ) {
ntX = (pow(ntX,3)) ;
} else { ntX = ( ntX - 16 / 116 ) / 7.787 ; }
if ( (pow(ntZ,3)) > 0.008856 ) {
ntZ = (pow(ntZ,3)) ;
} else { ntZ = ( ntZ - 16 / 116 ) / 7.787 ; }
X = 95.047 * ntX ; //ref_X = 95.047 Observateur= 2°, Illuminant= D65
Y = 100 * ntY ; //ref_Y = 100.000
Z = 108.883 * ntZ ; //ref_Z = 108.883
colorXYZ[0] = X ;
colorXYZ[1] = Y ;
colorXYZ[2] = Z ;
return colorXYZ ;
}
// function to convert XYZ to RGB
float[] XYZtoRGB() {
X = colorXYZ[0];
Y = colorXYZ[1];
Z = colorXYZ[2];
float ntX = X / 100 ; //X compris entre 0 et 95.047 ( Observateur = 2°, Illuminant = D65 )
float ntY = Y / 100 ; //Y compris entre 0 et 100.000
float ntZ = Z / 100 ; //Z compris entre 0 et 108.883
float ntR = ntX * 3.2406 + ntY * (-1.5372) + ntZ * (-0.4986) ;
float ntG = ntX * (-0.9689) + ntY * 1.8758 + ntZ * 0.0415 ;
float ntB = ntX * 0.0557 + ntY * (-0.2040) + ntZ * 1.0570 ;
if ( ntR > 0.0031308 ) {
ntR = 1.055 * ( pow(ntR,( 1 / 2.4 )) ) - 0.055 ;
} else { ntR = 12.92 * ntR ; }
if ( ntG > 0.0031308 ) {
ntG = 1.055 * ( pow(ntG,( 1 / 2.4 )) ) - 0.055 ;
} else { ntG = 12.92 * ntG ; }
if ( ntB > 0.0031308 ) {
ntB = 1.055 * ( pow(ntB,( 1 / 2.4 )) ) - 0.055 ;
} else { ntB = 12.92 * ntB ; }
R = ntR * 255 ;
G = ntG * 255 ;
B = ntB * 255 ;
colorRGB[0] = R ;
colorRGB[1] = G ;
colorRGB[2] = B ;
return colorRGB ;
}
// I know that with RGB, not every visible color is possible
//so I just made this quick function, to bound RGB values between 0 and 255
float[] arrondirRGB () {
for (int i=0;i<3;i++) {
if (colorRGB[i]>255) {
colorRGB[i]=255 ;
}
if (colorRGB[i]<0) {
colorRGB[i]=0 ;
}
}
return colorRGB;
}
// operating section
void draw () {
nuancier.beginDraw();
nuancier.noSmooth();
nuancier.colorMode(RGB, 255);
nuancier.endDraw();
for (x=0;x<taille;x++) {
for (y=0;y<taille;y++) {
colorLAB[0] = (((taille-y)*100)/taille) ; // --------------------------------------------------------------- valeur 100 // formule ((x*100)/taille)
colorLAB[1] = 0 ; // ----------------------------------------------------------- valeur 0 // formule ((x*256)/taille)-127
colorLAB[2] = (((x)*256)/taille)-127 ; // -------------------------------------------------- valeur 0 // (((taille-y)*256)/taille)-127
println(colorLAB[0]);
LABtoXYZ () ;
XYZtoRGB () ;
arrondirRGB () ;
nuancier.beginDraw();
nuancier.stroke (colorRGB[0],colorRGB[1],colorRGB[2]);
nuancier.point (x,y);
nuancier.endDraw();
}
}
nuancier.save("nuancier.tiff");
println("done !");
}
Ok I found out !
The problem was dividing by integers.
I don't know if it works like that in other languages, but in processing if you write
x = 2/5
the result will be x = 0 instead of x = 0.4 ; it's because with the denominator being an integer, the result will always be an integer .... so
x = 2/5.0
will give x = 0.4 !
I had to put a ".0" after every integer dividing, and turn to float any integer data that would divide.
The result is perfect, no more problems !
https://github.com/processing/processing/wiki/Troubleshooting#Why_does_2_.2F_5_.3D_0_instead_of_0.4.3F

Resources