Thus, in one dimension, the temporal evolution of the probability density is determined by the spatial derivatives of two fluxes: a diffusive flux, associated with random fluctuations, and a drift flux, associated with the deterministic tendency imposed by external forces.
When x varies through small stochastic steps Δx, we define the diffusion coefficient as
that is, the temporal evolution of the probability is given by the divergence of the sum of two fluxes: a diffusive flux and a flux generated by external forces.
Before proceeding, however, we will first seek to understand how this equation is derived.
Fokker-Planck Equation with Small Variation Steps¶
The joint probability that the system is in state X2 at time t2 and in state X1 at the later time t1 is equal to the product of the probability that the system is in X2 at time t2 and the conditional probability that, given the system is in X2 at t2, it evolves to state X1 at time t1.
This is the standard relation for joint probabilities,
That is, the probability that the system transitions to state X1 depends only on its immediately preceding state X2. Information about earlier states does not provide any additional information.
For a Markov process, the Chapman-Kolmogorov equation is satisfied:
The Chapman-Kolmogorov equation establishes that the probability of the system evolving from state X3 at time t3 to state X1 at time t1 can be obtained by considering all possible intermediate states X2 at time t2. For each intermediate state, we multiply the probability of the system evolving from X3 to X2 by the probability of evolving from X2 to X1, and then integrate over all possible values of X2, that is, over all possible intermediate states.
Let us assume that the transition probabilities do not depend on the absolute time, but only on the elapsed time interval. Therefore, for simplicity of notation,
That is, initially we had only a direct transition from X to Y, separated by a time interval t+Δt. By applying the Chapman--Kolmogorov equation, we introduce an intermediate state Z at time t, decomposing the trajectory into two successive transitions. The first describes the evolution from X to Z, whose time interval is t−0=t, whereas the second describes the evolution from Z to Y, whose interval is (t+Δt)−t=Δt. Since the process is homogeneous in time, the transition probability depends only on the duration of the interval and not on the absolute time at which it occurs. Therefore,
Notice that only the second transition is rewritten in this way; the total interval between X and Y remains t+Δt.
Since the integral runs over all possible states, the integration variable does not represent a specific state, but only an index that enumerates all possible states. Therefore, we can replace Y by Z (or any other symbol), provided that the replacement is made consistently throughout the entire integral. Thus, we can rewrite the integral over dY as an integral over dZ in the second term:
because there is a 100% probability that the system evolves from state Z to some state (we are integrating over all possible states), and since h(Z) does not depend on Y, we have
Since the test function h(Z) has compact support, the boundary term vanishes, because it is zero outside the region of interest. Therefore, we are left with
Again, due to the fact that h(Z) has compact support, we have that h(1)(Z)=0 outside its support, that is, at the boundaries of the integration domain. Performing another integration by parts, with
which means that, at the initial instant, the random variable X assumes the value X0 with unit probability. The entire probability distribution is concentrated at X0, being represented by the Dirac delta distribution.
calculated with respect to the transition probability distribution, that is, considering all possible transitions from the state X0 at time 0 to the states X at time Δt.
To demonstrate this relation, we introduce some additional assumptions. Consider a single realization of the process during a time interval (Δt), in which (ΔN) transactions occur and the total transferred wealth is (Δw). We define the average wealth transferred per transaction in this realization as
Next, we generalize to an ensemble of realizations, in which both (Δw) and (ΔN) may vary. Taking the mathematical expectation over this ensemble and assuming that the number of transactions occurring within an interval is statistically independent of the average wealth transferred per transaction, we obtain:
For a Poisson process, we assume that the probability of an event occurring within a small time interval is proportional to the time interval. That is,
while reinforcing the assumption that we are working with a Poisson process. Consider a single realization of the process during a time interval Δt, in which ΔN transactions occur:
For the first term, we repeat the reasoning from the previous case. Since we avoid the case where i=j, if the first summation involves ΔN terms, the second sums over ΔN values for i and ΔN−1 values for j (for example), thereby excluding instances where i=j. Thus, the second summation consists of ΔN(ΔN−1) terms. Denoting the ensemble average of the terms ⟨Δ(w)jΔ(w)i⟩ as ⟨ΔΔ(w)E⟩, we write:
Therefore, since the second term is proportional to (Δt)2, after dividing by Δt it remains of order Δt, vanishing in the continuous limit. This shows that the second Kramers-Moyal coefficient is determined only by the second moment of the wealth transferred in a single transaction, in complete analogy with the result obtained for the first moment. Choosing the time unit as the average interval between transactions, that is, λ=1, we obtain
However, let us pause for a moment and start from the beginning. Suppose that wealth is distributed according to a probability density function (PDF) P(w). Then,
Before proceeding, it seems interesting to make one more observation. In the description of the model, it is assumed that the commodity possesses an “intrinsic value”, and that when agents exchange with each other, they assign a price different from this intrinsic value, that is, they evaluate it above or below its intrinsic value. This causes a transfer of wealth (measured in intrinsic value) between agents.
In this description, the concept of the agent’s “utility function” is even mentioned to justify this incorrect valuation (it is worth noting that this is explicitly described as an error). It is interesting that, while attempting to preserve the idea of a utility function from marginalist microeconomics, the model simultaneously postulates the existence of an objective value that differs from the price.
However, continuing, we aim to model the exchange of wealth between two agents such that:
One agent has wealth w and another has wealth w′.
The amount to be transferred is a fraction β of the wealth of the poorer agent.
The amount of wealth being transferred from w′ to w is
I believe this issue will not affect the equations developed later, since they deal with probability flows. However, a simple way to resolve it is to use another popular definition of the Heaviside function:
Here, ⟨.⟩ denotes the average over the distribution of step sizes, that is, in this case, the average over the distribution of possible amounts of wealth transferred in an interaction.
The wealth variation of an agent with wealth w after a transaction has two sources of stochasticity:
The wealth w′ of the partner agent must be obtained from a sample of the probability distribution function P(w′).
The random variable r.
We define the average of the function f(w′,r) over these two sources of randomness as:
Now we need to understand why we are calculating the average over the first term inside the brackets. We want an average over both sources of randomness. For a fixed value of w′, there are two possible values of r with equal probability. Therefore,
This means that the global average of f (over both sources of randomness) is calculated in two steps: (i) we fix the partner’s wealth w′ and calculate the average over the variable r; (ii) we then average these results over all possible values of the partner’s wealth w′, weighted by their probability of occurrence.
It is worth noting that Ei[f] indicates that the average is taken over the variable i. Therefore,
However, this case corresponds to a single point in the integration domain. Since a set composed of a single point has null measure, its contribution to the integral is zero. In one dimension, the measure of a set corresponds to its length; in two dimensions, to its area; in three dimensions, to its volume. More generally, integrals are computed with respect to the measure of the integration domain.
provided that P(0) and P′(0) do not diverge too rapidly. Since B(0)=0 trivially, it is sufficient that P(0) remains finite, which is a reasonable condition.
it is necessary and sufficient that the tail of the distribution P(w) and its derivative P′(w) decay sufficiently fast. This is again a reasonable assumption, since no agent can possess infinite wealth.
Moreover, for A(∞)=0, we now have a trivial integral, since the integration limits are identical.
In summary, we assume the following regularity conditions:
P(w) is differentiable in a neighborhood of w=0, such that P(0) and P′(0) are finite. Consequently,
Observation: Saying that a quantity goes to zero “faster” means that, when comparing two functions, one vanishes more rapidly than the other in a given limit. For example, consider A(x)=x, and B(x)=x−2, as x→∞. In this case, A(x) diverges while B(x) approaches zero. The function B(x) approaches zero faster than A(x) grows, since
Let us assume that, during a small time increment, the wealth w is taxed at a rate τ, transferring an amount τw to the collector. The total amount of wealth collected from all agents is therefore
According to the model description, this quantity represents the transfer rate, that is, the rate at which wealth is transferred. Therefore, the total change in wealth over a given time interval is
where Δ(w,w′,r) is the accumulated wealth change due to exchanges during the interval Δt. The difference between Δ(w) and Δr(w) is that the former represents an amount of wealth, while the latter is a rate of change.
We will try to solve the equation and obtain the same result as the article. According to the authors, the solutions present power-law behavior for large values of w and a cutoff behavior for small values of w, in full agreement with Pareto’s observations.
That is, it is not exactly a power-law distribution. A numerical solution was created with the aid of DeepSeek, ChatGPT and Gemini.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp, cumulative_trapezoid
from scipy.optimize import root_scalar
# =====================================================
# PARÂMETROS
# =====================================================
chi = 2
w_start = 0.1
w_end = 100
# =====================================================
# EVENTO DE PARADA (SINGULARIDADE)
# =====================================================
# Esta função avisa o solver quando o denominador atinge 1e-15
def limite_denominador(w, y):
P, A, B = y
denom = 0.5 * w * w * A + B
return denom - 1e-15
# Comando para interromper a integração quando a função retornar 0
limite_denominador.terminal = True
# =====================================================
# SISTEMA DE EDOS (AGORA MATEMATICAMENTE PURO)
# =====================================================
def ode(w,y):
P,A,B = y
denom = 0.5*w*w*A + B
# A trava artificial foi removida. O solver confia no evento.
dP = ((chi*(1-w)-w*A)/denom)*P
dA = -P
dB = 0.5*w*w*P
return [dP,dA,dB]
# =====================================================
# MÉTODO DO TIRO
# =====================================================
def shoot(P0):
sol = solve_ivp(
ode,
[w_start, w_end],
[P0, 1, 0],
events=limite_denominador, # <--- Evento adicionado aqui
rtol=1e-10,
atol=1e-12
)
return sol.y[1,-1]
res = root_scalar(
shoot,
bracket=[1e-10,2],
method='brentq'
)
P0 = res.root
print("P inicial =", P0)
# =====================================================
# SOLUÇÃO FINAL
# =====================================================
sol = solve_ivp(
ode,
[w_start, w_end],
[P0, 1, 0],
events=limite_denominador, # <--- Evento adicionado aqui
dense_output=True, # Permite calcular pontos customizados depois da solução
rtol=1e-10,
atol=1e-12
)
# Descobrindo onde a simulação realmente parou (pode ser 100, ou antes)
w_max_real = sol.t[-1]
print(f"Integração concluída até w = {w_max_real}")
# Criando a malha exata de 4000 pontos até o limite real encontrado
w = np.linspace(w_start, w_max_real, 4000)
# Avaliando os resultados nessa nova malha usando a saída densa (sol.sol)
y_densa = sol.sol(w)
P = y_densa[0]
A = y_densa[1]
B = y_densa[2]
P inicial = 1.3656669579129148e-10
Integração concluída até w = 100.0
# @title
# =====================================================
# TESTE 1
# RESÍDUO DA EDO
# =====================================================
Q = (0.5*w**2*A+B)*P
dQ = np.gradient(Q,w)
R = chi*(1-w)*P-dQ
print()
print("========== TESTE 1 ==========")
print("Resíduo máximo =",np.max(np.abs(R)))
print("Resíduo médio =",np.mean(np.abs(R)))
# =====================================================
# TESTE 2
# RECONSTRUÇÃO DE A
# =====================================================
A_int = np.zeros_like(w)
for i in range(len(w)-1):
A_int[i] = A_int[i] = np.trapezoid(P[i:], w[i:])
# =====================================================
# TESTE 3
# RECONSTRUÇÃO DE B
# =====================================================
B_int = cumulative_trapezoid(
0.5*w**2*P,
w,
initial=0
)
print()
print("========== TESTE 2 ==========")
print("Erro máximo A =",np.max(np.abs(A-A_int)))
print("Erro máximo B =",np.max(np.abs(B-B_int)))
# =====================================================
# TESTE 4
# HIPÓTESE DO ARTIGO
# A≈1
# B≈0
# =====================================================
# Este 'mask_short_range' é específico para a região de w < 0.3
mask_short_range = w<0.3
print()
print("========== TESTE 3 ==========")
print("A médio =",np.mean(A[mask_short_range]))
print("A mínimo =",np.min(A[mask_short_range]))
print("A máximo =",np.max(A[mask_short_range]))
print()
print("B médio =",np.mean(B[mask_short_range]))
print("B máximo =",np.max(B[mask_short_range]))
# =====================================================
# TESTE 5
# EQUAÇÃO 22
# =====================================================
Qapprox = 0.5*w**2*P
dQapprox = np.gradient(Qapprox,w)
erro22 = np.max(np.abs(dQ[mask_short_range]-dQapprox[mask_short_range]))
print()
print("========== TESTE 4 ==========")
print("Erro aproximação Eq.22 =",erro22)
# =====================================================
# TESTE 6
# EXPOENTE LOCAL
# =====================================================
# Define uma máscara consistente para todos os gráficos log-log e cálculo de alpha
mask_for_log_plots = (P > 1e-15) & (w > 0.1)
alpha = np.gradient(
np.log(P[mask_for_log_plots]),
np.log(w[mask_for_log_plots])
)
# =====================================================
# GRÁFICOS
# =====================================================
plt.figure(figsize=(7,5))
plt.plot(w,P)
plt.xlabel("w")
plt.ylabel("P")
plt.grid()
plt.figure(figsize=(7,5))
plt.loglog(w[mask_for_log_plots],P[mask_for_log_plots]) # Usa a máscara consistente
plt.xlabel("w")
plt.ylabel("P")
plt.grid()
plt.figure(figsize=(7,5))
plt.plot(w,A,label="A")
plt.plot(w,A_int,"--",label="A integral")
plt.legend()
plt.grid()
plt.figure(figsize=(7,5))
plt.plot(w,B,label="B")
plt.plot(w,B_int,"--",label="B integral")
plt.legend()
plt.grid()
plt.figure(figsize=(7,5))
plt.plot(w,R)
plt.title("Resíduo da Eq. (21)")
plt.grid()
plt.figure(figsize=(7,5))
plt.plot(w[mask_short_range],dQ[mask_short_range],label="Eq.21")
plt.plot(w[mask_short_range],dQapprox[mask_short_range],'--',label="Eq.22")
plt.xlim(0,0.3)
plt.legend()
plt.grid()
#plt.figure(figsize=(7,5))
#plt.plot(w[mask_for_log_plots],alpha) # Usa a máscara consistente
#plt.axhline(-3,color='r',ls='--',label='Pareto')
#plt.xlabel("w")
#plt.ylabel(r"$d\log P/d\log w$")
#plt.legend()
#plt.grid()
# =====================================================
# DIAGNÓSTICO FINAL - EXPOENTE LOCAL
# =====================================================
========== TESTE 1 ==========
Resíduo máximo = 0.003084306495342054
Resíduo médio = 1.3438167479948002e-05
========== TESTE 2 ==========
Erro máximo A = 0.002406190124915941
Erro máximo B = 4.542429082963692e-05
========== TESTE 3 ==========
A médio = 0.9996122233846921
A mínimo = 0.9977994902589599
A máximo = 1.0
B médio = 1.3615078697893104e-05
B máximo = 8.335080497379325e-05
========== TESTE 4 ==========
Erro aproximação Eq.22 = 9.806582728119628e-05
# =====================================================
# COMPARAÇÕES TEÓRICAS PARA w PEQUENO E w ALTO
# =====================================================
# --- 1. Ajuste da constante C para w pequeno (Eq. 23) ---
# Escolhe um ponto na região de w pequeno (ex: w ≈ 0.2)
w_ref_small = 0.2
idx_small = np.argmin(np.abs(w - w_ref_small))
C_small = P[idx_small] * (w_ref_small ** (2*(chi+1))) * np.exp(2*chi / w_ref_small)
# Gera a curva teórica para w pequeno
w_teo_small = np.linspace(w_start, 0.5, 200) # até w=1 para ver a transição
P_teo_small = C_small * w_teo_small ** (-2*(chi+1)) * np.exp(-2*chi / w_teo_small)
# --- 2. Ajuste da constante C para w alto (Gaussiana centrada em w=1) ---
B_inf = B[-1] # Agora SEM fator empírico!
# Escolhe um ponto na região da cauda (ex: w ≈ 4) para ajustar a constante
w_ref_high = 4.0
idx_high = np.argmin(np.abs(w - w_ref_high))
# Usando a fórmula correta: P = C * exp( chi*(2w - w^2) / (2*B_inf) )
C_high = P[idx_high] / np.exp(chi * (2*w_ref_high - w_ref_high**2) / (2 * B_inf))
# Gera a curva teórica para w alto
w_teo_high = np.linspace(2, 8, 300)
P_teo_high = C_high * np.exp(chi * (2*w_teo_high - w_teo_high**2) / (2 * B_inf))
# Forma equivalente (centrada em 1):
# P_teo_high = C_high * np.exp(-chi * (w_teo_high - 1)**2 / (2 * B_inf))
# --- 3. Gráficos de comparação ---
# (b) Comparação para w alto (log-log)
plt.figure(figsize=(7,5))
plt.loglog(w[mask_for_log_plots], P[mask_for_log_plots], label='Numérico (Eq. 21)')
plt.loglog(w_teo_high, P_teo_high, 'g--', linewidth=2, label=rf'Gaussiana: $\exp(-{chi:.1f} w^2 / (2 B_\infty))$')
plt.xlim(1, 6)
plt.ylim(1E-14, 1)
plt.xlabel('w')
plt.ylabel('P(w)')
plt.title('Comparação para w alto (cauda Gaussiana)')
plt.legend()
plt.grid(True, which='both', linestyle='--')
# (c) Comparação dupla (apenas para visualização geral)
plt.figure(figsize=(7,5))
plt.loglog(w[mask_for_log_plots], P[mask_for_log_plots], label='Numérico (Eq. 21)')
plt.loglog(w_teo_small, P_teo_small, 'r--', label='Eq. 23 (w pequeno)')
plt.loglog(w_teo_high, P_teo_high, 'g--', label='Gaussiana (w alto)')
plt.xlim(0.1, 6)
plt.ylim(5E-15, 2)
plt.xlabel('w')
plt.ylabel('P(w)')
plt.title('Comparação geral com as assíntotas')
plt.legend()
plt.grid(True, which='both', linestyle='--')
plt.show()
# (a) Comparação para w pequeno (log-log)
plt.figure(figsize=(7,5))
plt.loglog(w[mask_for_log_plots], P[mask_for_log_plots], label='Numérico (Eq. 21)')
plt.loglog(w_teo_small, P_teo_small, 'r--', linewidth=2, label=f'Eq. 23: $w^{{-{2*(chi+1)}}} e^{{-2chi/w}}$')
plt.xlim(w_start, 1.0)
plt.xlabel('w')
plt.ylabel('P(w)')
plt.title('Comparação para w pequeno')
plt.legend()
plt.grid(True, which='both', linestyle='--')