Author: Louis Liu

  • Why Aren’t Generalized Coordinates in the Lagrangian Equation Considered Functions of Time?

    Why Aren’t Generalized Coordinates in the Lagrangian Equation Considered Functions of Time?

    Note: This post is an English adaptation of my original Chinese article (URL). Some parts have been modified for clarity, cultural relevance, or to better fit the English-speaking audience.

    I was once puzzled by this issue, so I’d like to briefly share my understanding now. It may not be entirely correct, but here’s my take:

    Without losing generality, let’s consider a $1$-dimensional space, as the conclusions here can be extended to $n$ dimensions.

    First, in the Euler-Lagrange equation, the Lagrangian $\mathcal{L}$ is defined as a multivariable function $\mathcal{L}=f : \mathbb{R}^{2 N+1} \rightarrow \mathbb{R}$, so $\mathcal{L}(q_1, \cdots ,q_N;v_1, \cdots ,v_N;t) : \mathbb{R}$. Therefore, when we consider expressions like $\dfrac{\partial \mathcal{L}}{\partial q_i}$, $\dfrac{\partial \mathcal{L}}{\partial v_i}$, or $\dfrac{\partial \mathcal{L}}{\partial t}$, we are treating $q_i$, $v_i$, and $t$ as three entirely independent variables, much like how we handle variables $x$, $y$, and $z$ in the function $f(x, y, z)$.

    Why is that? Fundamentally, it’s because this is how the mathematical definition of partial derivatives works. Even if the variables we’re differentiating are interrelated: for example, consider the function $f(x(t), t)$. Clearly, $x$ is a function of $t$, but when you take the partial derivative of $f$ with respect to $t$, it doesn’t affect $x(t)$ at all, and when you take the partial derivative of $f$ with respect to $x(t)$, it doesn’t affect $t$. This is simply how partial derivatives operate, and you must refer to the formal definition of partial derivatives to grasp this. Therefore, when we take partial derivatives of the Lagrangian $\mathcal{L}$, $q_i$, $v_i$, and $t$ are treated as independent variables.

    However, when we consider the derivative $\dfrac{\mathrm{d} \mathcal{L}}{\mathrm{d} t}$, we are effectively treating the Lagrangian $\mathcal{L}$ as a single-variable function $\mathcal{L}=f(t): \mathbb{R} \rightarrow \mathbb{R}$. Thus, we need to apply the chain rule to expand it, resulting in:

    $$
    \displaystyle \frac{\mathrm{d} \mathcal{L}}{\mathrm{d} t}=\frac{\partial \mathcal{L}}{\partial t}+\sum_{i=1}^N \frac{\partial \mathcal{L}}{\partial q_i} \frac{\mathrm{d} q_i}{\mathrm{d} t} +\sum_{i=1}^N \frac{\partial \mathcal{L}}{\partial v_i} \frac{\mathrm{d} v_i}{\mathrm{d} t}\\
    $$

    It is important to note that the derivative $\dfrac{\mathrm{d} \mathcal{L}}{\mathrm{d} t}$ referred to here is the total derivative of the Lagrangian $\mathcal{L}$. According to the definition of the total derivative, the function being differentiated should be a single-variable function.

    Therefore, the essence of solving this question lies in understanding the formal definitions of total derivatives and partial derivatives.

    Updated: 2024-09-26

    A friend of mine recently mentioned that he still doesn’t quite understand why the Lagrangian behaves differently in the Euler-Lagrange equation versus when considering the total derivative of it after reading my initial post, so I decided to clarify this distinction by rewriting my initial post into a formal mathematical approach. So here’s an updated post, using extremely formal and rigorous mathematical language, to explain the reasoning behind it.

    I used to be perplexed by this question, and now, after some time, I’d like to share my understanding of it from a purely mathematical perspective (note: this might not be the definitive answer).

    Without losing generality, let’s consider a $1$-dimensional space, as the conclusions here can be extended to $n$ dimensions.

    First and foremost, let’s clarify an important point: in the Euler-Lagrange equation, the Lagrangian $\mathcal{L}$ is defined as a multivariate function $\mathcal{L} = f(q_1, \cdots, q_N; v_1, \cdots, v_N; t)$, where $f: \mathbb{R}^{2N+1} \to \mathbb{R}$.

    For the partial derivatives $\dfrac{\partial \mathcal{L}}{\partial q_i}$, $\dfrac{\partial \mathcal{L}}{\partial v_i}$, or $\dfrac{\partial \mathcal{L}}{\partial t}$, we treat $q_i$, $v_i$, and $t$ as three completely independent variables, much like how we treat $x$, $y$, and $z$ in a function $f(x, y, z)$.

    According to the formal definition of partial derivatives (note: set $m = 1$ and $n = 2N+1$ in the diagram, which aligns the function $\mathbf{f}$ as $\mathbb{R}^{2N+1} \to \mathbb{R}$, thereby matching the type of the function Lagrangian $\mathcal{L}$. Let $\mathbf{f}(\mathbf{x}) = \mathcal{L}$, which yields $f_i(\mathbf{x}) = \mathbf{f}(\mathbf{x}) = \mathcal{L}$):

    Referenced from Baby Rudin – 9.16

    Which indicates that when calculating partial derivatives, we disregard the relationships between the input variables of the function, as each input in a multivariate function forms an independent dimension. Therefore, when calculating the partial derivative $f_i(\mathbf{x} + t \mathbf{e}_j) -f_i(\mathbf{x})$, we are only looking at the change in a single input, while the input variables are orthogonal to each other.

    For example, consider the function $f(x(t), t)$. Clearly, $x$ is a function of $t$, but when you take the partial derivative of $f$ with respect to $t$, it won’t affect $x(t)$ at all, and similarly, taking the partial derivative of $f$ with respect to $x(t)$ won’t affect $t$. This is because, within this function, the dimensions formed by $x(t)$ and $t$ are orthogonal and do not influence each other.

    Now, regarding the total derivative, its formal definition is:

    Referenced from Baby Rudin – 9.17

    where $\mathbf{f}'(\mathbf{x})$ is defined as:

    Referenced from Baby Rudin – 9.11

    Once these definitions and theorems are in place, consider the following example:

    Referenced from Baby Rudin – 9.18

    Thus, when calculating the total derivative $\dfrac{d\mathcal{L}}{dt}$ of the Lagrangian $\mathcal{L}$, the Lagrangian $\mathcal{L}$ is defined as $\mathcal{L} = (f \circ \gamma) : \mathbb{R} \rightarrow \mathbb{R}$, where $f: \mathbb{R}^{2N+1} \to \mathbb{R}$ and $\gamma: \mathbb{R} \to \mathbb{R}^{2N+1}$.

    So, if we set $g(t) = \mathcal{L}(t) = (f \circ \gamma)(t)$ and define $\gamma(t) = \begin{bmatrix} q_1 & \cdots & q_N & v_1 & \cdots & v_N & t \end{bmatrix}^T$, using the chain rule to expand the total derivative of the Lagrangian $\mathcal{L}$, we obtain the following formula:

    $$
    \displaystyle \frac{\mathrm{d} \mathcal{L}}{\mathrm{d} t}= \sum_{i=1}^N \left ( \ (D_i f ) (\gamma (t)) \ \gamma_i'(t) \ \right ) = \frac{\partial f}{\partial t}+\sum_{i=1}^N \frac{\partial f}{\partial q_i} \frac{\mathrm{d} q_i}{\mathrm{d} t} +\sum_{i=1}^N \frac{\partial f}{\partial v_i} \frac{\mathrm{d} v_i}{\mathrm{d} t}\
    $$

    Therefore, the essence of solving this question lies in understanding the formal definitions of total derivatives and partial derivatives.

    Updated: 2024-11-02

    Here is an update, as I feel I’ve gained a new understanding of the mathematical concept of total derivative.

    Firstly, most textbooks provide the total derivative formula for the Lagrangian $\mathcal{L}$ as:

    $$
    \frac{\mathrm{d} \mathcal{L}}{\mathrm{d} t}= \frac{\partial \mathcal{L}}{\partial t}+\sum_{i=1}^N \frac{\partial \mathcal{L}}{\partial q_i} \frac{\mathrm{d} q_i}{\mathrm{d} t} +\sum_{i=1}^N \frac{\partial \mathcal{L}}{\partial v_i} \frac{\mathrm{d} v_i}{\mathrm{d} t}
    $$

    On the other hand, the total derivative formula I wrote for the Lagrangian $\mathcal{L}$ is:

    $$
    \frac{\mathrm{d} \mathcal{L}}{\mathrm{d} t} = \frac{\partial f}{\partial t}+\sum_{i=1}^N \frac{\partial f}{\partial q_i} \frac{\mathrm{d} q_i}{\mathrm{d} t} +\sum_{i=1}^N \frac{\partial f}{\partial v_i} \frac{\mathrm{d} v_i}{\mathrm{d} t}
    $$

    Then, who made a mistake here? Now please let me analyze.

    Generally, textbooks provide the general formula for the total derivative of any function $f: \mathbb{R}^N \rightarrow \mathbb{R}$ as:

    $$
    \frac{\mathrm{d} f}{\mathrm{d} t}=\sum_{i=1}^N \frac{\partial f}{\partial x_i} \frac{\mathrm{d} x_i}{\mathrm{d} t}
    $$

    In fact, if we observe the LHS of this identity, we find that the type of function $f$ is not $\mathbb{R} \rightarrow \mathbb{R}$, then why is it acceptable to use the total derivative formula on that function directly?

    I personally believe this is a matter of a historical notational convention, because:

    For a function $f: \mathbb{R}^N \rightarrow \mathbb{R}$, when we write out the total derivative $\dfrac{\mathrm{d} f}{\mathrm{d} t}$, we are actually referring to $\dfrac{\mathrm{d} z}{\mathrm{d} t}$, where $z(t) = (f \circ g)(t)$, and $z: \mathbb{R} \rightarrow \mathbb{R}$, $f: \mathbb{R}^N \rightarrow \mathbb{R}$, $g: \mathbb{R} \rightarrow \mathbb{R}^N$, $g(t) = \begin{bmatrix} x_1 \cdots \ x_N \end{bmatrix}^{T}$

    Thus, the correct formula for the total derivative should be:

    $$
    \frac{\mathrm{d}z}{\mathrm{d} t}=\sum_{i=1}^N \frac{\partial f}{\partial x_i} \frac{\mathrm{d} x_i}{\mathrm{d} t}
    $$

    However, comparing this with the original total derivative formula:
    $$
    \frac{\mathrm{d} f}{\mathrm{d} t}=\sum_{i=1}^N \frac{\partial f}{\partial x_i} \frac{\mathrm{d} x_i}{\mathrm{d} t}
    $$

    We find that the change is actually minimal, with the only difference lying on the LHS. Therefore, conventionally, if we see the ordinary derivative symbol $\dfrac{\mathrm{d}}{\mathrm{d} t}$ applied to a multivariate function $f: \mathbb{R}^N \rightarrow \mathbb{R}$, as $\dfrac{\mathrm{d} f}{\mathrm{d} t}$, it means that we are actually referring to the total derivative $\dfrac{\mathrm{d}(f \circ g)}{\mathrm{d} t}$. If we see the ordinary derivative symbol $\dfrac{\mathrm{d}}{\mathrm{d} t}$ applied to a univariate function $f: \mathbb{R} \rightarrow \mathbb{R}$, then it remains unchanged.


  • A Mathematical Exploration of Norton’s Dome and Determinism in Classical Mechanics

    A Mathematical Exploration of Norton’s Dome and Determinism in Classical Mechanics

    Note: This post is an English adaptation of my original Chinese article (URL). Some parts have been modified for clarity, cultural relevance, or to better fit the English-speaking audience.

    Let’s explore this from a mathematical perspective:

    First, when we say that classical mechanics follows determinism, mathematically, it means the following:

    Within the frame of classical mechanics, the mechanical differential equations of any system must always have a solution, and that solution is unique.

    However, it is important to note that this does not imply that these mechanical differential equations must satisfy the sufficient conditions of the Existence and Uniqueness Theorem (for ODEs, this would be the Picard-Lindelöf Theorem or the Cauchy Existence and Uniqueness Theorem, among others; for PDEs, it could be the Cauchy-Kowalevski Theorem or the Lax-Milgram Theorem, among others). Since the sufficient conditions of the Existence and Uniqueness Theorem are not necessary conditions, we cannot prove that a differential equation lacks a unique solution. For instance, some ODEs may not satisfy Lipschitz continuity, but their solutions may still exist and be unique.

    Now, for the Norton’s Dome problem, its mechanical differential equation is as follows (note, we are only considering the tangential equation, as we are more interested in how the ball moves along the surface of the dome. Here, $\vec{r}(t)$ represents the displacement vector from the apex of the dome to the position of the ball along its surface. Due to the radial symmetry of the geometric model, we can use the scalar $r(t)$ to simplify the calculations):

    $$
    \frac{d^2 r(t)}{dt^2} = \sqrt{r(t)}, \quad \left. \frac{dr(t)}{dt} \right|_{t=0} = 0 , \quad r(0) = 0\\
    $$

    Mathematically, we can verify (details omitted here for brevity) that the function on the right-hand side of the differential equation satisfies the Continuity for $r\ge0$, which guarantees the existence of at least one solution. However, the function does not satisfy the Lipschitz Continuity at $r=0$, which means we cannot guarantee the uniqueness of the solution.

    Once again, to emphasize: since these conditions are sufficient but not necessary, we cannot prove that the differential equation lacks a unique solution.

    So, let’s try solving it anyway (perhaps there is a unique solution, who knows? Haha). But in the end, we find, unfortunately, that there are infinitely many solutions.

    $$
    r(t) = \begin{cases} 0, & \forall \ t<t_0 \\ \dfrac{1}{144}(t – t_0)^4, & \forall \ t \geq t_0 \end{cases}, \quad \text{where } t_0 \in \mathbb{R}\\
    $$

    From a physical standpoint, constructing such a perfect system is likely impossible. It’s akin to assuming a perfect spherical object placed on a perfectly flat surface and calculating the pressure distribution. However, we know that in reality, the surface of the sphere must curve, otherwise, we would obtain an infinite pressure value.

    Updated: 2024-09-11

    I’ve seen some responses and comments suggesting that Norton’s Dome can be resolved by applying Newton’s 1st Law, leading to the conclusion that classical mechanics does adhere to determinism. I’d like to offer my perspective on this from a mathematical standpoint.

    First, mathematically speaking, Newton’s 2nd Law is essentially a definition of force. I recall reading in a book that if we were to remove the concept of force entirely and rely solely on $\dfrac{\mathrm{d} \vec{p}}{\mathrm{d} t}$, all the results of physics would remain unchanged.

    Similarly, Newton’s 1st Law is simply a special case of the 2nd Law where $\vec{F} = 0$. In fact, Newton’s 1st Law cannot hold prior to the 2nd Law, because before we’ve defined force, we cannot even interpret $\vec{F} = 0$. Thus, mathematically, Newton’s 2nd Law is more fundamental. Moreover, Newton’s 1st Law is not a definition but rather a proposition, and it is a true proposition, meaning it’s a theorem (based on its importance level).

    As such, Newton’s 1st Law cannot solve this issue. The core problem is that, based on the displacement solution $r(t)$, we can derive the acceleration $a(t)$:

    $$
    a(t) = \frac{d^2 r(t)}{dt^2} = \begin{cases} 0, & \forall \ t<t_0 \\ \dfrac{1}{12}(t – t_0)^2, & \forall \ t \geq t_0 \end{cases}, \quad \text{where } t_0 \in \mathbb{R}\\
    $$

    We can further derive the force $F(t)$:

    $$
    F(t)=ma(t) = m\frac{d^2 r(t)}{dt^2} = \begin{cases} 0, & \forall \ t<t_0 \\ \dfrac{m}{12}(t – t_0)^2, & \forall \ t \geq t_0 \end{cases}, \quad \text{where } t_0 \in \mathbb{R}, \quad m \in \mathbb{R}^+ \\
    $$

    Clearly, for $t \geq t_0$​, the force $F(t)$ is not a constant but a variable. Thus, if you wish to apply Newton’s 1st Law, it only holds for $t \le t_0$, since during this time $F(t)=0$, satisfying the conditions of Newton’s 1st Law. However, as soon as $\ t > t_0$​, the force becomes $F(t)\ne0$, and Newton’s 1st Law no longer applies.

    This shows that Newton’s 1st Law alone is insufficient to resolve the Norton’s Dome problem.


  • Why Use L2 Norm Instead of L1 Norm in Loss Functions?

    Why Use L2 Norm Instead of L1 Norm in Loss Functions?

    Have you noticed that, in many applications, MSE (Mean Squared Error), RMSE (Root Mean Squared Error) and SSE (Sum of Squared Error) are often the preferred choice for the loss function. But why is this the case? Why do we favor the L2 norm over the L1 norm, such as Mean Absolute Error (MAE)?

    For a linear regression model, the answer is obvious — Gauss-Markov Theorem directly implies that L2 norm error is inside the best linear unbiased estimator. But in practice, not all models we work with are linear regression models…

    Consider the loss function in some machine learning models (typically non-linear), which is often defined as

    $$ \text{MSE} = \dfrac{1}{N}\sum_{i=1}^{N} \left( \left( y -\hat{y} \right)^2 \right )$$

    One might argue that L2 norm error emphasizes larger errors by squaring the residuals, effectively “zooming in” on significant deviations. But if that’s the case, why not use even higher powers which can penalize large errors more heavily, such as $ \dfrac{1}{N}\displaystyle\sum_{i=1}^{N} \left( \left( y -\hat{y} \right)^4 \right ) $

    Indeed, higher powers would penalize large errors even more. However, the preference for the L2 norm isn’t just about magnifying errors, now let’s delve into it!

    Usually, the goal in many statistical models is to find the function $f(\mathbf{x})$ that best describes the input $\mathbf{x}$ and the observed data, enabling accurate predictions and generalization to new data.

    To achieve this, we typically use Maximum Likelihood Estimation (MLE), which allows us to estimate the model parameters that make the observed data most probable. Specifically, when we maximize the likelihood function of the errors $\mathbf{\epsilon}$ — the differences between the model’s predictions and the observed data — we are finding the parameters that make these errors most likely under our model.

    Why? Because by maximizing the likelihood of these errors, we then can identify the parameters that most likely generated the observed errors. This approach is rooted in empirical evidence: It makes sense to believe the cases (to choose the parameters) that make the observed errors the most probable (that maximizes the likelihood function of the observed errors), as we have no reason to prefer less likely errors.

    For example, imagine your parents walk into your room five times, and each time they catch you playing computer games instead of doing homework 😂. They might conclude that you’ve been playing computer games for all day, even though you actually spent hours doing homework and just happened to take a break at the wrong moments (what a bad excuse btw😂)… Here, they’re maximizing the likelihood of the “variable” — their assumption that you’re always gaming — because those were the moments they observed, and they don’t think that is a rare coincidence. In reality, you were just unlucky, but based on the evidence they have, their conclusion is the most probable one by applying MLE.

    So, typically, the statistical model’s goal is to find $\hat{y}$ such that:

    $$
    \hat{y} = \arg \left ( \max_{y} \Big ( L(\epsilon) \Big ) \right )
    $$

    where

    • $\hat{y}$ is the set of expect model’s best outputs which $\hat{y} = \{\hat{y}_1,\hat{y}_2,\cdots, \hat{y}_N\}$
    • $y$ is the set of observed data which $y = \{y_1, y_2, \cdots, y_N\}$
    • $L(\epsilon)$ is the joint likelihood of every individual error which $L(\epsilon) = L\left (\displaystyle \bigcap^{N}_{i=1} \epsilon_i \right )$
    • $\epsilon_i$ is individual error which $\epsilon_i=\hat{y}_i-y_i$

    For simplicity and to make the model computationally feasible, we assume every individual error in $\epsilon$ to be statistically independent, which $L(\epsilon) = \displaystyle \prod^{M}_{i=1} L(\epsilon_i) $, resultantly:

    $$
    \hat{y} = \arg \bigg ( \max_{y} \Big ( \displaystyle \prod^{N}_{i=1} L(\epsilon_i) \Big ) \bigg )
    $$

    Taking the logarithm to simplify the product into a sum (and because the logarithm is a strictly increasing monotonic function, which $\forall x_1, x_2 \in \mathbb{R}^{+}, \, x_1 < x_2 \implies \log(x_1) < \log(x_2)$, so the maximization is preserved):

    \begin{align*}
    \hat{y} &= \arg \bigg ( \max_{y} \bigg ( \log \Big ( \displaystyle \prod^{N}_{i=1} L(\epsilon_i) \Big ) \bigg ) \bigg ) \\
    \hat{y} &= \arg \bigg ( \max_{y} \bigg ( \sum^{N}_{i=1} \Big ( \log \big ( L(\epsilon_i) \big ) \Big ) \bigg ) \bigg ) \\
    \end{align*}

    Here, we assume that every individual error follows a normal distribution, which $L(\epsilon_i) = \dfrac{1}{\sqrt{2\pi \displaystyle\sigma_i^2}} \ \exp\left(-\dfrac{\epsilon_i^2}{2\sigma_i^2}\right)$, with the mean of every individual error is $0$ and homoscedasticity which $\sigma_1=\sigma_2=\cdots=\sigma_n=\sigma$. Because each error can be seen as the sum of smaller i.i.d. (identically distributed and independent) variables, then applying the Central Limit Theorem implies every individual error tends to follow a normal distribution when taking the limit as the total number of variables approaches infinity.

    \begin{align*}
    \hat{y} &= \arg \bigg ( \max_{y} \bigg ( \sum^{N}_{i=1} \Big ( \log \big ( L(\epsilon_i) \big ) \Big ) \bigg ) \bigg ) \\
    &= \arg \left( \max_{y} \left( \sum_{i=1}^{N} \left( -\frac{1}{2} \log(2\pi\sigma_i^2) -\frac{\epsilon_i^2}{2\sigma_i^2} \right) \right) \right) \\
    &= \arg \left( \min_{y} \left( \sum_{i=1}^{N} \left( \frac{1}{2} \log(2\pi\sigma_i^2) + \frac{\epsilon_i^2}{2\sigma_i^2} \right) \right) \right) \\
    &= \arg \left( \min_{y} \left( \frac{1}{2} \sum_{i=1}^{N} \log(2\pi\sigma_i^2) + \frac{1}{2} \sum_{i=1}^{N} \frac{\epsilon_i^2}{\sigma_i^2} \right) \right)\\
    &= \arg \left( \min_{y} \left( \frac{1}{2} \sum_{i=1}^{N} \log(2\pi) + \frac{1}{2} \sum_{i=1}^{N} \log(\sigma_i^2) + \frac{1}{2} \sum_{i=1}^{N} \frac{\epsilon_i^2}{\sigma_i^2} \right) \right) \\
    &= \arg \left( \min_{y} \left( \frac{N}{2} \log(2\pi) + \frac{N}{2} \log(\sigma^2) + \frac{1}{2\sigma^2} \sum_{i=1}^{N} \epsilon_i^2 \right) \right) \\
    &= \arg \left( \min_{y} \left( \frac{1}{2\sigma^2} \sum_{i=1}^{N} \epsilon_i^2 \right) \right) \\
    &= \arg \left( \min_{y} \left( \sum_{i=1}^{N} \epsilon_i^2 \right) \right) \\
    &= \arg \left( \min_{y} \left( \sum_{i=1}^{N} \left (\hat{y}_i-y_i \right )^2 \right) \right) \\
    \end{align*}

    Given the above derivation, we see that minimizing the sum of squared errors is equivalent to maximizing the likelihood of the errors under the assumption that they follow a normal distribution with mean zero and constant variance. This directly leads to the use of the L2 norm (squared errors) in loss functions such as Mean Squared Error (MSE).

    However, it’s important to note that the L2 norm error may not be the best choice in all cases. Specifically, when the error distribution deviates from normality, the L2 norm’s assumptions break down.

    For example, in classification tasks where errors are often not normally distributed, so L2 norm error might lead to suboptimal results. In classification tasks, the errors are related to the incorrect classification of categories rather than continuous deviations, therefore the data typically follow Categorical Distribution. Here, the loss function can be more appropriately modeled by Cross-Entropy. Or if the data follow the Laplace Distribution, then picking L1 norm error in the loss function would be a better option. (Note: You can derive those results by applying the similar math strategies.)


  • Intro to Git, Github and VSCode

    Intro to Git, Github and VSCode

    Hi, this is Louis Liu. In this tutorial, I will guide you through some basic operations in Git, GitHub, and VSCode. (The Mandarin Translation is on the second page.)

    If you haven’t yet completed the LICENSE signing for the Echo-Land game project under the CruxAbyss game development team, please make sure to do so first. Before signing, you’ll need to familiarize yourself with some fundamental GitHub operations, such as:

    1. What are Git and GitHub
    2. What is a Repository (Repo) in GitHub
    3. What is an Issue in a GitHub Repo
    4. What is a Pull Request (PR) in a GitHub Repo
    5. How to modify, add, or delete files in a GitHub Repo

    Once you have a good understanding of these operations, you’ll be ready to complete the signing process on your own.

    What Are Git and GitHub

    Git is a distributed version control system for code.

    Let’s start by understanding what a “version control system for code” means.

    Essentially, Git acts as a historical recorder for your code. Why do we need this? In real-world development projects (coding), it’s almost impossible to write all the code at once and have the entire project running smoothly. Typically, we modularize the code, breaking down a large task (large codebase) into smaller tasks (smaller pieces of code) that are handled separately, and then gradually integrating these smaller pieces into the larger codebase.

    At this point, Git becomes incredibly important as a historical recorder for your code because it helps you document your progress at various stages. For example, if your manager asks you to build a robot that can automatically send and receive emails, your first step should be to break down this large task: “a robot that can automatically send and receive emails” into two smaller tasks: “a robot that can automatically receive emails” and “a robot that can automatically send emails.” Let’s say you work on the “receive emails” part first. Once completed, wouldn’t it be wise to save your progress? This is where Git comes in handy — you can use Git to record the current state of your code and then move on to the next task, “a robot that can automatically send emails.”

    You might wonder: Why do I need to record this? Can’t I just complete the two tasks separately without using Git?

    Yes, you could, but can you guarantee that while working on the second task, you won’t accidentally modify the code for the first task? For instance, while writing code for the “send emails” functionality, you might suddenly realize that you could optimize the code for the “receive emails” part, so you make some changes. But then you find out that your optimization was entirely wrong, or you accidentally deleted some of your previous code, causing the program to stop running. Now, you want to revert to the state when you just finished writing the “receive emails” functionality to compare and figure out what went wrong. You start using Undo (Ctrl + Z or Command + Z), but find that you can’t get back to that exact state. Now, you’re left staring at your broken code, forced to painstakingly fix it.

    But what if you had used Git? It would be incredibly convenient, you could simply use Git to revert to the last recorded state of your code and compare the differences between the last version and your current one. That’s why Git is essential in almost all large-scale project developments.

    Now, why is Git called “distributed”?

    Because Git allows multiple developers to collaborate on the same project. For example, you can share your project along with its Git repository with others, and everyone can work on it simultaneously, optimizing code, proposing new features, and more. Git allows for code comparison, branch creation, code merging, and so on.

    GitHub is a platform that integrates Git for hosting code repositories.

    This platform provides a way for developers worldwide to collaborate on various projects, with added functionalities and features.

    That’s why we host our game project files on GitHub: firstly, it has Git to help us record the historical state of all files in the project. Additionally, GitHub’s built-in features like webhooks and code review tools can significantly enhance our game development process.

    What Is a Repository (Repo) in GitHub

    In GitHub, a Repository (often abbreviated as Repo) is essentially a “code repository.” This is where all the files and their history related to a project are stored. For instance, the game project we’ve uploaded to GitHub is currently one of the Repositories in our GitHub account, as shown in the image below:

    Repositories are central to how GitHub works. They act as the home for your project’s files, including source code, documentation, and any other assets related to the project. Within a Repo, you can track changes to your files over time, collaborate with others, and manage different versions of your project.

    What Is an Issue in a GitHub Repo

    Imagine this scenario:

    You’re browsing GitHub, looking for some interesting code projects to try out. Suddenly, you stumble upon a repository (Repo) that contains a Canvas bot that automatically completes your homework. You’re instantly intrigued! You download the Repo to your local machine and follow the instructions in the repository’s README file to learn how to use the bot to do your Canvas assignments.

    (Quick note: What is a README file? It’s essentially a “User Guide” that most repositories include. The reason it’s called “READ ME” is that the code author wants to ensure others understand what the Repo does. So the README contains an introduction to the Repo and details on how to use it.)

    However, as you run the code from the Repo, you encounter an error! You’re confident that you’ve followed every step outlined in the README file. This likely means one of two things: either the author’s code has a problem, or there’s an issue with the README instructions. Either way, the issue lies within the files of the Repo — something is wrong or there’s a bug. Since you’ve discovered this problem and would like the author to fix it (Come on!! This bot could help you with your homework!!), you can go to the GitHub repository’s Issues section to report this problem and provide feedback on the bug. If you have a bit more technical skill, you could even debug the code, identify the exact source of the error or bug, and then report it via an Issue.

    Here’s an example of where you would submit/report an Issue on GitHub:

    On GitHub, here is the “Issues” tab you may click on to report an issue
    Here is an example of a reported issue of a Repo

    It’s important to note that in the Issues section of a GitHub repo, you’re not just limited to reporting bugs. You can also suggest improvements to the code or request the addition of new features. For example, you might be very satisfied with the Canvas bot that automatically does your homework, but you also wish it could help you complete online Canvas exams. Since this feature isn’t currently available in the repository, and you might not have the coding skills to add it yourself, you can submit a feature request in the Repo’s Issues section. This way, you can inform the code author of your desire for this functionality, and they may consider adding it in the future.

    Overall, here are the procedures to open an issue of a Repo on Github

    1. Navigate to the Repo: Go to the GitHub repository where you encountered the issue or want to suggest an improvement.
    2. Access the Issues Tab: Click on the “Issues” tab, typically located near the top of the repository page.
    3. Create a New Issue: Click the “New Issue” button to start reporting your problem or suggesting a new feature.
    4. Describe the Issue or Request: Give your issue a clear title and provide a detailed description. If you’re reporting a bug, include information about what you were doing when you encountered the error, any relevant error messages, and steps to reproduce the issue. If you’re suggesting a feature, explain why the feature would be useful and how it could be implemented.
    5. Submit the Issue: Once you’ve filled out the details, click “Submit new issue” to send it to the repository’s maintainers.

    What is a Pull Request (PR) in a GitHub Repo?

    Imagine this scenario:

    You’ve created a bot that automatically completes assignments on Canvas, and you’re really pleased with it. However, you also wish that this bot could help you complete Canvas online exams, but the current repository (repo) doesn’t include this feature yet. However, being a skilled developer, you’re confident that you can add this new functionality to the repo. So, you spend a few days improving the repo you downloaded locally, and you successfully implement the feature that enables the bot to take online exams on Canvas! Feeling generous, you realize that such a tool shouldn’t be kept to yourself — it should benefit all students!

    You decide to upload your improved repo to GitHub. But there’s a catch: you can’t directly modify the original author’s repo on GitHub because you don’t have the necessary permissions. Also, creating a new repo and uploading it wouldn’t be appropriate because your code is based on the original author’s work, where they created the bot that completes assignments on Canvas. Therefore, following international conventions and basic ethical guidelines, you should submit a Pull Request (PR) to the original author’s repo on GitHub. If the original author accepts your PR, your code will be merged into the repo, and your name will be added to the list of contributors for that project.

    But this raises the question: What exactly is a Pull Request (PR)?

    A PR is essentially a request to the original author, asking them to consider integrating your changes into the current repository. It’s as if you’ve written a new poem in the style of the “Tang Poems” and submitted it to the “300 Tang Poems” collection. If the curator of the “300 Tang Poems” accepts your submission, the collection would become “301 Tang Poems,” and you would be recognized as one of the contributors.

    OK, so how do you submit a PR? Can you just click the Pull Request button on the repo on Github?

    Actually, it’s not that simple. Please read the next section!

    How to Modify, Add, or Delete Files in a GitHub Repository

    Now, let’s simulate a scenario where you’ve made changes to files in a GitHub repository and want to submit a Pull Request (PR) for those changes.

    First, let’s clarify one point: if you’ve downloaded the repository to your local machine and made changes there, you won’t be able to submit a PR directly. Why? Because GitHub requires that the repository you’re modifying must be connected to the same Git repository to submit a PR.

    You might wonder, “Oh, so should I just create a new Git repository for my local changes?”

    Absolutely not! If you create a new Git repository for your local changes, it will be a completely new Git instance, different from the original author’s repository. The history recorded by your Git (version control system) will only include the changes you’ve made, not those made by the original author. This is because your Git only starts recording from the state of the code you initially downloaded (like starting a test from 60% completion without knowing what happened from 0% to 60%). On the other hand, the original author’s Git tracks all their changes, but none of yours (like a test recording only the progress from 0% to 60%).

    A shared Git repository should record the entire process from 0% to 100%, without missing any steps!

    So, how do you merge the changes you’ve made (from 60% to 100%) with the original author’s changes (from 0% to 60%)?

    Answer: You need to start by copying the original repository, including its Git history, to your local machine, and then make your modifications. You should not create a new Git repository!

    But why is it necessary to use the same Git repository to make improvements to a repo? What if I don’t want to use the same Git repository?

    Answer: You can indeed choose not to use the same Git repository, but:

    1. If you intend to make your improved repository public but use a different Git repository, it effectively erases the contributions (from 0% to 60%) of the original author, which is generally considered unethical.
    2. From a collaboration standpoint, this approach can lead to a lack of consistency, leaving other developers unsure which repository to contribute to. For instance, you might improve the code’s readability, while someone else adds a new feature. If you’re not using the same Git repository, the project could split into two separate repositories, preventing the integration of these different improvements and reducing overall development efficiency.

    Remember we mentioned earlier that Git is “distributed”? Git allows multiple developers to collaborate on the same project, but the key is that you must use the same “version control system” or “historical recorder for code” to ensure that everyone is working on the same repository.

    Example: Imagine A and B both borrowed C’s homework to copy, but since C is known as the class underachiever, his homework typically scores only 60%. A and B must be very careful while copying to avoid making the same basic mistakes. After making their own corrections, they both finish the homework. However, since A and B are very generous, they decide to share their corrected versions with the whole class. The problem is, whose version should be shared — A’s or B’s? If one is shared and later D, the top student, wants to improve it further, what happens to the other version? To avoid this issue, A and B decide to compare their work and combine their efforts into one perfect version (similar to merging two repos through a PR).

    This example reflects the principle that when collaborating on a repository, everyone must use the same Git. If A and B both share their versions, it’s like splitting one modified repository into two, as they didn’t use the same Git. This forces the rest of the class to choose between the two, which is inefficient. By combining their efforts, they ensure that others can benefit from a single, improved version — just as using the same Git allows for a unified repository.

    Now that we’ve established the importance of using the same Git when collaborating on a repository, let’s dive into the practical steps.

    Since you need to copy the original repository along with its Git history to your local machine from the start, how do you do this? A normal download won’t include the Git history. Therefore, you need to click “Fork” next to the repository. This will copy both the original repository and its Git history to your GitHub account.

    Let’s go through this step together. Follow along with this tutorial using a sample repository designed for learning GitHub, no need to worry about causing any issues.

    First, click “Fork” on the repository page. See the image below for reference:

    After clicking, you’ll see a new page. Don’t change anything, simply click the green “Create fork” button in the lower right corner:

    Once you’ve clicked, wait a few seconds, and you should see the following page:

    In the image, the information highlighted in the red box indicates that this is the repository you’ve forked (in this case, Deep0Thinking forked the Repo). You can compare it with the original author’s repository to see the differences (in this case, this forked Repo is up to date, so currently no changes between the forked Repo and the original Repo).

    Now that you’ve forked the repository, the next step is to clone it to your local machine. This will allow you to make changes, add new features, or delete files, all while maintaining a connection to the original Git history.

    To clone your forked repository:

    1. Make sure you have “git” installed on your computer, if you don’t have git installed, please check here: https://git-scm.com/downloads

    2. Go to your forked repository on GitHub and click on the “Code” button. You’ll see an option to clone using HTTPS, SSH, or GitHub CLI. Copy the URL provided (by clicking on that icon next to the URL inside the red box):

    3. Open your terminal (on MacOS, you can press command + spacebar, then type in terminal and press return to open your terminal).

    4. In terminal, type the following command:

    git clone <your-copied-URL>

    This command will create a local copy of the repository on your computer.

    5. Navigate into the cloned repository directory:

    cd <repository-name>

    Now that your repository is cloned locally, you can start by navigating to the cloned repository directory (your project folder). Once you’ve opened this folder in your preferred text editor (in this case I’ll be sticked with VSCode to demonstrate), go ahead and write something in it, anything you like, just to create a change.

    Next, you’ll need to save the file locally (on MacOS, you can press command + s to save a file locally), which will register the change you’ve made. Once the change is saved locally, you’ll see a red icon or indicator in VSCode, signaling that there are uncommitted changes for Git in your working directory.

    (Here, I did some changes to the `ok.md` file)

    Now, let’s prepare to commit your changes. In the Source Control panel, click on the red-highlighted icon (typically a “+” symbol) next to that ok.md file. This action stages the file, indicating that you want to include this change in your next commit.

    If you’ve modified multiple files and only want to commit some of them, you can selectively stage individual files by clicking the “+” icon next to each file you wish to include. This selective staging is useful when you’ve made changes across different files but want to commit only the changes that are complete and ready for version control.

    After staging your changes, the next step is to commit them. In the message box under “Source Control,” write a clear and concise commit message. This message should briefly describe what changes were made to the files you’ve staged. Note that writing a commit message is mandatory; without it, Git will not allow you to commit your changes.

    It’s essential to develop the habit of writing meaningful commit messages. These messages act as a log for your code’s history, and vague or unclear messages can make it difficult to track the progress of your project or understand the purpose of past changes. Properly written commit messages make it easier to manage your project over time.

    Once you’ve written your message, click the green “Commit & Push” button. This action records your changes in the Git history and pushes them to your remote repository (e.g., on GitHub).

    The “Commit changes” action in Git is simply a way of recording your changes — it’s not the same as creating a Pull Request (PR). A PR is a formal request to merge changes from one repository (a forked one of the original repo) into another (the original repo).

    Commit changes are typically minor and incremental, helping to keep a record of small updates or progress steps (think of it as taking snapshots of your work to prevent data loss). In contrast, a PR is more significant, akin to submitting a complete and finalized version of your work for review and integration into the main project.

    You should use commit changes regularly to keep track of your progress. However, reserve PRs for when you have completed a substantial part of your work that meets specific project goals.

    Now, let’s create a PR to see how it works. After you’ve made and committed several changes that fulfill a certain project objective, click on the icon highlighted in red (usually labeled “Pull Requests”) in GitHub or in your GitHub repo’s interface:

    You’ll be directed to a new page where you can create a PR. Here, you should:

    • Title: Provide a title that briefly summarizes the changes you are proposing to merge.
    • Description: In the description field, add detailed information about the changes. Explain what was modified, why the changes were made, and any other relevant context.
    • Labels: Don’t forget to click on the “Labels” section and select the appropriate label if possible (like “Bug Fixed”, “Typo Fixed”…). This categorizes your PR, making it easier for reviewers to understand the scope and purpose of your changes.

    After filling out these fields, click the “Create pull request” button.

    Once the PR is created, it will appear on the PR page of the repository, and the repository’s maintainers will be notified for review:

    The maintainers will review the PR based on its contribution and relevance to the project. If the changes meet the necessary standards, the PR will be merged into the original repository.

    Remember, a PR is essentially a request to merge the code from your forked repository into the original one. If the PR is accepted, both repositories will be synchronized, with the original repository incorporating your changes.

    Additional Notes

    • Commit Messages: Aim to be as descriptive as possible. Instead of writing “fixed bugs,” you might write “fixed null pointer exception in email processing module.” This level of detail will save you and your team time when reviewing past commits.
    • Branching: Before working on a new feature, create a new branch. This keeps your work isolated until it’s ready to be merged.
    • Merge Conflicts: When working on a team, you might encounter merge conflicts. These occur when changes from different branches conflict with each other. Git will require you to resolve these conflicts manually.

    With these steps, you should now have a solid foundation for using Git, GitHub, and VSCode in your development workflow. Happy coding!!!!

    Pages: 1 2


  • How is Diandian (点点) (A cat my family rescued 2 years ago) now?

    How is Diandian (点点) (A cat my family rescued 2 years ago) now?

    Two years ago, my family and I embarked on an unexpected journey that would forever change our lives. It began on a stormy night when we found a small, injured kitten struggling to survive. The experience, filled with challenges and moments of hope, has been one of profound learning and immense love.

    To share our story, I’ve uploaded a detailed video on Bilibili (on 2022-02-19 at 11:08:30), documenting the entire process of how we found, rescued, and nurtured this little life back to health. The video is a raw and honest representation of the events, spoken in Chinese, capturing every step of this emotional journey.

    If you prefer reading over watching, I’ve written a detailed account below, outlining the significant moments and reflections from this experience. Whether you choose to watch the video or read the text, I invite you to join us on this journey of recovery, resilience, and unconditional love.

    The story you’re about to see or read is more than just about saving a kitten; it’s a testament to the power of family, the kindness of the human spirit, and the incredible will to live that exists within all beings, no matter how small!!

    Thank you for taking the time to witness our story. Here are the links to the video on Bilibili and YouTube. For those who prefer reading, please find the complete narrative below.

    On February 7, 2022, my family found this poor little kitten lying inside our garden in a distressing condition during a heavy rainstorm. The kitten was severely injured, barely alive, and in dire need of help. It was a heart-wrenching scene: the kitten was drenched, injured, and had been attacked by a larger cat, presumably to claim territory. Thankfully, my family intervened just in time, scaring off the attacker and bringing the kitten into our house for warmth and safety.

    My parents immediately took action, drying the kitten and providing a warm, comfortable space for it to rest. Despite its weak state, the kitten showed a strong will to live. It was heart-breaking to see it struggle; the injuries were severe, affecting its ability to move and even swallow properly due to a throat injury. Yet, with careful and loving care from my family, the kitten began to show signs of recovery, although the journey was slow and fraught with challenges.

    In the beginning, the kitten could hardly eat due to its injuries, but with patience and tender care, it slowly started to regain strength. My parents went above and beyond, ensuring the kitten was well-fed with suitable milk and gradually introducing soft food. It was a delicate process, given the extent of the kitten’s injuries, including nerve damage and physical trauma.

    Over time, the kitten, which we came to cherish as a symbol of resilience and hope, began to exhibit signs of improvement. It was not just a physical recovery; the kitten brought a new sense of joy and purpose into our home. We were all invested in its recovery, celebrating every small step forward, from the first time it stood on its own to the moment it began to eat without assistance.

    The journey was not without its setbacks. There were moments of doubt and fear, times when we wondered if we were doing enough or if the kitten would fully recover. But through it all, the bond between us and the little fighter grew stronger. The kitten’s will to live and our dedication to its recovery created an unbreakable bond.

    Today, two years later, the kitten is no longer just a kitten but a vibrant, loving member of our family. Its recovery was a miracle, a testament to the power of love, care, and resilience. The kitten, now fully grown, has overcome its traumatic start to life and has become a source of endless joy and laughter for our family:

    This experience taught us invaluable lessons about compassion, the importance of helping those in need, and the incredible strength of even the smallest creature. It was a reminder that every life is precious and worth saving.

    As I write this update, the once fragile kitten is curled up comfortably beside my family, purring contentedly.

    To everyone who supported us through this journey, whether by offering advice, sending well-wishes, or simply keeping us in your thoughts, we extend our deepest gratitude! This story is not just about the survival of a little kitten; it’s a story of hope, love, and the incredible difference a small act of kindness can make.

    Thank you for being part of our journey!!


  • Cracking the Logic Gates Construction Using the Knowledge from Mathematical Logic

    Cracking the Logic Gates Construction Using the Knowledge from Mathematical Logic

    Recently, I’ve started exploring Mathematical Logic, guided by Elliott Mendelson’s “Introduction to Mathematical Logic, 6th Edition”. One fascinating fact I found in the textbook is that “Every truth function is generated by a statement form involving the logical connectives in a functional complete set“. This idea sparked my interest, leading me to connect it with experiences from my past.

    Before diving deeper, please let me introduce some prerequisite concepts to you.

    Formally, in Mathematical Logic:

    • A truth function is defined as $f: \{0, 1\}^n \to \{0, 1\} $, where $0$ represents False (F) and $1$ represents True (T).
    • A propositional variable is the variable $\in \{0, 1\}$, equivalently, it is the variable that can either have the True or False value.
    • Well-formed formulas (WFFs) are expressions defined as follows:
      • A propositional variable is a WFF.
      • If $A$ and $B$ are WFFs, then $A \wedge B, \neg B, \neg A$ are also WFFs.

    Then we proceed to introduce the following theorems:

    $\textbf{Theorem 1}$

    Every truth function is generated by a WFF involving the logical connectives $\neg$ (NOT), $\wedge$ (AND) and $\vee$ (OR). Equivalently, the set $\{\neg, \wedge, \vee\}$ constitutes a functionally complete set of logical connectives.

    $\textbf{Proof}$

    For any truth function $f(x_1,x_2,\cdots,x_n)$ where $x_1,x_2,\cdots,x_n \in \{0, 1\}$, we can represent $f(x_1,x_2,\cdots,x_n)$ in a truth table with $2^n$ rows, since the total number of combinations of $x_1,x_2,\cdots,x_n$ is $2^n$ and each combination produces a corresponding output of $f(x_1,x_2,\cdots,x_n)$.

    For each row in the truth table where the function $f(x_1,x_2,\cdots,x_n)$ outputs $1$, we can construct a conjunction $\wedge$ (AND) that corresponds to that particular combination of inputs.

    More generally, for a given row $i \in \{1,2,\cdots, 2^n\}$, we define a conjunction $C_i$ as follows: $C_i = U_{i,1} \wedge U_{i,2} \wedge \cdots \wedge U_{i,n}$, where $U_{i,j} = x_{i,j}$ if $x_{i,j} = 1$, else $U_{i,j} = \neg x_{i,j}$ if $x_{i,j} = 0$, where $j \in \{1,2,\cdots,n\}$.

    After setting up $C_{1}, C_{2},\cdots, C_{n}$, we take the disjunction $\vee$ (OR) of all such conjunctions corresponding to the truth rows where the function $f$ outputs $1$, assume there are $m \in \{1,2,\cdots,n-1\}$ such rows (The situations of $m=0$ and $m=n$ are discussed below.). This forms a statement in disjunctive normal form (DNF) representing our original truth function $f$. This DNF statement, denoted as $D$, is defined as $D = C_1 \vee C_2 \vee \cdots \vee C_m$, where each $C_k$ (where $k \in \{1,2,\cdots,m\}$) corresponds to one of the rows where $f$ outputs $1$, and $m$ is the number of such rows.

    If $m=0$, in other words, if $f$ always outputs $0$, then $D$ can be defined as a contradiction (for example: $D = x_1 \wedge \neg x_1$). If $m=n$, in other words, if $f$ always outputs $1$, then $D$ can be defined as a tautology (for example: $D = x_1 \vee \neg x_1$).

    Accordingly and obviously, we have $f(x_1,x_2,\cdots,x_n) \iff D$. Then since $D$ is a corresponding wff involving the logical connectives $\neg$ (NOT), $\wedge$ (AND) and $\vee$ (OR), therefore “Every truth function is generated by a WFF involving the logical connectives $\neg$ (NOT), $\wedge$ (AND) and $\vee$ (OR).”

    $\Box$

    $\textbf{Example 1}$

    $$\begin{array}{c}
    x_1 & x_2 & x_3 & f\left(x_1, x_2, x_3\right) \\
    \mathrm{F} & \mathrm{F} & \mathrm{F} & \mathrm{T} \\
    \mathrm{F} & \mathrm{F} & \mathrm{T} & \mathrm{T} \\
    \mathrm{F} & \mathrm{T} & \mathrm{F} & \mathrm{F} \\
    \mathrm{T} & \mathrm{F} & \mathrm{F} & \mathrm{F} \\
    \mathrm{F} & \mathrm{T} & \mathrm{T} & \mathrm{F} \\
    \mathrm{T} & \mathrm{T} & \mathrm{F} & \mathrm{F} \\
    \mathrm{T} & \mathrm{F} & \mathrm{T} & \mathrm{F} \\
    \mathrm{T} & \mathrm{T} & \mathrm{T} & \mathrm{F}
    \end{array}$$

    Then $$f(x_1, x_2, x_3) \iff D = (\neg x_1 \wedge \neg x_2 \wedge \neg x_3) \vee (\neg x_1 \wedge \neg x_2 \wedge x_3)$$

    $\Box$

    Here is the Python program I wrote. This program uses AND, OR and NOT gate, based on $\textbf{Theorem 1}$, to construct the equivalent DNF of any logic gate.
    # python3
    
    def convert_to_dnf(truth_table):
        D = []
        for row in truth_table:
            if row[-1] == 1:
                terms = []
                for i, val in enumerate(row[:-1]):
                    if val == 1:
                        terms.append(f"x_{i+1}")
                    else:
                        terms.append(f"¬x_{i+1}")   
                if terms:
                    C_i = " ∧ ".join(terms)
                    D.append(C_i)
        if D:
            dnf_structure = f'({") ∨ (".join(D)})'
        else:
            dnf_structure = "(x_1 ∧ ¬x_1)"
    
        return dnf_structure
    
    # Here we use the truth table from Example 1
    truth_table = [
        [0, 0, 0, 1],
        [0, 0, 1, 1],
        [0, 1, 0, 0],
        [1, 0, 0, 0],
        [0, 1, 1, 0],
        [1, 1, 0, 0],
        [1, 0, 1, 0],
        [1, 1, 1, 0],
    ]
    
    dnf_gate_structure = convert_to_dnf(truth_table)
    print("DNF:", dnf_gate_structure)

    $\textbf{Theorem 2}$

    The set $\{\downarrow \text{(NOR)} \}$ constitutes a functionally complete set of logical connectives.

    $\textbf{Proof}$

    According to the definition, $x_1 \downarrow x_2 \iff \neg (x_1 \vee x_2)$. By constructing and analyzing the corresponding truth table, we deduce that $\neg x_1 \iff (x_1 \downarrow x_1)$, $x_1 \wedge x_2 \iff (x_1 \downarrow x_1) \downarrow(x_2 \downarrow x_2)$ and $x_1 \vee x_2 \iff (x_1 \downarrow x_2) \downarrow(x_1 \downarrow x_2)$. Then apply $\textbf{Theorem 1}$ and the substitutions, clearly “The set $\{\downarrow \}$ constitutes a functionally complete set of logical connectives.”

    $\Box$

    $\textbf{Example 2}$

    Set

    $$\begin{align}
    A & = \bigg( \Big( \big( (x_1 \downarrow x_1) \downarrow (x_1 \downarrow x_1) \big) \downarrow \big( (x_2 \downarrow x_2) \downarrow (x_2 \downarrow x_2) \big) \Big) \downarrow \Big( \big( (x_1 \downarrow x_1) \downarrow (x_1 \downarrow x_1) \big) \downarrow \big( (x_2 \downarrow x_2) \downarrow (x_2 \downarrow x_2) \big) \Big) \bigg)\\
    B & = \bigg( (x_3 \downarrow x_3) \downarrow (x_3 \downarrow x_3) \bigg) \\
    C & = \bigg( x_3 \downarrow x_3 \bigg)
    \end{align}$$

    Then the function $f(x_1, x_2, x_3)$ in $\textbf{Example 1}$ can be rewritten as

    $$\begin{align}
    &f(x_1, x_2, x_3) \\
    \iff & D = (\neg x_1 \wedge \neg x_2 \wedge \neg x_3) \vee (\neg x_1 \wedge \neg x_2 \wedge x_3) \\
    \iff & D = \big( (x_1 \downarrow x_1) \wedge (x_2 \downarrow x_2) \wedge (x_3 \downarrow x_3) \big) \vee \big( (x_1 \downarrow x_1) \wedge (x_2 \downarrow x_2) \wedge x_3 \big) \\
    \iff & D = \bigg( \Big( \big( (x_1 \downarrow x_1) \downarrow (x_1 \downarrow x_1) \big) \downarrow \big( (x_2 \downarrow x_2) \downarrow (x_2 \downarrow x_2) \big) \Big) \wedge (x_3 \downarrow x_3) \bigg) \\
    & \vee \bigg( \Big( \big( (x_1 \downarrow x_1) \downarrow (x_1 \downarrow x_1) \big) \downarrow \big( (x_2 \downarrow x_2) \downarrow (x_2 \downarrow x_2) \big) \Big) \wedge x_3 \bigg) \\
    \iff & D = \bigg( A \downarrow B \bigg) \vee \bigg( A \downarrow C \bigg) \\
    \iff & D = \Bigg( \bigg( A \downarrow B \bigg) \downarrow \bigg( A \downarrow C \bigg) \Bigg) \downarrow \Bigg( \bigg( A \downarrow B \bigg) \downarrow \bigg( A \downarrow C \bigg) \Bigg)
    \end{align}$$

    $\Box$

    Applying $\textbf{Theorem 2}$ fully unlocks the potential to design any logic gate we desire! This concept took me back to October 2021, when I discovered “Turing Complete”, which is an amazing game on Steam dedicated to constructing fundamental stuffs in Computer Science (such as logic gates and circuits). Then I shared my excitement about this game on Zhihu.com, recommending it as an excellent introduction for those new to logic circuits.

    Below are some related screenshots.

    At that time, I actually found some of the construction problems in that game quite challenging (to me), so I was thinking that whether it is possible to build up an algorithm that can automatically construct new logic gates through a pattern of systematic combinations? And later on I was working on other academic stuffs (I checked my timeline and found myself was preparing for the IB and AP exams during that time, though those exams were later all canceled in Shanghai due to the quarantine unfortunately…) and completely forgot about this.

    This old idea resurfaced recently as I delved into Mathematical Logic, so I wrote this post…


  • Using Raspberry Pi to Build a US VPN Server for My Family in China

    Using Raspberry Pi to Build a US VPN Server for My Family in China

    Disclaimer: This post is based on my personal experience and is not sponsored or influenced by any platform or service mentioned.

    In this blog post, I’m going to share my experience and detailed process of setting up a Raspberry Pi as a VPN server for my family in China. Due to the “Great Firewall” of China (for a more detailed background on this, please refer to my previous post here), accessing services like Google and ChatGPT is always a big challenge for the internet users in China (including my family). This became even more pressing when, around December 2023, all ChatGPT access node IPs used by our ClashX VPN were blocked by OpenAI. This situation led me to seek alternative methods to restore unrestricted internet access for my family.

    To circumvent these restrictions, I decided to set up a VPN server using a Raspberry Pi. I placed the Raspberry Pi at my friend Ethan’s house, whom I thank for his and his wife Lily’s help!

    Why Raspberry Pi? I chose a Raspberry Pi due to its compact size, low power consumption, and affordability (the total price of the Raspberry Pi Kit I bought is 187.41$ after tax).

    (March 14, 2024: Update, I just uploaded a video of Raspberry Pi 5 (which recorded on January 26, 2024) to YouTube so you can see how small it is.)

    Why this VPN? WireGuard was chosen over OpenVPN for its simplicity, lighter nature and better performance, though both are viable options. I configured the Raspberry Pi using the CLI interface to maximize performance since a GUI consumes more resources. So for those looking to optimize their Raspberry Pi for VPN use, I recommend switching the “boot option” in “system config” to “text console” through sudo raspi-config.

    One critical aspect was configuring port forwarding and static routing in NAT to enable communication between the VPN clients and the server. Port forwarding was set to direct traffic from port 51820 by default(used by WireGuard) to the Raspberry Pi, enabling external VPN client connections. Meanwhile, port forwarding and static routing was necessary within the home network to guide traffic destined for the VPN network directly to the Raspberry Pi in the router’s NAT setting, ensuring proper internal communication and internet access. Incidentally, I chose CloudFlare as the DNS provider.

    And the Deco router in Ethan’s home has the ability to interact with IPv4 devices via NAT port forwarding, theoretically eliminating the need for Dynamic DNS (DDNS) for VPN connections, because the combination of the router’s IPv6 + the specified port number can create a definitive pathway for initiating communication and accessing the Raspberry Pi remotely.

    However, I heard that IPv6 supports better security features natively as more ISPs and devices are gradually shifting to IPv6. So I prefer using IPv6 for my Raspberry Pi’s remote SSH access (in my case, as I’m frequently updating and maintaining my custom-designed Discord bot (here) for my game dev team (CruxAbyss) hosted on the Raspberry Pi recently: Despite Cloudflare Workers is a popular choice for serverless code hosting (with the first 100,000 requests each day being free!), I prefer direct control in Raspberry Pi for frequent update at the current stage, particularly as the request volume my code would generate may exceed this number each day.), especially, I’m very interested in applying the real-time IP address updates for my Raspberry Pi to deal with the dynamic property of Ethan’s router’s IPv6 address assignments:

    The main challenge was dealing with dynamic IP addresses due to Ethan’s router (a Deco model) using DHCPv6. Assigning a static IPv6 to the router itself was not feasible due to the limitations of the router’s model and the potential security risks involved. Furthermore, I attempted to configure the router to reserve a static IPv6 address to the Raspberry Pi. However, I found that Ethan’s Deco router could only assign static IPv4 addresses, not IPv6. So this led to the necessity of implementing DDNS to keep the server accessible despite changing IP addresses. Thus, I resorted to using DDNS to ensure the SSH accessibility to my Raspberry Pi server regardless of the changes in its IPv6.

    Awkwardly, during the setup, I discovered that Ethan’s Deco router supported VPN settings (including VPN like OpenVPN) 😂, including DDNS, but its DDNS was intended for the router’s use, not the devices under it. Therefore, I used a custom CloudFlare-DDNS solution (the repo is here). Also, ensure to initiate the ddns configuration on the Raspberry Pi by first establishing an SSH connection to input the token, as manual entry can be pretty cumbersome…

    Forgot to mention, to enable SSH for Raspberry Pi, please execute sudo raspi-config, followed by sudo systemctl restart cron and sudo reboot. Initially, I recommend to connect both the Raspberry Pi and the controlling computer to the same network for SSH access. To enable SSH access under different networks later on, you need to make adjustments to the router’s firewall and Raspberry Pi’s UFW settings to permit SSH and VPN traffic, also ensuring port 22 is open for SSH connections. For IPv6 SSH connection, make sure both the client and server have IPv6 addresses and are configured to accept IPv6 connections. The device’s IPv6 connectivity can be checked using online tests such as here.

    Once you could access the SSH connection with Raspberry Pi, then make sure replace the “DROP” in “DEFAULT_FORWARD_POLICY” the UFW config file with “ACCEPT”, or the traffic coming from the VPN interface (for example, wg0) and destined for the internet won’t be forwarded. This would prevent your VPN clients (like your phone) from accessing external websites or any resource outside the Raspberry Pi itself!

    After configuring the VPN and resolving the networking issues, I recommend running pivpn debug to identify and resolve potential problems. This step is essential to ensure the VPN operates smoothly and securely.

    Note: For the CloudFlare users, a significant step was configuring the CloudFlare DDNS script without enabling the “proxied” option in your CloudFlare DNS record settings. This was crucial as the VPN service needed to recognize direct connection requests from clients (recall the public DNS name you previously input), not masked ones via CloudFlare’s DDoS protection services (the underlying mechanism involves CloudFlare’s proxy acting to overlay a masking IP onto your domain. You can verify this by pinging your proxied domain directly from the terminal, which reveals that the IPv6 address returned is not the actual IPv6 of your domain.). Ensuring the DNS records for the VPN were not proxied allowed for direct and secure connections to the Raspberry Pi server.

    However, I noticed that when I’m on an external network (outside my home), I can SSH into your Raspberry Pi using both its IPv4 and IPv6 addresses. But, when I’m at home and on the same local network as my Raspberry Pi, I can only SSH into it using its IPv4 address, as the SSH over IPv6 fails when I’m on the same local network. I think the most likely cause is that the router’s default settings were blocking or not routing IPv6 traffic correctly within the local network. As many home routers are configured primarily to handle IPv4 traffic internally.


  • I Switched From Github Pages to WordPress…

    I Switched From Github Pages to WordPress…

    Disclaimer: This post is based on my personal experience and is not sponsored or influenced by any platform or service mentioned.

    One of the most compelling reasons for my switch was the need for efficiency and a streamlined focus on content production. WordPress, with its intuitive panel and user-friendly interface, significantly reduced the time I spent on technical configurations and layout adjustments. Unlike my experience with GitHub Pages, where I found myself often entangled in Jekyll configurations and tweaking frontend languages, WordPress allowed me to concentrate more on crafting quality content, which is the heart of any blog.

    Transitioning from the static and somewhat rigid structure of GitHub Pages, I immediately noticed how the WordPress panel facilitated a smoother creative process. Its drag-and-drop functionality, along with a plethora of themes and customizable elements, made designing my blog an enjoyable rather than a cumbersome task.

    While I value the technical skills I acquired from managing my blog via GitHub Pages —- such as a deeper understanding of Jekyll and frontend languages (HTML, CSS and JavaScript), and even some Git usages — it’s essential to align one’s tools with one’s goals. Moreover, it’s worth noting that GitHub Pages is a free platform, making it an excellent starting point for those new to blogging or with limited resources. WordPress, on the other hand, provided me with a balance, offering a platform that’s easy to use yet powerful enough to cater to my evolving needs. However, the time I spent grappling with code on GitHub Pages was not in vain, it undoubtably endowed me with a solid foundation that now enables me to appreciate and utilize WordPress features more effectively.

    Upon my transition to WordPress, I quickly noticed an essential aspect: although customizing your site with specific styles and blocks might necessitate some familiarity with frontend languages, the WordPress community has already developed most of the necessary styles and blocks. This accessibility is a significant advantage, as it allows for the personalization and modification of these elements to suit your unique style and needs without requiring extensive coding knowledge. Moreover, if you’re inclined, there’s always the opportunity to dive into custom coding to further tailor and enhance your site.

    Furthermore, the WordPress community is vast and exceptionally supportive. The platform’s wide range of available extensions and plugins has dramatically simplified the process of adding new features to my site. I didn’t have to dive deep into extensive coding to implement enhancements. Like tools for SEO and interactive elements are readily available, which have been crucial in boosting my blog’s functionality and expanding its reach.

    Finally, my ambition to create a more interactive and engaging platform for my audience was a significant driver behind the move from a static site to a dynamic one. While GitHub Pages does offer some level of interactivity through the GitHub applications like comment app (giscus), WordPress provides a more integrated solution. As a more versatile and dynamic platform, WordPress has opened up avenues for real-time interactions, such as native commenting systems, polls, and other engaging elements that are more seamlessly integrated than on a static site like GitHub Pages. This shift towards a more backend-focused approach has allowed me to make my website more interactive with the audience in a way that static sites struggle to match.

    Switching from GitHub Pages to WordPress has been a transformative journey for my blog. While GitHub Pages served as a great starting point, WordPress has offered a more scalable, user-friendly, and interactive platform that aligns perfectly with my goals as a content creator. The transition was a step forward in making my blog more accessible, engaging, and enjoyable for my audience.

    In line with sharing my journey from GitHub Pages to WordPress, I recognize the value that GitHub Pages brought to my blogging experience, particularly for those who are just starting out or are more technically inclined. To aid others in their blogging endeavors, I’ve ceased updates on my GitHub Page, deep0thinking.github.io, but the repository remains accessible for educational purposes at Deep0Thinking/Deep0Thinking.github.io.

    For those interested in exploring or building a static site based on GitHub Pages, I’ve created a template, 2nd-Minima, which is a user-friendly, advanced template derived from the popular Jekyll-theme-Minima. This template is perfect for those unfamiliar with front-end programming and offers a simplified setup for your blogging journey. You can find this template and a comprehensive guide to using it at Deep0Thinking/2nd-Minima.

    The 2nd-Minima template provides a straightforward approach to blogging, with clear instructions for setup, customization, and deployment. From initial blog creation to integrating engaging features like the giscus comment system, the repository guides you through each step of the process. It also includes tips for personalizing your blog’s appearance and functionality, ensuring that even beginners can create an attractive and effective site!

    This resource is my way of giving back to the community that has supported me through my blogging journey! Whether you decide to stick with GitHub Pages or eventually transition to another platform like I did, I hope the 2nd-Minima template helps you find your footing in the vast world of blogging 🙂

    Remember, the best platform is the one that best serves your needs and those of your audience, so I encourage you to explore various platforms to find what best suits your needs. Happy blogging!


  • Competitive Mathematics — Factorization

    Competitive Mathematics — Factorization

    Note: This article is based extensively on the content of 《数学奥林匹克小丛书》, supplemented by my own insights and reorganized to cover additional topics not addressed in the original text. Therefore, it should be regarded as a newly compiled set of notes rather than a completely original work.

    Basics

    Definition

    The definition of “factorize $A$ over $B$” is: To write the polynomial $A$ as a product of several factors where each factor has coefficients in field $B$, and every factor in this expression is irreducible over the specified field.

    ($A$ is irreducible over $B$ means that “$A$ cannot be written as a product of at least two nonconstant polynomials with coefficients in $B$”.)

    Factorization depends on the field over which you are working. You can factorize over the rational, the real, the complex, or other fields, depending on your goals.

    Here are some examples of factorizations:

    $$

    \begin{aligned}

    &24 =2^3 \times 3 \\

    &a^2-5b^2 =(a+\sqrt{5}b)(a-\sqrt{5}b) \\

    &64a^4+1 =(8a^2-4a+1)(8a^2+4a+1) \\

    &a^3+b^3+c^3-3abc = (a+b+c)(a^2+b^2+c^2-ab-bc-ca)\\

    \end{aligned}

    $$

    If you are wondering how such factorizations are found, do not worry. This article aims to guide you through methods and reasoning that will help you understand and perform these steps on your own.

    Fundamentals

    Before we moving on to the following parts, I think it’s necessary to introduce the basic concepts and the fundamentals of factorizations first…

    Consider this factorization for polynomial over the real numbers field:

    $$x^3+2x^2+3x+6$$

    Student A:

    $$

    \begin{aligned}

    &x^3+2x^2+3x+6 \\

    =\ & (x^3+3x)+ (2x^2+6) \\

    =\ & x(x^2+3)+ 2(x^2+3) \\

    =\ & (x+2)(x^2+3) \\

    \end{aligned}

    $$

    Student B:

    $$

    \begin{aligned}

    &x^3+2x^2+3x+6 \\

    =\ & (x^3+2x^2)+ (3x+6) \\

    =\ & x^2(x+2)+ 3(x+2) \\

    =\ & (x+2)(x^2+3) \\

    \end{aligned}

    $$

    We can see that student A and B both get the same result, though they are using different approaching methods to factorize.

    But here is the question, how can we be sure that even if we use different approaching methods to factorize, we are still going to get the same factorization result?

    In other words, is the factorization unique over the real numbers field?

    The answer is yes, the factorization over the real numbers field is unique.

    And here is a brief informal reasoning which we won’t discuss the details further, because these mathematical concepts are way more beyond the contents that we are focusing on currently:

    Based on the fundamental theorem of algebra and the complex conjugate root theorem, we are able to conclude that:

    (Assume $P(x)$ and $f(x)$ to be any polynomial of $1$ variable $x$ with real coefficients)

    1. $\forall \ P(x)$ can always be factorized to the product form of several $f(x)$ of 1st degree and 2nd degree.

    2. The factorization of $\forall \ P(x)$ over the real numbers field is unique.

    It is essential to understand the two fundamental properties of factorization as we will encounter various factorization problems. Thus, I would like to claim these two conclusions at this point. Please keep them in mind to aid your comprehension of factorization.

    Formulas

    $$

    \begin{aligned}

    & a^2-b^2=(a+b)(a-b) \\

    & a^3+b^3=(a+b)\left(a^2-a b+b^2\right) \\

    & a^3-b^3=(a-b)\left(a^2+a b+b^2\right) \\

    & a^2+2 a b+b^2=(a+b)^2 \\

    & a^2-2 a b+b^2=(a-b)^2 \\

    & a^3+3 a^2 b+3 a b^2+b^3=(a+b)^3 \\

    & a^3-3 a^2 b+3 a b^2-b^3=(a-b)^3 \\

    &a^2+b^2+c^2+2 ab+2 bc+2 ca =(a+b+c)^2\\

    &a^n-b^n=(a-b)\left(a^{n-1}+a^{n-2} b+a^{n-3} b^2+\cdots+a b^{n-2}+b^{n-1}\right), \quad n \in \mathbb{Z^+}\\

    &a^n+b^n=(a+b)\left(a^{n-1}-a^{n-2} b+a^{n-3} b^2-\cdots-a b^{n-2}+b^{n-1}\right), \quad n \in (2\mathbb{Z^+}-1)\\

    \end{aligned}

    $$

    The listed factorization formulas above are so important that you should master. And all these formulas are easy to prove except the last 2, which requires you to apply the polynomial remainder theorem (which we will discuss later).

    Strategies

    Note: In the following exposition, I will attempt to simulate the thought process of the problem setters, exploring how they might craft and refine problems to push contestants beyond standard solution templates and inspire deeper reasoning.

    Method of undetermined coefficients

    MUC is an approach that does the factorization reversely through assuming the factors expressions and then expand forwardly.

    Problem: Please factorize

    $$Ax^2+Bx+C, \quad A,B,C \in \mathbb{Q} $$

    over the integer numbers field.

    First, let’s be clear that when we are talking about the factorization of a polynomial, it means we are trying to find its polynomial factors. So a polynomial won’t have some factors like $(ax^{0.5}+b)$ or $(ax^{-1}+b)$ according to the definition of the polynomial.

    If $Ax^2+Bx+C$ can be factored over the integers, it must have 2 factors polynomial of 1st degree in the form of $ax+b$, since it is a 2nd degree polynomial. If it cannot be factored in this way, then it can only have factors of 2nd or higher degree, which would imply that the polynomial cannot be factored over the integer numbers field or even over the real numbers field.

    Now, assume $\exists \ a,b,c,d \in \mathbb{Q}, \quad c,d \ne 0$ such that:

    $$

    \begin{aligned}

    (ax+b)(cx+d)&= Ax^2+Bx+C \\

    acx^2+ (ad+bc)x+bd &= Ax^2+Bx+C \\

    \end{aligned}

    $$

    Then we have:

    $$

    \begin{cases}

    &ac &= A \\

    &ad+bc&=B \\

    &bd&=C \\

    \end{cases}

    \label{eq:function}

    \implies

    \begin{cases}

    &a &= \frac{A}{c} & (1)\\

    &ad+bc&=B & (2)\\

    &b&=\frac{C}{d} & (3)\\

    \end{cases}

    $$

    Substitute $(1), (3)$ into $(2)$ get:

    $$

    \begin{aligned}

    \frac{A}{c}d+\frac{C}{d}c&=B \\

    Ad^2-Bcd+Cc^2&=0 \\

    \end{aligned}

    $$

    Now the question has changed to factorize $Ad^2-Bcd+Cc^2$ over the integer numbers field, but it is even more complicated than the original problem $Ax^2+Bx+C$ …

    So that indicates, maybe we should change the way we think.

    Let’s solve the following problem first.

    Problem: Please factorize

    $$x^2+x-6$$

    over the integer numbers field.

    Assume $\exists \ a,b,c,d \in \mathbb{Q}$ such that:

    $$

    \begin{aligned}

    (ax+b)(cx+d)&= x^2+x-6 \\

    acx^2+ (ad+bc)x+bd &= x^2+x-6 \\

    \end{aligned}

    $$

    Then we have:

    $$

    \begin{cases}

    &ac &= 1 \\

    &ad+bc&=1 \\

    &bd&=-6 \\

    \end{cases}

    $$

    Since attempting to solve the entire system of equations would be difficult, it may be more effective to use a different approach. One possible method is to find integer solutions by substituting numbers into the equations system first… and we luckily got:

    $$

    \begin{cases}

    a &= 1 \\

    b&=3 \\

    c &= 1 \\

    d&=-2 \\

    \end{cases}

    $$

    Therefore $x^2+x-6=(ax+b)(cx+d)=(x+3)(x-2)$

    Now, let’s think about how to make this problem harder by doing some tiny modifications:

    $$x^2+x-6 \ \to\ \dfrac{x^2+x-6}{3} = \dfrac{x^2}{3}+\dfrac{x}{3}-2$$

    Here it is! Then let’s try to solve them.

    Problem: Please factorize

    $$\dfrac{x^2}{3}+\dfrac{x}{3}-2$$

    over the integer numbers field.

    Are you going to apply the previous solving method? Yes, you can, but this time, you’ll definitely need to deal with fractions (because integer $\times$ integer $\ne$ fraction… etc). Since the polynomial in the problem contains fractions, it may be more convenient to eliminate them at first. Therefore, transform:

    $$\dfrac{x^2}{3}+\dfrac{x}{3}-2 = \dfrac{1}{3}(x^2+x-6)$$

    Then we can focus on solving $x^2+x-6$ first, then times the result with $\dfrac{1}{3}$ . So $\dfrac{x^2}{3}+\dfrac{x}{3}-2=\dfrac{1}{3}(x+3)(x-2)$, accordingly the answer is $\dfrac{x^2}{3}+\dfrac{x}{3}-2$ cannot be factorized over the integer numbers field because its factors contain non-integer coefficients.

    Similarly…

    $$x^2+x-6 \ \to\ 7(x^2+x-6) = 7x^2+7x-42 $$

    Problem: Please factorize

    $$7x^2+7x-42$$

    over the integer numbers field.

    Using the same approach, we can get the answer: $7x^2+7x-42= 7(x+3)(x-2)$

    How about this…

    $$x^2+x-6= (x+3)(x-2) \ \to\ (x+3y)(x-2y)=x^2+xy-6y^2 $$

    Problem: Please factorize

    $$x^2+xy-6y^2$$

    over the integer numbers field.

    We can still apply the MUC for this problem, but please make sure that you set up $(ax+by)(cx+dy)$ instead of some others factors like $(ax+b)(cx+dy^2)$, because that product cannot produce the term of $xy$. Furthermore, it is important to note that any factors polynomials of a polynomial cannot have a degree higher than the degree of the polynomial itself (you can try to prove it using the MUC, it is quite easy).

    So the result is: $x^2+xy-6y^2= (x+3y)(x-2y)$

    Keep modifying the problem…

    $$x^2+x-6 = (x+3)(x-2) \ \to\ (x+2y+3)(x-5y-2) = x^2 -3xy -10y^2 + x -19y -6 $$

    Problem: Please factorize

    $$x^2 -3xy -10y^2 + x -19y -6$$

    over the integer numbers field.

    For this problem, maybe you will not know how to set up the factors with undetermined coefficients unless you saw the process how I derive it. Then what should you do to develop your “MUC” ability effectively? One word, practicing.

    For $x^2 -3xy -10y^2 + x -19y -6$, we can notice that the there are terms of 2nd , 1st and 0 degree, so we should set up the factors polynomials with the max degree of 1st in the form of $(ax+by+c)(dx+ey+f)$ , though you can also try to set up the factors polynomials in the form of $(ax+c)(by+d)$ , this would tell “no solution” instead, and it’s not because $x^2 -3xy -10y^2 + x -19y -6$ cannot be factorized over the integer numbers fields, it’s due to your wrong factors form setting at the beginning.

    Therefore, by processing the right factors form setting, we can get $x^2 -3xy -10y^2 + x -19y -6 = (x+2y+3)(x-5y-2)$ through testing the integers substitutions finitely.

    $$x^2+x-6 \ \to\ x^2+x-6-1 = x^2+x-7 $$

    Problem: Please factorize

    $$x^2+x-7$$

    over the integer numbers field.

    Similarly, we have:

    $$

    \begin{cases}

    &ac &= 1 \\

    &ad+bc&=1 \\

    &bd&=-7 \\

    \end{cases}

    $$

    However, through setting up the right form of factors and testing the integers substitutions finitely, we discovered that the problem can only have the answer: $x^2+x-7=x^2+x-7$, because the equations system fails to satisfy all the integer substitution, in other words, this equations system has no integer solutions. However, it can be factorized over the real numbers field:

    $$

    x^2+x-7=-\dfrac{1}{4}(-2 x+\sqrt{21}-1)(2 x+\sqrt{21}+1)

    $$

    Method of substitutions

    MS is a powerful technique for factorizing polynomials with high degrees. By using MS, we can simplify the original polynomial by reducing its degree or creating the symmetric situation. This approach can greatly simplify the process of factoring complicated polynomials.

    Now, let me set up a problem first.

    $$x^2+5x-6 \ \to\ (x^2)^2+5(x^2)-6 = x^4+5x^2-6$$

    Problem: Please factorize

    $$x^4+5x^2-6$$

    over the integer numbers field.

    Assume $y=x^2$, then

    $$x^4+5x^2-6=y^2+5y-6=(y+6)(y-1)=(x^2+6)(x^2-1)=(x^2+6)(x+1)(x-1)$$

    Similarly…

    $$x^2+5x-6 \ \to\ (x^2+5x-6)^2+5(x^2+5x-6)-6$$

    Problem: Please factorize

    $$(x^2+5x-6)^2+5(x^2+5x-6)-6$$

    over the integer numbers field.

    Assume $y=x^2+5x-6$, then

    \begin{align*}
    (x^2+5x-6)^2+5(x^2+5x-6)-6
    &=y^2+5y-6=(y+6)(y-1) \\
    &= (x^2+5x-6+6)(x^2+5x-6-1) s\\
    &= x(x+5)(x^2+5x-7)
    \end{align*}

    What if I expend the question:

    $$(x^2+5x-6)^2+5(x^2+5x-6)-6 = x^4+10 x^3+18 x^2-35 x$$

    Since in this form, the problem won’t provide you any hint to set up the substitution $y=x^2+5x-6$ directly, you need to discover that hidden property yourself instead, but it is very hard to notice that \((x^2+5x-6)^2+5(x^2+5x-6)-6 = x^4+10 x^3+18 x^2-35 x\) reversely… So, is there a better method except MS to solve this problem? Luckily, yes, and we will discuss later.

    How about this…

    $$x^2+5x-6 \ \to\ x^2+5x(x^2+5x-6)-6(x^2+5x-6)^2$$

    Problem: Please factorize

    $$x^2+5x(x^2+5x-6)-6(x^2+5x-6)^2$$

    over the integer numbers field.

    Assume $y=x^2+5x-6$, then

    $$x^2+5x(x^2+5x-6)-6(x^2+5x-6)^2=x^2+5xy-6y^2=(x+6y)(x-y)$$

    Problem: Please prove that the product of (any 4 consecutive positive integers) plus 1 can become a perfect square number.

    $\forall \ x \in \mathbb{Z^+}$, we have:

    $$x(x+1)(x+2)(x+3)+1=\Big( x(x+3) \Big)\Big( (x+1)(x+2) \Big) +1 =(x^2+3x)(x^2+3x+2) +1 $$

    Assume $y=x^2+3x+1$, then we derive the answer

    \begin{align*}
    (x^2+3x)(x^2+3x+2)+1
    &=(x^2+3x+1-1)(x^2+3x+1+1)+1\\
    &=(y-1)(y+1)+1\\
    &=y^2-1+1=y^2=(x^2+3x+1)^2
    \end{align*}

    It’s time to explain my motivation:

    Our primary goal is to factorize $x(x+1)(x+2)(x+3)+1$ and satisfy

    $$x(x+1)(x+2)(x+3)+1=(?)^2$$

    And according to the 2 fundamental properties of factorizations:

    1. $\forall \ P(x)$ can always be factorized to the product form of several $f(x)$ of 1st degree and with 2nd degree.

    2. The factorization of $\forall \ P(x)$ over the real numbers field is unique.

    We know that the polynomial $x(x+1)(x+2)(x+3)+1$ must be factorable over the integer field since this problem is solvable, and also using different approaches won’t affect the result of the factorization over the integer field of this polynomial.

    However, expending the polynomial directly may be not a good approach, unless you’ve discovered that there is no other way. So then I have:

    $$x(x+1)(x+2)(x+3)+1=\Big( x(x+3) \Big)\Big( (x+1)(x+2) \Big) +1 =(x^2+3x)(x^2+3x+2) +1$$

    But why didn’t I factorize $x(x+1)(x+2)(x+3)$ in this way:

    $$x(x+1)(x+2)(x+3)+1=\Big( x(x+1) \Big)\Big( (x+2)(x+3) \Big) +1 =(x^2+x)(x^2+5x+6) +1$$

    Because $(x^2+3x)(x^2+3x+2)+1$ indicates the hidden identity of $x^2+3x$, and then I could apply the substitution easily to replace $x^2+3x$, but for $(x^2+x)(x^2+5x+6) +1$, you cannot do so.

    Then why did I set up $y=x^2+3x+1$ instead of $y=x^2+3x$, though both of them contain $x^2+3x$ ? It is because the former could reveal the hidden symmetry property of $(x^2+3x)(x^2+3x+2)+1$ and then I can naturally apply the formula $(y-1)(y+1)=y^2-1$ and derive the perfect square after adding 1, but the latter cannot.

    Problem: Please factorize

    $$x^4+(x-8)^4$$

    over the integer numbers field.

    If you know the binomial theorem, you can expand the polynomial $x^4+(x-8)^4=2 x^4-32 x^3+384 x^2-2048 x+4096$ and then do the factorization. However, it is not recommended, want to know why? Here is the answer:

    Assume $y=(x-4)$ and $z=y^2$, then we rewrite the express as

    $$(y+4)^4+(y-4)^4=2y^4+192y^2+512=2(y^2)^2+192(y^2)+512=2z^2+192z+512$$

    When comparing $2z^2+192z+512$ and $2x^4-32x^3+384x^2-2048x+4096$, it is evident that factoring $2z^2+192z+512$ is a much simpler task than factoring the latter polynomial. The reason is because the substitution of $y=(x-4)$ what we were using could reveal the symmetry property of the polynomial and this property can provide a significant advantage in problem-solving, for this problem, it helped us eliminate the odd degree terms and accordingly decrease the complexity of the factorization.

    Now, how should we factorize $2z^2+192z+512$ ? Applying MUC? Yes, it is a valid approach, but not efficient enough for this case, we will discuss it later.

    Polynomial Remainder Theorem and Rational Root Theorem

    Assume $P(x)$ is a polynomial and $\forall \, r \in \mathbb{R}, \quad \exists! \, Q(x), R$ such that $P(x)=Q(x)(x-r)+R$, where $Q(x)$ is a polynomial and $R \in \mathbb{R}$, accordingly we have $P(r)=Q(r)\times 0+R=R$ . If $P(r)=0$, then $R=0$, which $P(x)=Q(x)(x-r)$ . In other words, if $P(r)=0$ , then $(x-r)$ must be one of its factors.

    Problem: Please factorize

    $$x^3-2x^2-5x+6$$

    over the integer numbers field.

    Through substituting some small integers, we found that $P(1)=0$ , therefore $(x-1)$ must be one of its factors. Then applying the polynomial division and MUC:

    $$x^3-2x^2-5x+6=(x-1)(x^2-x-6)=(x-1)(x-3)(x+2)$$

    Problem: Please factorize

    $$2z^2+192z+512$$

    over the real numbers field.

    $2z^2+192z+512=2(z^2+96z+256)$, for this problem, applying the MUC is definitely not a good idea since the coefficients are too large. Besides, substituting random real numbers to test is also not an efficient approach… Therefore, we can try to solve the equation $P(z)=z^2+96z+256=0$ directly to find the $r$ that let $P(r)=0$ through applying the quadratic formula $z=\dfrac{-b\pm \sqrt{b^2-4ac}}{2a}=-48\pm 32\sqrt{2}$ , so the solution is:

    $$2z^2+192z+512=2(x+48-32\sqrt{2})(x+48+32\sqrt{2})$$

    It’s time to introduce a corollary of PRT — RRT (Rational Root Theorem) (it is not hard to prove):

    For a polynomial equation $P(x)=\displaystyle \sum_{i=0}^{n}\left ( a_{i}x^{i}\right )=0$ with $a_{i}\in \mathbb{Z}$, $n\ge 0$ and $a_{n} \ne 0$ , then every rational solution $x=\dfrac{p}{q}$ which this equation satisfies: $p$ is the factor of $a_{0}$ and $q$ is the factor of $a_{n}$.

    So the steps to apply this corollary are:

    1. Write down all the factors of $a_{0}$ and $a_{n}$ respectively.
    2. Use these factors ($p \mid a_{0}$ and $q \mid a_{n}$) to form all the possible rationals $\left \{\dfrac{p}{q}\right \}$.
    3. Test these candidates by directly substituting them into the polynomial $P(x)$ to check if they satisfy $P(\dfrac{p}{q}) = 0$ with PRT.

    Problem: Please factorize

    $$x^4+10 x^3+18 x^2-35x$$

    over the integer numbers field.

    $x^4+10 x^3+18 x^2-35x = x(x^3+10 x^2+18 x-35)$, for $x^3+10 x^2+18 x-35$, as $a_{0}=-35$, $a_{3}=1$, then all the possible rationals are $\left \{ -35, -7, -5, -1, 1, 5, 7, 35 \right \}$. By applying MS, $x=-5$ is the only rational root for the polynomial equation $P(x)=0$, which proves that $x+5$ is the only rational factor of $x^3+10 x^2+18 x-35$ by PRT. Then by using polynomial division, $x^3+10 x^2+18 x-35 = (x+5)(x^2+5x-7)$, since $x+5$ is the only rational factor of it, therefore $x^2+5x-7$ is irreducible over the rational numbers field. So the factorization result is $x^4+10 x^3+18 x^2-35x = x(x+5)(x^2+5x-7)$.

    Clearly, RRT is a powerful tool for finding rational roots and factoring polynomials over the integers (or rationals). However, they do not help us factor polynomials that lack linear rational or integer factors, because no rational root doesn’t necessarily implies irreducibility.

    Recall that any polynomial $P(x)$ with real coefficients can be written (uniquely, up to constant factors) as a product of one or more 1st-degree or 2nd-degree polynomials.

    • So for polynomials of degree $2$ or $3$ with rational coefficients, if RRT finds no rational root, then the polynomial is irreducible over $\mathbb{Q}$. This is because any nontrivial factorization of a quadratic or cubic must include a linear factor $(x -r)$, which would imply the existence of a rational root $r$.
    • For polynomials of degree $4$ or higher, having no rational root does not guarantee irreducibility over $\mathbb{Q}$. A higher-degree polynomial may factor into two or more irreducible polynomials each of degree $\ge 2$. For instance, $ x^4 + 2x^2 + 1 = (x^2 + 1)^2 $ has no rational (or real) roots, yet it is clearly reducible over $\mathbb{Q}$.

    Cyclotomic Polynomials and Primitive Roots

    For the previous example, $x^4 + 2x^2 + 1 = (x^2 + 1)^2$ is indeed a valid factorization over $\mathbb{Z}$, yet RRT does not reveal any rational root. Thus, to handle more advanced factorizations, especially when a polynomial’s roots lie on the complex unit circle, we turn to cyclotomic polynomials and primitive roots. These concepts allow us to incorporate the PRT in an extended setting: instead of substituting a rational number to test if $(x -r)$ divides the polynomial, we substitute a complex number (a root of unity) to see if its minimal polynomial (a cyclotomic polynomial) divides the polynomial in question.

    A complex number \(\omega\) is called an \(n\)-th root of unity if

    $$
    \omega^n = 1
    $$

    They are precisely the solutions to the equation \(x^n -1 = 0\), and can be represented by

    $$
    \omega_k = e^{\tfrac{2\pi i k}{n}},
    \quad
    k = 0,1,\dots,n-1
    $$

    Geometrically, these \(n\)-th roots of unity lie on the unit circle at equal angular intervals of \(\dfrac{2\pi}{n}\).

    An \(n\)-th root of unity \(\omega\) is called primitive if \(\omega^n = 1\) and, for every divisor \(d < n\), \(\omega^d \neq 1\). Equivalently, the order of \(\omega\) is exactly \(n\).

    Now let us see how the PRT can still be used when the suspected root is complex. Suppose \(P(x)\in \mathbb{Z}[x]\) and we guess that a non-rational complex number \(\omega\) might be a root of $P$. By the PRT,

    $$
    P(\omega) = 0
    \implies
    (x -\omega) \mid P(x) \quad \text{in the relevant extension field}
    $$

    Even though \(\omega\) is not rational, we can substitute \(x=\omega\) into \(P(x)\). If \(P(\alpha)=0\), the polynomial \(P\) must have \(\omega\)’s minimal polynomial (over \(\mathbb{Q}\)) as a factor. When \(\omega\) is a primitive $n$-th root of unity, its minimal polynomial is precisely a \(n\)-th cyclotomic polynomial $\Phi_n(x)$. (Wait, what is a \(n\)-th cyclotomic polynomial and its proof? Don’t worry, I’ll show you later.) Hence, by substituting \(\omega\) into \(P(x)\), we effectively confirm that

    $$
    \Phi_n(x) \mid P(x)
    \quad
    \text{if \(\omega\) is a primitive \(n\)-th root of unity}
    $$

    And the reason is because if $\alpha$ is a primitive root and $(x-\omega) \mid P(x)$, then all unique primitive roots $\omega_1, \omega_2, \dots, \omega_{\varphi(n)}$ (you will know what is $\varphi(n)$ later) must have

    $$
    (x-\omega_1)(x-\omega_2)\cdots(x-\omega_{\varphi(n)}) \mid P(x)
    $$

    Thus, an interesting fact about cyclotomic polynomial just revealed,

    $$
    \Phi_n(x) = (x-\omega_1)(x-\omega_2)\cdots(x-\omega_{\varphi(n)})
    $$

    The \(n\)-th cyclotomic polynomial, denoted by \(\Phi_n(x)\), is defined as the unique monic polynomial in \(\mathbb{Z}[x]\) whose roots are exactly the primitive \(n\)-th roots of unity. Symbolically,

    $$
    \Phi_n(x)
    =
    \prod_{\substack{1 \le d \le n \\ \gcd(d,n)=1}}
    \Bigl(x -e^{\tfrac{2\pi i d}{n}}\Bigr)
    $$

    A very important fact is that each cyclotomic polynomial \(\Phi_n(x)\) is irreducible over \(\mathbb{Q}\), and that’s why it is precisely a minimal polynomial stated previously. A common way to prove irreducibility uses Gauss’s lemma, which we won’t discuss here. Moreover, a classical result in number theory shows that the total number of the unique primitive \(n\)-th roots of unity is \(\varphi(n)\), where \(\varphi\) denotes Euler’s totient function:

    $$
    \deg(\Phi_n) = \varphi(n)
    $$

    A key theorem called Cyclotomic Polynomial Factorization Theorem states that

    $$
    x^n -1 = \prod_{d \,\mid\, n} \Phi_d(x)
    $$

    where the product is over all positive divisors \(d\) of \(n\). Because each factor \(\Phi_d(x)\) is irreducible in \(\mathbb{Q}[x]\), this gives a complete factorization of \(x^n -1\) over the integers.

    Several small cyclotomic polynomials appear frequently in factorization problems:

    $$
    \Phi_1(x) = x -1,
    \quad
    \Phi_2(x) = x + 1,
    \quad
    \Phi_3(x) = x^2 + x + 1,
    \quad
    \Phi_4(x) = x^2 + 1,
    \quad
    \Phi_6(x) = x^2 -x + 1,
    \quad\dots
    $$

    Using these, one can obtain some factorizations like

    $$
    x^6 -1
    =
    \Phi_1(x)\,\Phi_2(x)\,\Phi_3(x)\,\Phi_6(x)
    =
    (x-1)(x+1)(x^2 + x + 1)(x^2 -x + 1)
    $$

    Problem: Please factorize

    $$
    P(x) = x^5 + x^4 + x^2 + x + 2
    $$

    By the RRT, no rational root emerges from checking divisors of the constant term. We next consider \(\omega\), a primitive cube root of unity satisfying \(\omega^3 = 1\) and \(\omega \neq 1\). By the definition of primitive root, \(\omega\) also satisfies \(\omega^2 + \omega + 1 = 0\). Using the PRT perspective in complex field, we substitute \(x = \omega\):

    $$
    \omega^5 + \omega^4 + \omega^2 + \omega + 2
    =
    \omega^2 + \omega + \omega^2 + \omega + 2
    =
    2(\omega^2 + \omega) + 2
    =
    2(\,\omega^2 + \omega + 1\,)
    =
    2 \cdot 0
    =
    0
    $$

    Hence, \(\omega\) is a root of \(P(x)\). By the properties of the primitive root \(\omega\), \(\Phi_3(x) = x^2 + x + 1\) (again, the minimal polynomial of \(\omega\) over \(\mathbb{Q}\)) must divide \(P(x)\). Indeed, a polynomial long division confirms:

    $$
    x^5 + x^4 + x^2 + x + 2
    =
    (x^2 + x + 1)\,(x^3 + x^2 + 1)
    $$

    and both factors are irreducible over \(\mathbb{Q}\) by RRT. Thus, we have obtained the complete factorization of \(P(x)\) in \(\mathbb{Z}[x]\).

    Cyclotomic polynomials and primitive \(n\)-th roots of unity form a cornerstone of advanced polynomial factorization. Although the RRT succeeds in uncovering rational linear factors, many polynomials require identifying complex roots of unity. The PRT, when interpreted in the relevant extension field, tells us that if \(\alpha\) is a root of a polynomial \(P\), then the minimal polynomial of \(\alpha\) divides \(P(x)\). For the roots of unity, this minimal polynomial is precisely a cyclotomic polynomial. Consequently,

    $$
    \Phi_n(x)
    \mid
    P(x)
    \quad
    \text{if \(P(\omega)=0\) for a primitive \(n\)-th root of unity \(\omega\)}
    $$

    In practice, testing certain cyclotomic substitutions and applying polynomial long division can yield nontrivial factorizations that remain inaccessible via rational-root checks alone. The fundamental identity

    $$
    x^n -1 = \prod_{d \,\mid\, n} \Phi_d(x)
    $$

    provides the prototype for such factorizations, and memorizing small \(\Phi_n(x)\) values is often a substantial aid in problem-solving contexts.

    Eisenstein’s Criterion and Modular Methods

    Having explored the RRT and cyclotomic polynomials, we now turn to another cornerstone of polynomial factorization techniques: Eisenstein’s criterion and modular arithmetic checks. These methods are especially helpful when rational or obvious cyclotomic factors fail to show up, yet we still seek to prove irreducibility or discover a hidden factorization.

    Eisenstein’s Criterion provides a powerful and quick way to prove a polynomial is irreducible over $\mathbb{Q}$, relying on prime divisibility patterns in the coefficients. More precisely, Eisenstein’s Criterion says:

    Let $P(x) = a_n x^n + a_{n-1} x^{n-1} + \dots + a_1 x + a_0 \in \mathbb{Z}[x]$. If there exists a prime $p$ such that:

    • $p \mid a_k$ for all $k<n$ ($p$ divides every coefficient except possibly the leading one)
    • $p \nmid a_n$ (the leading coefficient is not divisible by $p$)
    • $p^2 \nmid a_0$ (the constant term is not divisible by $p^2$)

    then $P(x)$ is irreducible over $\mathbb{Q}$.

    In plain language, this means if all coefficients but the leading one are multiples of some prime $p$, yet the constant term is “not too divisible” by $p$ (that is, only by one power of $p$ but not $p^2$), then $P(x)$ cannot be factored into polynomials of smaller degree with rational coefficients.

    But, failure to meet these conditions (for every prime) does not imply reducibility. Many irreducible polynomials do not satisfy Eisenstein’s divisibility conditions. Why? Because Eisenstein’s Criterion is a sufficient condition for irreducibility, not a necessary one. If a polynomial $P(x)$ meets Eisenstein’s divisibility pattern for some prime $p$, it is guaranteed irreducible over $\mathbb{Q}$. Hence, it is a one-way test: if it works, you get an instant proof of irreducibility; if not, it gives no conclusion.

    Here is a typical example:

    Problem: Please factorize

    $$
    P(x) = x^2 + 1
    $$

    over the rational numbers field.

    Obviously it is irreducible by using quadratic formula. Yet, there is no prime $p$ dividing $1$ and also meeting the “$p^2 \nmid 1$” pattern in the sense required by Eisenstein. No single $p$ divides all coefficients except the leading one, so Eisenstein’s Criterion gives no verdict. Still, $x^2+1$ is irreducible in $\mathbb{Q}[x]$.

    Sometimes no prime $p$ directly fits $P(x)$’s coefficients, however, the polynomial

    $$
    P(x + c)
    $$

    (for some small integer shift $c$) might meet Eisenstein’s conditions. This trick can salvage many cases where direct Eisenstein fails. An example is, again:

    Problem: Please factorize

    $$
    P(x) = x^2 + 1
    $$

    over the rational numbers field.

    Set $x = y + 1$. Then $x^2 + 1 = (y+1)^2 + 1 = y^2 + 2y + 2$, hence, $p=2$ satisfies all the Eisenstein conditions for $P(y)$, so it is irreducible over $\mathbb{Q}$.

    Problem: Please factorize

    $$
    x^5 + 5x^3 + 10
    $$

    over the rational numbers field.

    As $n=5$ and pick $p=5$, then we have $p \mid a_{k}$ for any $k<n$, and $p \nmid n$, with $p \nmid a^2_{0}$, which satisfies the Eisenstein’s Criterion, so this polynomial is irreducible over $\mathbb{Q}$.

    When Eisenstein’s Criterion does not apply, one can still appeal to modular techniques (often reducing coefficients modulo a small prime $p$) to gather hints about whether a polynomial

    $$
    P(x) = a_n x^n + \cdots + a_0 \quad \in \quad \mathbb{Z}[x]
    $$

    is irreducible or not. The strategy is to reduce its coefficients modulo a prime $p$. We get $$ \overline{P}(x) = (a_n \bmod p)\,x^n + \dots +(a_0 \bmod p) \quad \in \quad \mathbb{F}_p[x] $$

    The overall idea is:

    • Pick a small prime $p$ (often $2,3,5,\dots$)
    • Reduce the coefficients of $P(x)$ modulo $p$, obtaining $\overline{P}(x) \in (\mathbb{Z}/p\mathbb{Z})[x]$
    • Check if $\overline{P}(x)$ factors in $\mathbb{F}_p[x]$
    • If $\overline{P}(x)$ does factor nontrivially over $\mathbb{F}_p$, that suggests (not guarantee) $P(x)$ might also factor over $\mathbb{Q}$. You can try lifting (via Hensel’s lemma or systematic guessing) to recover the factorization over $\mathbb{Z}$.
    • If $\overline{P}(x)$ remains irreducible modulo $p$ for several distinct primes $p$, you start suspecting $P(x)$ is irreducible over $\mathbb{Q}$. (Though keep in mind: a single prime $p$ giving irreducibility does not absolutely prove $P(x)$ irreducible in $\mathbb{Q}[x]$, but multiple prime checks strongly reinforce it.)

    But the question is, why does this help?

    If $P(x)$ factors over $\mathbb{Q}$, say

    $$
    P(x) = f(x)\,g(x),
    \quad
    f(x),\,g(x) \in \mathbb{Q}[x]
    $$

    then by multiplying through by a suitable integer to clear denominators, we get a factorization in $\mathbb{Z}[x]$. Reducing that factorization modulo $p$,

    $$
    P(x)\bmod p = \bigl(f(x)\bmod p\bigr)\,\bigl(g(x)\bmod p\bigr)
    \quad \text{in } \mathbb{F}_p[x].
    $$

    Hence, if $P(x)$ is reducible in $\mathbb{Q}[x]$, it will usually (not guarantee) appear reducible mod $p$ as well.

    So when doing such reduction, the factorization “transfers” (reduces) to a factorization in $\mathbb{F}_p[x]$ except in rare cases of so-called accidental factorization or accidental irreducibility. Checking multiple primes reduces the chance of such accidents.

    From my perspective, these modular checks are less straightforward or less commonly the “go-to” technique than methods which were already discussed in previous chapters. Therefore, we will not delve into the details of how a factorization found in $\mathbb{F}_p[x]$ can be systematically “lifted” to $\mathbb{Z}[x]$. It suffices to note that if such a modular factorization exists (and meets certain technical conditions), then in principle one can recover a genuine integer-coefficient factorization for $P(x)$ (due to Hensel’s Lemma).

    Thus, while modular methods can indeed be powerful (especially in computational settings or more advanced number theory), they are, in practice, not always the most efficient or elementary path to factorization in a contest or instructional context, particularly when simpler tools are already available…

    Symmetric Polynomials

    When dealing with factorization problems in multiple variables, one special class of polynomials stands out: symmetric polynomials. A polynomial $f(x_1, x_2, \dots, x_n)$ of $n$ variables is said to be symmetric if, for every permutation $\sigma$ of the set $\{1, 2, \dots, n\}$, we have

    $$
    P \left (x_{\sigma(1)}, x_{\sigma(2)}, \dots, x_{\sigma(n)} \right ) = P(x_1, x_2, \dots, x_n)
    $$

    In other words, swapping any two variables does not change the value of a symmetric polynomial. For example, $x^3+y^3$, $x^2+y^2+z^2-5xyz$, and $x^2y^2-x-y$ are symmetric polynomials, but $x^2+y^3$ is not one of them, because after swapping $x$ and $y$, the polynomial becomes $y^2+x^3 \ne x^2+y^3$.

    A central result in the theory of symmetric polynomials is the Fundamental Theorem of Symmetric Polynomials, it states that every symmetric polynomial can be expressed in terms of the elementary symmetric polynomials. The elementary symmetric polynomials are defined as follows:

    \begin{align*}
    e_1(x_1, x_2, \dots, x_n) &= x_1 + x_2 + \cdots + x_n \\[6pt]
    e_2(x_1, x_2, \dots, x_n) &= \sum_{1 \leq i < j \leq n} x_i x_j \\[6pt]
    e_3(x_1, x_2, \dots, x_n) &= \sum_{1 \leq i < j < k \leq n} x_i x_j x_k \\[6pt]
    &\vdots \\[6pt]
    e_n(x_1, x_2, \dots, x_n) &= x_1 x_2 \cdots x_n
    \end{align*}

    In general, for $1 \leq k \leq n$,

    $$
    e_k(x_1, x_2, \dots, x_n) = \sum_{1 \leq i_1 < i_2 < \cdots < i_k \leq n} x_{i_1} x_{i_2} \cdots x_{i_k}
    $$

    These elementary symmetric polynomials form a natural set of “building blocks” for any symmetric polynomial. Moreover, each $e_k$ is homogeneous of degree $k$, since every term in $e_k$ is a product of degree $k$. This homogeneity and the fundamental theorem of symmetric polynomials together imply that if you aim to factor a symmetric polynomial, it is often advantageous to consider factorization patterns that involve these elementary symmetric polynomials. In many problems, this approach simplifies the process dramatically.

    When factorizing symmetric polynomials, a natural strategy is to first identify factors using a substitution-based reasoning similar to the PRT, and then leverage the fundamental structure provided by the elementary symmetric polynomials to complete the factorization with MUC.

    Let $ P(x_1,x_2,\dots,x_n) $ be a symmetric polynomial in $ n $ variables over a field $\mathbb{K}$. Suppose there exists a polynomial function $ f:\mathbb{K}^n \to \mathbb{K} $ such that

    $$
    P\bigl(f(x_1,x_2,\dots,x_n),\,x_2,\dots,x_n\bigr) = 0
    $$

    By the symmetry of $ P $ and the bound variable renaming (formally known as $\alpha$-conversion), it follows that, for each $ i \in \{1,2,\dots,n\} $,

    $$
    P\bigl(x_i, x_2,\dots,x_{i-1},f(x_i,x_2,\dots,x_{i-1}, x_{1}, x_{i+1},\dots,x_n),x_{i+1},\dots,x_n\bigr) = 0
    $$

    By PRT, for every variable we have

    $$
    (x_i -f(x_i,x_1,\dots,x_{i-1},x_{i+1},\dots,x_n)) \mid P(x_1,x_2,\dots,x_n)
    $$

    Thus we can conclude

    $$
    (x_1 -f(x_1,x_2,\dots,x_n)) (x_2 -f(x_2,x_1,\dots,x_n)) \cdots (x_n -f(x_n,x_1,\dots,x_{n-1})) \mid P(x_1,x_2,\dots,x_n)
    $$

    Problem: Please factorize

    $$
    P(a,b,c) = a^3(b-c) + b^3(c-a) + c^3(a-b)
    $$

    First, we check what happens if we set $a=b$. Substitute $a=b$:

    $$
    P(b,b,c) = b^3(b-c) + b^3(c-b) + c^3(b-b) = b^4 -b^4 + c^3(0) = 0
    $$

    Since $P(b,b,c)=0$, so, again, by following the property of symmetric polynomials and bound variable renaming (formally known as $\alpha$-conversion), we know that $P(b,b,c)=P(a,c,c)=P(a,b,a)=0$, which indicates $(a-b)$, $(b-c)$, $(c-a)$ are also factors of $P$ by using PRT. Therefore, we have:

    $$
    (a-b) \mid P(a,b,c) \implies (a-b)(b-c)(c-a) \mid P(a,b,c)
    $$

    So we’ve identified a cubic factor $(a-b)(b-c)(c-a)$ in our homogeneous polynomial $P(a,b,c)$ of degree $4$. This leaves us needing one more factor of degree $1$ to match the total degree of $P(a,b,c)$. Since $P$ is symmetric and homogeneous, the missing factor must itself be a symmetric, homogeneous polynomial of degree $1$.

    Returning to our specific polynomial $P(a,b,c)$ in three variables, we need a symmetric, homogeneous polynomial of degree $1$. In three variables, the only such elementary symmetric polynomial of degree $1$ is $e_1(a,b,c) = a + b + c$.

    Thus, we propose that the missing factor is $e_1(a,b,c)$ and apply MUC, then we can assume:

    $$
    P(a,b,c) = k (a-b)(b-c)(c-a)\,e_1(a,b,c)
    $$

    for some constant $k \in \mathbb{R}$ that we must determine.

    To find the constant multiplier $k$, we can substitute convenient numeric values into $P(a,b,c)$ and into our proposed factorization. A convenient choice is to pick some values for $a,b,c$ that simplify computation. Note: These numeric values must satisfy $ a \ne b \wedge b \ne c \wedge c\ne a $ in this case, or that would trigger the PRT and the substitution would be meaningless. So, let us set $(a,b,c)=(0,1,2)$ for simplicity:

    \begin{align*}
    LHS &= P(0,1,2) = 0^3(1-2) + 1^3(2-0) + 2^3(0-1) = (0)(-1) + (1)(2) + (8)(-1) = 2 -8 = -6 \\
    RHS &= k (a-b)(b-c)(c-a)\,e_1(a,b,c) = k (0-1)(1-2)(2-0) (0+1+2) = 6k
    \end{align*}

    As $LHS = RHS$, so we must have $6k=-6$, giving $k=-1$. Thus:

    $$
    P(a,b,c) = -(a-b)(b-c)(c-a)(a+b+c)
    $$

    Problem: Please factorize

    $$
    P(a,b,c) = a^2(a-b-c)+b^2(b-a-c)+c^2(c-a-b)+2abc
    $$

    Similarly, let $a=b+c$, then $P(b+c,b,c) = 0$, which implies

    $$
    (a-(b+c)) \mid P(a,b,c) \implies (a-(b+c))(b-(a+c))(c-(a+b)) \mid P(a,b,c)
    $$

    By MUC, assume $P(a,b,c) = k(a-(b+c))(b-(a+c))(c-(a+b))$, then we do numeric values substitution to confirm the value of $k$, for simplicity, let $(a,b,c) = (1,0,0)$, then

    \begin{align*}
    LHS &= 1^2(1-0-0)+0+0+0 = 1 \\
    RHS &= k(1-(0+0))(0-(1+0))(0-(1+0)) = k(1)(-1)(-1)=k
    \end{align*}

    Therefore $LHS = RHS \implies k=1$, which implies

    $$
    P(a,b,c) = (a-(b+c))(b-(a+c))(c-(a+b))
    $$

    Problem: Please factorize

    $$
    P(a,b,c) = (x+y+z)^4-(x^2+y^2+z^2)^2-2(xy+yz+xz)((x+y+z)^2+(x^2+y^2+z^2))
    $$

    let $a=b$, then $P(b,b,c) = 0$, which implies

    $$
    (a-b) \mid P(a,b,c) \implies (a-b)(b-c)(c-a) \mid P(a,b,c)
    $$

    let $a=0$, then $P(0,b,c) = 0$, which implies

    $$
    (a-0) \mid P(a,b,c) \implies abc \mid P(a,b,c)
    $$

    So together, we have

    $$
    abc(a-b)(b-c)(c-a) \mid P(a,b,c)
    $$

    But $P(a,b,c)$ is a homogeneous symmetric polynomial of degree $4$, since it is divisible by a homogeneous symmetric polynomial of degree $6$, then $P(a,b,c)=0$.

    Problem: Please factorize

    $$
    P(a,b,c) = a^3+b^3+c^3-3abc
    $$

    let $a=-(b+c)$, then $P(-(b+c),b,c) = 0$, which implies

    $$
    (a+b+c) \mid P(a,b,c)
    $$

    Since $P(a,b,c)$ and $(a+b+c)$ are homogeneous, so $\dfrac{P(a,b,c)}{(a+b+c)}$ is homogeneous of degree $2$. By the fundamental theorem of symmetric polynomials and MUC, we can assume

    $$
    P(a,b,c) = (a+b+c)\left(k_1e_1^2(a,b,c)+k_2e_2(a,b,c)\right)
    $$

    By doing 2 sets of convenient numeric substitutions, we get

    $$
    P(a,b,c) = (a+b+c)\left(e_1^2(a,b,c)-3e_2(a,b,c)\right)
    $$

    In fact, $(e_1^2(a,b,c)-3e_2(a,b,c))$ is irreducible, this can be proven by using MUC with assuming $(e_1^2(a,b,c)-3e_2(a,b,c)) = (\alpha_1 a + \beta_1 b + \gamma_1 c)(\alpha_2 a + \beta_2 b + \gamma_2 c)$ and finding out that no solution exists.

    Problem: Please factorize

    $$
    P(a,b,c) = \left(y^2-z^2\right)(1+x y)(1+x z)+\left(z^2-x^2\right)(1+y z)(1+y x)+\left(x^2-y^2\right)(1+z x)(1+z y)
    $$

    This problem is a little bit tricky, since it is not homogeneous, so a natural approach is to rewrite it into the sum of several homogeneous polynomials:

    \begin{align*}
    P(a,b,c) = & \, \left(y^2-z^2\right)(1+x y)(1+x z)+\left(z^2-x^2\right)(1+y z)(1+y x)+\left(x^2-y^2\right)(1+z x)(1+z y) \\
    = & \, x y z\left ( x\left(y^2-z^2\right)+y\left(z^2-x^2\right)+z\left(x^2-y^2\right)\right) +\left ( \left(y^2-z^2\right)+\left(z^2-x^2\right)+\left(x^2-y^2\right)\right) \\
    & +\left(x(y+z)\left(y^2-z^2\right)+y(z+x)\left(z^2-x^2\right)+z(x+y)\left(x^2-y^2\right)\right) \\
    = & \, x y z\left(x\left(y^2-z^2\right)+y\left(z^2-x^2\right)+z\left(x^2-y^2\right)\right) \\
    & +\left(x(y+z)\left(y^2-z^2\right)+y(z+x)\left(z^2-x^2\right)+z(x+y)\left(x^2-y^2\right)\right)
    \end{align*}

    Then we can follow our common strategy to conquer these $2$ homogeneous polynomials respectively to finish factorizing the main goal $P(a,b,c)$:

    \begin{align*}
    P(a,b,c) = & \, x y z\left(x\left(y^2-z^2\right)+y\left(z^2-x^2\right)+z\left(x^2-y^2\right)\right) \\
    & +\left(x(y+z)\left(y^2-z^2\right)+y(z+x)\left(z^2-x^2\right)+z(x+y)\left(x^2-y^2\right)\right) \\
    = & \, xyz(x-y)(y-z)(z-x) + (x-y)(y-z)(z-x)(x+y+z) \\
    = & \, (xyz+x+y+z)(x-y)(y-z)(z-x)
    \end{align*}

    Some tips

    It is generally recommended to avoid immediately applying formulaic solutions without even thinking when encountering a problem, as taking some time to conduct initial observations can often lead to more effective problem-solving outcomes.

    If I have a question like factorize $x^2+x-6$ over the integer numbers field, will you consider applying the quadric formula $x=\dfrac{-b \pm \sqrt{b^2-4 a c}}{2 a}$ first?

    No (I mean, you can, but, it’s strongly not recommended to do that). Instead, we can do some simple transformations to generate the result easily:

    $$

    x^2+x-6=x^2+3x-2x-6=x(x+3)-2(x+3)=(x+3)(x-2)

    $$

    Or for this problem: Factorize $x^2-28x+195$ over the integer numbers field.

    Probably this one is not as simple as the previous one, because it contains larger numbers and is not obvious to observe anything… But, really?

    As long as you noticed $195=196-1$ and you are familiar with $196=14^2$, then you are able to solve this problem within 10 seconds, look:

    \begin{align*} x^2-28x+195&=x^2-28x+196-1\\&=(x^2-2\times 14x+14^2)-1^2\\&=(x-14)^2-1^2\\&=(x-14-1)(x-14+1)\\&=(x-15)(x-13)\end{align*}

    Factorize $x^2-28x+195$ over the integer numbers field.

    We can also apply the similar method: $0=8\times2a^2-8\times2a^2$

    $$ 64a^4+1 =(8^2a^4 + 8\times2a^2 +1) – 8\times2a^2 = (8a^2+1)^2 – (4a)^2=(8a^2-4a+1)(8a^2+4a+1) $$

    Upon reflection, you may be curious about how I was able to recognize the approach needed to solve these problems. The truth is, I wasn’t born with the knowledge. Rather, I have spent countless hours practicing and mastering various problem-solving techniques, which has allowed me to develop my mathematical intuition. What I want to emphasize is that humans have the ability to cultivate and refine their mathematical intuition (expanding your Maths database) through sufficient training and exposure, because this skill is about memorization and recognition (automatically retrieving or invoking a corresponding frame to solve the problem), etc… Just like developing a specific skill of a neural network through billions of training data… But for humans, the mechanized training process is a tedious and non-efficient process comparatively, since we are not as powerful as computers… However, we still need to practice as long as we aspire to participate in the Mathematical Olympiad or Putnam Maths Competition, these designed competitive mathematics for humans…

    Have you ever encountered a math problem that left you stumped, unable to even begin solving it? Chances are, you will at some point. But why does this happen?

    In competitive mathematics contests, problem setters strive to challenge well-prepared participants who have practiced typical problems extensively. To accomplish this, they must devise “good problems” that are difficult enough to separate the exceptional from the merely competent. These problems often require discovering a clever trick that is not immediately apparent.

    For instance, a problem like $64a^4+1=(64a^4 + 16a^2 +1) -16a^2$ may have been considered challenging in the past, but it has become too familiar to many participants. Therefore, problem setters must continue to raise the bar by increasing the difficulty of their problems.

    However, it’s important to remember that even the most challenging problems in a Mathematics contest are designed to be solved by humans within a limited time frame, so there’s no need to panic. Rest assured, you won’t encounter a problem as difficult as Goldbach’s conjecture, which is a extremely hard question that is yet to be proven, during the contest.

    Now, let’s delve into the Method of Trials and Errors (MTE):

    This approach is useful when your maths knowledge database is not sufficient to cover the problem directly, and you cannot call any existing methods from your database to solve the problem effectively. In such cases, try MTE. As we’ve mentioned earlier, even the most challenging problems in a Mathematics contest are designed to be solved by humans within a limited time frame. The difficulty of a problem may stem from the fact that you haven’t discovered the clever trick or technique that could solve it easily. It’s possible that a simple transformation to your approach could lead to a sudden insight or revelation from your observations that makes the solution obvious.

    For example, here is a very challenging one for you to solve:

    Problem: Please factorize

    $$
    x^8+x^4+1
    $$

    over the integer numbers field.

    At first sight, you may think applying MS is a good approach by letting $y=x^4$ since the relation of $(x^4)^2 = x^8$ is obvious, but after doing that, you would notice $y^2+y+1$ is not factorizable over the real number field as the discriminant is less than zero ($\Delta = 1-4 = -3 < 0$). Then you would apply RRT, and notice this polynomial doesn’t have any linear rational factor, as its degree is $\ge 4$. You may even start checking whether this polynomial is cyclotomic… But through some simple transformations, intuitively, we can do

    \begin{align*}x^8+x^4+1 &= x^8+2x^4+1-x^4 \\&= (x^4+1)^2-(x^2)^2 \\&= (x^4+x^2+1)(x^4-x^2+1) \\&= (x^4+2x^2+1-x^2)(x^4-x^2+1) \\&= \left ((x^2+1)^2-x^2) \right )(x^4-x^2+1)\\&=(x^2-x+1)(x^2+x+1)(x^4-x^2+1)\end{align*}


  • Why I Don’t Use Chinese Social Media Anymore…

    Why I Don’t Use Chinese Social Media Anymore…

    Note: This post is an English adaptation of my original Chinese article. Some parts have been modified for clarity, cultural relevance, or to better fit the English-speaking audience. The original Chinese text is provided on the next page (2nd page) of this post for reference and comparison.

    Preface: Due to identity-related reasons, I will not discuss details related to politically sensitive topics extensively.

    First off, I want to say that I love China and the culture and people there, as it is where I grew up. However, I am not particularly fond of China’s political environment in certain aspects, especially the excessive control over the internet.

    I remember during my junior high school years (around the second or third year (grade 7 or 8), which would be 2017 or 2018), in our ideology and morality class, our textbook (Shanghai Education Edition) mentioned that China is a democratic country and that the Chinese people have the human right to freedom of speech. But we know that’s not entirely the case.

    Suppose you express some sensitive truths about China online or present views that diverge from the official Chinese narrative. In that case, if your comments do not receive much dissemination, the online punishments you might face, ordered from least to most severe, include:

    • Your comments being systematically deleted, or your comments being “swallowed” (meaning it looks like your comments were posted, but in reality, only you can see them, indicating that your comments have been secretly hidden by the system).
    • Apart from comments being deleted or hidden, your account may also be temporarily muted by the system. If the comments you post are more direct or radical, your account might even be permanently banned. Also, since China enforces a real-name system on the internet, once you’re punished online for such sensitive comments, your name will be marked on a system list. This will lead to your account being “specially monitored” on all other Chinese platforms in the future.

    However, once the comments you post online gain a certain level of dissemination (whether intentionally or not), there’s a high probability that you will be summoned to the police station or the public security bureau for questioning (commonly referred to as “being invited for tea,” and this invitation is compulsory). Additionally, the charges against you could be baseless, such as “picking quarrels and provoking trouble” (since this charge is vaguely defined, it’s also known as the “universal charge” or “pocket crime”) or “defamation” (even though you were just stating objective facts), and so on.

    Nevertheless, the Chinese government cannot regulate the internet beyond China’s borders. Therefore, they have launched two types of countermeasures:

    • Full control over the internet information accessible by Chinese citizens within the country includes:
      • Setting up the “Great Firewall” (officially called the “Golden Shield Project“), which aims to thoroughly filter out information considered sensitive by the Chinese authorities from the domestic internet, thereby controlling all online content visible to Chinese netizens (I guess the “wall” uses a blacklist mechanism because when I first purchased my website domain, I had friends in China test it, and they could access it directly from within the country). This leads to a significant portion of Chinese netizens being isolated from the outside internet world, potentially causing some level of cognitive bias. What concerns me most is that due to the existence of the “Great Firewall,” we are unable to efficiently learn or keep up with the technological era, such as Chinese scholars being unable to access foreign forums or academic documents normally (there was a funny official mishap recently, haha, click here), and the recent ChatGPT cannot be used in China at all, etc. (March 10, 2024: Update, a while ago I even set up a VPN with a Raspberry Pi for my family back in China so they could use ChatGPT normally, since around December 2023, all ChatGPT access node IPs used by our ClashX VPN were blocked by OpenAI. Click here to check).

    • Forcefully preventing the publication of information sensitive to the Chinese authorities on the internet outside China includes:
      • In 2015, Chinese authorities employed DDoS attacks (which were not traditional DDoS attacks but utilized Man-on-the-Side Attacks, different from MITM Attacks). In simple terms, Baidu, the largest search engine in China at the time, was injected with malicious JS code, turning all normal internet requests sent by Chinese netizens at that time into targeted malicious traffic access, unwittingly turning them into temporary “puppet machines” for the Chinese side. Some technical details can be viewed here. This was aimed at overseas websites containing sensitive information about China, such as Github (the non-traditional DDoS attack caused the Github website to be paralyzed temporarily) because it hosted repositories containing sensitive information regarding China. Although this attack was not officially acknowledged by the Chinese authorities, the analysis and the bulk of the technical evidence suggest Chinese official involvement. The intent of this attack by Chinese authorities was to deter such websites and consequently force them to remove content sensitive to China.
      • Using human flesh search to locate the individual origin of the information and coercing them to stop the spread through various means of force.

    Now let’s return to the main topic: Why I no longer use Chinese social media?

    After experiencing the following incident, I realized how important the basic human right to freedom of speech is.

    Starting from March 2022, due to the lockdown in Shanghai caused by the pandemic, residents were required to quarantine at home. Actually, for me, a typical homebody, this didn’t seem to have much impact…since I generally don’t like going out unless necessary, such as only going out for school or family dinners, so usually, the virtual world created by electronic devices (phones, computers, game consoles, etc.) is my main activity area.

    In fact, at the beginning of the home quarantine policy, I even felt quite happy because, firstly, all schools in Shanghai (including my high school) shifted from offline to online education, so I didn’t need to go to school, haha. At the same time, I could spend all day in front of my computer at home, with my family around, without worrying about food and drink, which felt really great!

    However, the drawbacks of this policy gradually became apparent.

    (March 10, 2024: Update, actually, I originally wrote a lot about this, but considering my identity-related reasons, I decided to delete them. If you’re curious, you can search online with the keyword: Shanghai quarantine)

    Therefore, in the early morning of May 1, 2022, I posted a singing video in my WeChat Moments (below). I didn’t make it very clear but subtly expressed my complaints through singing. However, not long after, I learned that a few of my WeChat friends had been permanently banned, seemingly for political reasons. At the same time, friends advised me that posting such Moments could be risky and suggested I delete them. Then, about 6 hours after posting, I deleted the video from my Moments.

    (March 10, 2024: Update, I just re-uploaded the video on YouTube because I realized that the Bilibili video I initially embedded here was forcibly taken down on Bilibili…)

    After that, I no longer wanted to use any Chinese social media, such as WeChat, Zhihu, Bilibili, etc.

    However, since my family and friends, for various reasons, cannot completely detach themselves from these Chinese social media platforms, I also cannot fully separate myself from these Chinese apps.

    But my main battlefield has completely shifted.

    Well, that’s it.

    Pages: 1 2